#!/usr/bin/env ruby
# encoding: UTF-8
# coding: UTF-8

require 'fileutils'
require 'time'
require 'json'

#=> Also requires Inkscape and Pecas

Encoding.default_internal = Encoding::UTF_8
Dir.chdir(File.dirname(__FILE__))

#=> Variables
$language = 'en-US'
$mariana = 'Mariana Eguaras\' blog'
$author_name = 'Nika Zhenya'
$author_email = 'nika.zhenya@cliteratu.re'
$site_name = 'Publishing is Coding: Change My Mind'
$site_description = $author_name + '\'s entries from ' + $mariana + ' in broken english.'
$site_keywords = 'publishing, blog, book, ebook, methodology, foss, libre-software, format, markdown, html, epub, pdf, mobi, latex, tex'
$site_link = 'https://blog.cliteratu.re'
$site_img = 'icon.png'
$date = Time.now.to_s.split(' ')[0]
$head = File.read('template/site/head.html')
$header = File.read('template/site/header.html')
$footer = File.read('template/site/footer.html')
$rss = {
  :channel => {
    :title => $site_name,
    :link => $site_link,
    :description => $site_description,
    :language => $language,
    :managingEditor => $author_email + ' (' + $author_name + ')',
    :lastBuildDate => '',
    :image => {
      :title => $site_name,
      :url => $site_link + '/' + $site_img,
      :link => $site_link
    },
    :items => []
  }
}
$xml = []

#=> Definitions

# Gets date in proper format
def get_date d, rfc = false
  d = d.split('-')

  def month m
    months = [
      'January', 'February', 'March', 'April',
      'May', 'June', 'July', 'August',
      'September', 'October', 'November', 'December'
    ]

    return months[m.to_i - 1]
  end

  if rfc
    return Time.new(d[0], d[1], d[2]).rfc2822
  else
    return month(d[1]) + ' ' + 
           d[2].to_i.to_s + ', ' + 
           d[0]
  end
end

# Replaces strings
def replace_content content, title = 'Main'
  elements = [
    ['language', $language],
    ['site_name', $site_name],
    ['site_description', $site_description],
    ['site_keywords', $site_keywords],
    ['site_link', $site_link],
    ['site_img', $site_img],
    ['author_name', $author_name],
    ['author_email', $author_email],
    ['date', get_date($date)],
    ['title', title]
  ]

  elements.each do |e|
    content.gsub!("$#{e[0]}$", e[1])
  end

  if content.split("\n")[0] == '<header>'
    content.gsub!($mariana, "<a target=\"_blank\" href=\"https://marianaeguaras.com/blog/\">#{$mariana}</a>")
  end

  if title == 'Main' 
    content.gsub!('href="../', 'href="')
    content.gsub!('src="../', 'src="') 
  end

  return content
end

# Changes file content
def change_file url, content
  file = File.new(url, 'w:UTF-8')
  file.puts content
  file.close
end

