#!/usr/bin/env ruby
require 'rubygems'
require 'redcarpet'
require 'fileutils'
require 'impress_renderer'
require 'trollop'
require 'tempfile'
require 'launchy'

THEMES_DIRNAME = './themes/'

def log(x)
  puts "\033[94m" + x + "\033[0m" if OPTS[:verbose]
end

def base_dir
  File.dirname(__FILE__) + "/../lib/"
end

def list_available_stylesheets
  log "Available stylesheets:"
  log "mdpress stylesheets"
  Dir.glob(base_dir + "impress_css/*.css").each do |file|
    puts File.basename(file, ".css")
  end
  log "Local stylesheets"
  Dir.glob(THEMES_DIRNAME + "*.css").each do |file|
    puts File.basename(file, ".css")
  end
end

def readfile file
  if file =~ /^http/
    require 'httparty'
    response = HTTParty.get(file)
    if response
      return response.body
    else
      raise "couldn't download url: #{file}"
    end
  else
    return File.read(file)
  end
end

def render opts
  text = readfile(FILENAME)
  # ugly hack to get attributes for impress.js
  # TODO make this pretty
  lines = text.split("\n")
  lines.drop_while { |l| l =~ /^\s*$/ }

  attrs = [""]
  
  new_lines = []
  lines.each_with_index do |line, i|
    if line =~ /^=(.*)$/ && (i == 0 || lines[i-1] =~ /^(-\s*){3,}$/)
      line =~ /^=(.*)$/
      attrs[attrs.size-1] = $~.to_a[1]
      next
    elsif line =~ /^(-\s*){3,}$/
      attrs << ""
    end
    new_lines << line
  end

  text = new_lines.join("\n")

  # now use those attributes and render the file
  include Redcarpet
  ImpressRenderer.init_with_attrs attrs, opts
  if File.exist?(STYLESHEET_HEAD)
    ImpressRenderer.set_head(File.read(STYLESHEET_HEAD))
  else
    ImpressRenderer.set_head("")
  end

  m = Markdown.new(ImpressRenderer, :autolink => true, :fenced_code_blocks => true, :tables => true)
  log "rendering presentation"
  f = File.open(DIRNAME + "/index.html", "w+")
  f.write(m.render(text))
  f.close
end

OPTS = Trollop::options do
  banner <<-EOS
Usage: mdpress [filename] [options]
where [options] are:
EOS
  opt :automatic, "Keeps running and automatically updates the presentation to reflect changes to markdown file."
  opt :stylesheet,  "Specify what stylesheet to use.", :default => "default"
  opt :list, "List all available stylesheets."
  opt :run, "Run presentation (automatically compiles to a tmp directory and opens in a browser window)"
  opt :latex, "Provide Latex support"
  opt :verbose, "Be verbose."
end

if OPTS[:list]
  list_available_stylesheets
  exit
end

Trollop::die("no file specified") if ARGV.empty? # show help screen

if OPTS[:run]
  file = ARGV[0]
  tmp = Tempfile.new("mdpress")
  tmp.write(readfile(file))
  tmp.flush
  FILENAME = tmp.path
  DIRNAME = FILENAME + "_dir"
else
  FILENAME = ARGV[0]
  DIRNAME = File.basename(FILENAME, File.extname(FILENAME))
end

if File.exist?(THEMES_DIRNAME + "#{OPTS[:stylesheet]}.css")
    STYLESHEET = THEMES_DIRNAME + "#{OPTS[:stylesheet]}.css"
    STYLESHEET_HEAD = THEMES_DIRNAME + "#{OPTS[:stylesheet]}.html"
else 
    STYLESHEET = base_dir + "impress_css/#{OPTS[:stylesheet]}.css"
    STYLESHEET_HEAD = base_dir + "impress_css/#{OPTS[:stylesheet]}.html"
end

unless File.exist?(STYLESHEET)
  puts OPTS[:stylesheet] + " is not a valid stylesheet. See available stylesheets with `mdpress -l`."
  exit
end

if File.exist?(DIRNAME)
  unless File.directory?(DIRNAME)
    puts "please delete the file: #{DIRNAME} before continuing."
    exit
  end
else
  log "making directory"
  Dir.mkdir(DIRNAME)
end

render OPTS

log "copying files"
FileUtils.cp_r(base_dir + "js", DIRNAME)
FileUtils.cp_r(base_dir + "css", DIRNAME)
FileUtils.cp(STYLESHEET, DIRNAME + "/css/style.css")

def auto
  while true
    sleep 2
    if FileUtils.uptodate?(FILENAME, [DIRNAME + "/index.html"])
      log "updating from #{FILENAME}"
      render OPTS
    end
    # Takes care of updating stylesheets for local styles.
    if FileUtils.uptodate?(STYLESHEET, [DIRNAME + "/css/style.css"])
      log "updating stylesheet #{STYLESHEET}"
      FileUtils.cp(STYLESHEET, DIRNAME + "/css/style.css")
    end
  end
end

if OPTS[:automatic]
  if ARGV[0] =~ /^http/
    puts "Can't run in auto mode for remote files."
  else
    log "waiting for updates..."
    auto
  end
elsif OPTS[:run]
  log "opening in browser."
  Launchy.open(DIRNAME + "/index.html", :application => :browser)
else
  log "done."
end
