#!/usr/bin/env ruby

$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])

help = <<HELP
Gollum is a multi-format Wiki Engine/API/Frontend.

Basic Command Line Usage:
  gollum [OPTIONS] [PATH]

        PATH                         The path to the Gollum repository (default .).

Options:
HELP

require 'optparse'
require 'rubygems'
require 'gollum'

exec         = {}
options      = { 'port' => 4567, 'bind' => '0.0.0.0' }
wiki_options = {
    :live_preview  => false,
    :allow_uploads => false,
    :allow_editing => true,
}

opts = OptionParser.new do |opts|
  opts.banner = help

  opts.on("--port [PORT]", "Bind port (default 4567).") do |port|
    options['port'] = port.to_i
  end

  opts.on("--host [HOST]", "Hostname or IP address to listen on (default 0.0.0.0).") do |host|
    options['bind'] = host
  end

  opts.on("--version", "Display current version.") do
    puts "Gollum " + Gollum::VERSION
    exit 0
  end

  opts.on("--config [CONFIG]", "Path to additional configuration file") do |config|
    options['config'] = config
  end

  opts.on("--adapter [ADAPTER]", "Git adapter to use in the backend. Defaults to grit.") do |adapter|
    Gollum::GIT_ADAPTER = adapter
  end

  opts.on("--irb", "Start an irb process with gollum loaded for the current wiki.") do
    options['irb'] = true
  end

  opts.on("--css", "Inject custom css. Uses custom.css from root repository") do
    wiki_options[:css] = true
  end

  opts.on("--js", "Inject custom js. Uses custom.js from root repository") do
    wiki_options[:js] = true
  end

  opts.on("--template-dir [PATH]", "Specify custom template directory") do |path|
    wiki_options[:template_dir] = path
  end

  opts.on("--page-file-dir [PATH]", "Specify the sub directory for all page files (default: repository root).") do |path|
    wiki_options[:page_file_dir] = path
  end

  opts.on("--base-path [PATH]", "Specify the base path for the served pages (default: /) Example: --base-path wiki yields the home page accessible at http://localhost:4567/wiki/.") do |path|
    wiki_options[:base_path] = path
  end

  opts.on("--gollum-path [PATH]", "Specify the path to the git repository to be served.") do |path|
    wiki_options[:gollum_path] = path
  end

  opts.on("--ref [REF]", "Specify the repository ref to use (default: master).") do |ref|
    wiki_options[:ref] = ref
  end

  opts.on("--no-edit", "Restricts editing capability through frontend.")  do
    wiki_options[:allow_editing] = false
  end

  opts.on("--no-live-preview", "Disables livepreview.") do
    wiki_options[:live_preview] = false
  end

  opts.on("--live-preview", "Enables livepreview.") do
    wiki_options[:live_preview] = true
  end

  opts.on("--allow-uploads [MODE]", [:dir, :page], "Allows file uploads. Modes: dir (default, store all uploads in the same directory), page (store each upload at the same location as the page).") do |mode|
    wiki_options[:allow_uploads]    = true
    wiki_options[:per_page_uploads] = true if mode == :page
  end

  opts.on("--mathjax", "Enables mathjax for rendering mathematical equations. Uses the TeX-AMS-MML_HTMLorMML config with the autoload-all extension by default.") do
    wiki_options[:mathjax] = true
  end

  opts.on("--mathjax-config [SOURCE]", "Inject custom mathjax config file. Uses mathjax.config.js from root repository by default") do |source|
    wiki_options[:mathjax_config] = source || 'mathjax.config.js'
  end

  opts.on("--user-icons [SOURCE]", "Set the history user icons. Valid values: gravatar, identicon, none. Default: none.") do |source|
    wiki_options[:user_icons] = source
  end

  opts.on("--show-all", "Shows all files in file view. By default only valid pages are shown.") do
    wiki_options[:show_all] = true
  end

  opts.on("--collapse-tree", "Collapse file view tree. By default, expanded tree is shown.") do
    wiki_options[:collapse_tree] = true
  end
  opts.on("--h1-title", "Sets page title to value of first h1") do
    wiki_options[:h1_title] = true
  end
end

# Read command line options into `options` hash
begin
  opts.parse!
rescue OptionParser::InvalidOption
  puts "gollum: #{$!.message}"
  puts "gollum: try 'gollum --help' for more information"
  exit
end

# --gollum-path wins over ARGV[0]
gollum_path = wiki_options[:gollum_path] ?
    wiki_options[:gollum_path] :
    ARGV[0] || Dir.pwd

if options['irb']
  require 'irb'
  # http://jameskilton.com/2009/04/02/embedding-irb-into-your-ruby-application/
  module IRB # :nodoc:
    def self.start_session(binding)
      unless @__initialized
        args = ARGV
        ARGV.replace(ARGV.dup)
        IRB.setup(nil)
        ARGV.replace(args)
        @__initialized = true
      end

      ws  = WorkSpace.new(binding)
      irb = Irb.new(ws)

      @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
      @CONF[:MAIN_CONTEXT] = irb.context

      catch(:IRB_EXIT) do
        irb.eval_input
      end
    end
  end

  begin
    require 'gollum-lib'
    wiki = Gollum::Wiki.new(gollum_path, wiki_options)
    if !wiki.exist? then
      raise Gollum::InvalidGitRepositoryError
    end
    puts "Loaded Gollum wiki at #{File.expand_path(gollum_path).inspect}."
    puts
    puts %(    page = wiki.page('page-name'))
    puts %(    # => <Gollum::Page>)
    puts
    puts %(    page.raw_data)
    puts %(    # => "# My wiki page")
    puts
    puts %(    page.formatted_data)
    puts %(    # => "<h1>My wiki page</h1>")
    puts
    puts "Check out the Gollum README for more."
    IRB.start_session(binding)
  rescue Gollum::InvalidGitRepositoryError, Gollum::NoSuchPathError
    puts "Invalid Gollum wiki at #{File.expand_path(gollum_path).inspect}"
    exit 0
  end
else
  require 'gollum/app'
  Precious::App.set(:gollum_path, gollum_path)
  Precious::App.set(:wiki_options, wiki_options)
  Precious::App.settings.mustache[:templates] = wiki_options[:template_dir] if wiki_options[:template_dir]

  if cfg = options['config']
    # If the path begins with a '/' it will be considered an absolute path,
    # otherwise it will be relative to the CWD
    cfg = File.join(Dir.getwd, cfg) unless cfg.slice(0) == File::SEPARATOR
    require cfg
  end

  base_path = wiki_options[:base_path]

  if wiki_options[:base_path].nil?
    Precious::App.run!(options)
  else
    require 'rack'

    class MapGollum
      def initialize base_path
        @mg = Rack::Builder.new do
          map '/' do
            run Proc.new { [302, { 'Location' => "/#{base_path}" }, []] }
          end

          map "/#{base_path}" do
            run Precious::App
          end
        end
      end

      def call(env)
        @mg.call(env)
      end
    end
    # Rack::Handler does not work with Ctrl + C. Use Rack::Server instead.
    Rack::Server.new(:app => MapGollum.new(base_path), :Port => options['port'], :Host => options['bind']).start
  end
end