# Converts MD in other formats
def convert_md md
  md_content = []
  item = {
    :guid => $site_link + '/html/' + File.basename(md, '.*'),
    :title => '', 
    :link => $site_link + '/html/' + File.basename(md, '.*') + '.html',
    :description => '',
    :author => $author_email + ' (' + $author_name + ')',
    :category => '',
    :pubDate => ''
  }

  # Gets properties from MD
  def item_split s
    return s.gsub(/@\S+\['(.*?)'\]/, '\1').strip.split('\',\'')
  end

  puts "Building '" + File.basename(md) + "'…"

  # Analizes MD
  file = File.open(md, 'r:UTF-8')
  file.each_with_index do |l, i|
    if i == 0
      item[:title] = l.gsub(/^#/, '').strip
    end

    if l =~ /^@meta\[.*?\]\s*?$/
      data = item_split(l)
      item[:pubDate] = get_date(data[0], true)
      item[:category] = data[1]
      item[:description] = data[2]
      md_content.push(
        '<p class="meta">' +
        get_date(data[0]) + ' | ' +
        data[1] + ' | ' +
        '<span class="smallcap"><a target="_blank" href="' + $site_link + '/md/' + File.basename(md) + '">MD</a></span> / ' +
        '<span class="smallcap"><a target="_blank" href="' + $site_link + '/ebooks/' + File.basename(md, ".*") + '.epub">EPUB</a></span> / ' +
        '<span class="smallcap"><a target="_blank" href="' + $site_link + '/ebooks/' + File.basename(md, ".*") + '.mobi">MOBI</a></span> / ' +
        '<a target="_blank" href="' + data[3] + '">spanish version</a>' +
        '</p>'
      )
    else
      md_content.push(l)
    end
  end

  # Everything is gonna be created in a temporary directory
  Dir.mkdir('tmp')
  Dir.chdir('tmp')

  # Some variables that are going to be used
  html_name = '../html/' + File.basename(md, '.*') + '.html'
  new_md_name = File.basename(md)
  cover_url = '../../template/ebooks/'

  # Creates an MD with some changes so it can be converted to HTML
  change_file(new_md_name, md_content)
  system("pc-pandog -i #{new_md_name} -o #{html_name}")

  # Will convert HTML to EPUB and MOBI
  system("pc-automata --init")
  Dir.chdir('epub-automata')

  # Modifies the metadata
  yaml_content = File.read('meta-data.yaml')
  yaml_content.gsub!('title: Sin título', 'title: "' + item[:title] + '"')
              .gsub!('Apellido, Nombre', $author_name)
              .gsub!('publisher:', "publisher:\n  - Perro Tuerto")
              .gsub!('synopsis:', 'synopsis: "' + item[:description] + '"')
              .gsub!('category:', "category:\n  - \"" + item[:category] + '"')
              .gsub!('language: es', 'language: en')
              .gsub!('cover:', 'cover: cover.png')
  change_file('meta-data.yaml', yaml_content)

  # Creates the cover
  FileUtils.cp(cover_url + 'svg/cover.svg', cover_url + 'svg/cover_tmp.svg')
  svg_content = File.read(cover_url + 'svg/cover_tmp.svg')
  svg_content = replace_content(svg_content, item[:title])
  change_file(cover_url + 'svg/cover_tmp.svg', svg_content)
  Dir.mkdir(cover_url + 'img')
  quiet = `inkscape -z -e #{cover_url}img/cover.png #{cover_url}svg/cover_tmp.svg`

  # Copies the images
  Dir.glob('../../img/*.*').each do |img|
    if File.basename(img) =~ /^e#{File.basename(md)[5..7]}/
      FileUtils.cp(img, cover_url + 'img')
    end
  end

  # Creates the ebooks
  system("pc-automata -f ../#{html_name} -i #{cover_url}img -c #{cover_url}img/cover.png -s ../../css/core.css -x ../../template/ebooks/xhtml --no-pre --no-analytics --no-ace")

  # Removes temporary covers
  FileUtils.rm("#{cover_url}svg/cover_tmp.svg")
  FileUtils.rm_rf("#{cover_url}img")

  # Renames and moves the ebooks
  Dir.glob('*.{epub,mobi}').each do |ebook|
    if File.basename(ebook) !~ /^epub-[\w|\d]+?\.epub/
      FileUtils.mv(ebook, '../../ebooks/' + File.basename(md, '.*') + File.extname(ebook))
    end
  end
  Dir.chdir('..')

  # Changes head, header, footer and styles for the final HTML
  write = false
  html_content = File.read(html_name).gsub(/\n/,'')
  html_content.gsub!(/.*?<\/style>\s+/, '')
              .gsub!(/<\/body>.*?$/, '')
  change_file(html_name, [replace_content($head, item[:title]), 
                          replace_content($header), 
                          html_content, 
                          replace_content($footer)])

  # Deletes temporary folder
  Dir.chdir('..')
  FileUtils.rm_rf('tmp')

  # Adds content to RSS
  $rss[:channel][:items].push(item)
end

# Converts the RSS to a XML syntax
def create_xml hash, space = ''
  hash.each do |k, v|
    if k.to_s != 'items'
      $xml.push(space + '<' + k.to_s + '>')

      if k.to_s == 'channel'
        $xml.push(space + '  <atom:link href="' + $site_link + '/feed/rss.xml" rel="self" type="application/rss+xml" />')
      end
    end

    if v.class == Hash
      create_xml(v, space + '  ')
    elsif v.class == Array
      v.each do |e| 
        $xml.push(space + '<item>')
        create_xml(e, space + '  ')
        $xml.push(space + '</item>')
      end
    else
      $xml.push(space + '  ' + v)
    end

    if k.to_s != 'items' 
      $xml.push(space + '</' + k.to_s + '>')
    end
  end
end

#=> Deployment

# Generates core CSS
Dir.chdir('css')
system("pc-add --add css")
change_file('core.css', [File.read('styles.css'), File.read('ebooks.css')])
Dir.chdir('..')

# Gets MDs to convert in other formats
Dir.glob('md/*.{md}').each_with_index do |md, i|
  convert_md(File.absolute_path(md))
end

# Last info added to RSS
$rss[:channel][:lastBuildDate] = get_date($date, true)
$rss[:channel][:items].sort_by!{|h| h[:link]}.reverse!
create_xml($rss)

# Builds index.html
puts "Building 'index.html'…"
html_content = []
$rss[:channel][:items].each do |item|
  inner_html = '<div class="entry" id="' + item[:guid].split('/').last + '"><p>' +
    '<a href="' + item[:link] + '">' + item[:title] + '</a>' +
    '</p><p class="meta">' + get_date(Time.parse(item[:pubDate]).to_s.split(/\s+/)[0]) +
    ' | ' + item[:category] + '</p><p>' + item[:description] + '</p></div>'
  html_content.push(inner_html.gsub!($site_link, '.'))
end
change_file('index.html', [replace_content($head), 
                           replace_content($header), 
                           html_content, 
                           replace_content($footer)])

# Builds RSS
puts "Building 'rss.xml'…"
change_file('feed/rss.xml', ['<?xml version="1.0" ?>', 
                             '<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">', 
                             $xml, 
                             '</rss>'])