#!/usr/bin/ruby1.8 -w

=begin
    Documentation generator for dhelp

    Copyright (C) 2005-2007  Esteban Manchado Velázquez

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
=end

# Keep the (non-existent) indentation in next line (the "PREFIX" one)
PREFIX = "/usr"
DEFAULT_INDEX_ROOT = "#{PREFIX}/share/doc/HTML"

require 'dhelp'
require 'dhelp/exporter/html'
include Dhelp

require 'commandline'
require 'find'
require 'yaml'


# Configuration class
class DhelpConf
  def initialize(path)
    @conf = YAML::load_file(path)
    @conf["search_directories"] ||= DEFAULT_SEARCH_DIRS
  end

  def to_hash
    @conf
  end

  def method_missing(meth)
    @conf[meth.to_s]
  end
end


# dhelp_parse application class
class DhelpParseApp < CommandLine::Application
  DHELP_CONF_FILE    = "/etc/dhelp.conf"
  DOC_DIR                 = '/usr/share/doc'
  DOC_BASE_DHELP_DIR      = '/var/lib/doc-base/dhelp'
  DEFAULT_SEARCH_DIRS     = [DOC_DIR, DOC_BASE_DHELP_DIR]

  def initialize
    version           "0.2.0"
    author            "Esteban Manchado Velázquez"
    copyright         "Copyright (c) 2005-2007, Esteban Manchado Velázquez"
    synopsis          "[-v] [-h] -a doc-base_file1 d-b_f2 ... | -d doc-base_file1 d-b_f2 ... | -i | -r"
    short_description "Debian online help system parser"
    long_description  "Dhelp parser to add/remove/index-incrementally/fully-reindex dhelp files"

    option :help
    option :names => %w(-a), :arity => [0,-1],
           :opt_found => lambda {|opt, name, value| @action = :add;
                                                    @doc_base_files = value },
           :opt_description => "add documents registered in the given doc-base file"
    option :names => %w(-d), :arity => [0,-1],
           :opt_found => lambda {|opt, name, value| @action = :delete;
                                                    @doc_base_files = value },
           :opt_description => "remove documents registered in the given doc-base file"
    option :names => %w(-v), :arity => [0,0],
           :opt_found => lambda { @verbose = true },
           :opt_description => "verbose"
    option :names => %w(-i), :arity => [0,0],
           :opt_found => lambda { @action = :index },
           :opt_description => "perform deferred incremental indexing of pending registered docs"
    option :names => %w(-r), :arity => [0,0],
           :opt_found => lambda { @action = :reindex },
           :opt_description => "perform full re-indexing of all registered docs"

    expected_args [0,0]

    @action  = nil
    @verbose = false
  end

  def packaged_configured?
    File.exists? '/var/lib/dhelp/configured'
  end

  # Adds the documents supplied in command-line to the pool.
  def add_documents(pool)
    @doc_base_files.each do |doc_base_file|
      if File.readable?(doc_base_file)
        if @verbose
          puts "Parsing document #{doc_base_file}"
        end
        doc_base_doc = Dhelp::DocBaseDocument.new(doc_base_file)
        if @verbose
          puts "Registering document #{doc_base_file}"
        end
        pool.register(doc_base_doc)
      else
        # Don't stop on single file errors; allow others with no error
        # to be successfully registered.
        $stderr.puts "Can't read doc-base file '#{doc_base_file}'"
      end
    end
  end

  # Rebuilds the HTML indices to be in sync with pool's state.
  def rebuild_html_index(pool)
    if @verbose
      puts "Rebuilding documentation index at #{DEFAULT_INDEX_ROOT}"
    end
    exporter = Dhelp::Exporter::Html.new(pool)
    exporter.export(:dir => DEFAULT_INDEX_ROOT)
  end

  # Starts the indexer to index the pending-documents-for-indexing list
  def do_deferred_indexing(user_opts = {})
    opts = {}
    if user_opts.has_key? :incremental
      opts[:incremental] = user_opts[:incremental]
    end
    if @verbose
      puts "Indexing documents contained in pending list"
    end
    indexer = Dhelp::Indexer.new(opts)
    indexer.index
  end

  def main
    begin
      if packaged_configured?
        conf = DhelpConf.new(DHELP_CONF_FILE)
      else
        $stderr.puts "Deferring until dhelp is configured"
        exit 0
      end
    rescue Errno::ENOENT
      $stderr.puts "Can't read configuration file #{DHELP_CONF_FILE}"
      exit 1
    end

    # List of directories to look for doc-base documents
    doc_base_dirs = conf.search_directories.map {|d| File.expand_path(d)}
    pool = Dhelp::DhelpDocumentPool.new(:doc_base_dir => doc_base_dirs)

    case @action
    when :add
      add_documents(pool)
    when :delete
      @doc_base_files.each do |doc_base_file|
        if @verbose
          puts "Deregistering document #{doc_base_file}"
        end
        pool.deregister(doc_base_file)
      end
    when :index
      # Index incrementally, to update with registered so-far documents.
      # This is the normal mode of operation, called by the dpkg trigger
      # after the end of each installation run.
      do_deferred_indexing
      return 0
    when :reindex
      # Recreate the pool, without doing a full indexing.
      pool.rebuild(false)
    else
      $stderr.puts usage
      return 1
    end

    # Always executed
    # We cannot defer this, unless a persistence mechanism between 
    # subsequent invocations of this binary is setup.
    rebuild_html_index(pool)
  rescue => e
    puts "#{e.class}: #{e} (#{e.backtrace.join("\n")})"
  end
end
