#! /usr/bin/env ruby
# Author::    Nicolas Despr�s  <nicolas.despres@lrde.epita.fr>.
# Copyright:: Copyright (c) 2005 Uttk Team. All rights reserved.
# License::   LGPL
# $Id: /w/fey/uttk/trunk/misc/textile_compiler 22074 2006-02-21T13:47:00.947568Z pouillar  $

require 'erb'
require 'pathname'
require 'optparse'

module TextileCompiler

  DEFAULT_SEVERITY_LEVEL = :warning

  SEVERITY_LEVELS = {
    :fatal => 0,
    :error => 1,
    :warning => 2,
    :info => 3,
    :debug => 4
  }

  def self.severity_level=(level)
    @@severity_level = level
  end

  def self.severity_level
    @@severity_level
  end

  def self.log(level, message)
    @@severity_level ||= DEFAULT_SEVERITY_LEVEL
    if SEVERITY_LEVELS[level] <= SEVERITY_LEVELS[@@severity_level]
      STDERR.puts "#{File.basename($0)}: #{level}: #{message}"
    end
  end

  def self.error(message)
    log(:error, message)
  end

  def self.fatal(message)
    log(:fatal, message)
    raise message
  end

  def self.warning(message)
    log(:warning, message)
  end

  def self.info(message)
    log(:info, message)
  end

  def self.debug(message)
    log(:debug, message)
  end

  class Compiler

    DEFAULT_OPTIONS = {
      :input_extension => '.rtextile',
      :output_extension => '.textile'
    }

    def initialize(commands, options={})
      @command = commands
      @options = DEFAULT_OPTIONS
      @options.merge!(options)
      TextileCompiler.debug("current directory = `#{Pathname.pwd}'")
    end

    def compile(*pathnames)
      pathnames.each do |src_pathname|
        if src_pathname.extname == @options[:input_extension]
          base_pathname = src_pathname.to_s.sub(/#{src_pathname.extname}$/, '')
          dest_pathname = Pathname.new(base_pathname +
                                       @options[:output_extension])
          dest_pathname.open('w') do |f|
            f.write ERB.new(src_pathname.read).result(@command.get_binding)
          end
        else
          TextileCompiler.warning("unknown file extension, ignore `#{src_pathname}'")
        end
      end
    end

  end # class Compiler

  class Textile

    def initialize
      @fixtures_directory = Pathname.new(".")
    end

    def get_binding
      binding
    end

    def comment(&block)
    end

    def command(command, options={})
      args = options[:arguments]
      args ||= []
      args = args.join(' ')

      cmd = "#{command} #{args}"
      cmd = "echo #{options[:input]} | #{cmd}" if options[:input]
      TextileCompiler.info("cmd `#{cmd}'")

      result = "|{background:#ddd}.<code>$ #{cmd}</code>|\n\n"

      TextileCompiler.debug("options[:directory] = `#{options[:directory]}'")
      directory = options[:directory]
      directory ||= "."
      directory = @fixtures_directory + Pathname.new(directory)
      unless directory.directory? and directory.executable? and directory.readable?
        TextileCompiler.error("bad directory `#{directory}' " +
                              "(fixtures_directory = `#{@fixtures_directory}'")
      end
      TextileCompiler.debug("directory = `#{directory}'")

      full_cmd = "cd #{directory} && #{cmd}"
      full_cmd += " 2>&1" if options[:with_stderr]
      TextileCompiler.debug("run `#{full_cmd}'")
      unless options[:without_output]
        result += "<pre>\n" + `#{full_cmd}` + "\n</pre>"
      end
      status = $?.exitstatus
      if status != 0
        TextileCompiler.warning("the command `#{full_cmd}' has exited with " +
                                "status #{status}")
      end
      result
    end

    def fixtures_directory=(new_value)
      tmp = Pathname.new(new_value)
      if tmp.directory? and tmp.executable? and tmp.readable?
        @fixtures_directory = tmp
      else
        TextileCompiler.error("bad fixture directory `#{tmp}'")
      end
    end

    attr_reader :fixtures_directory

  end # class Textile

end # class TextileCompiler


ME_DIR, ME = Pathname.new($0).split

options = TextileCompiler::Compiler::DEFAULT_OPTIONS
opts = OptionParser.new do |opts|

  opts.banner = "Usage: #{ME} [options] <.rtextile files>..."
  opts.separator ''

  opts.summary_indent = '  '
  opts.summary_width = 28

  opts.on('--input-extension EXT',
          "Input extention (default: #{options[:input_extension]})") do |ext|
    options[:input_extenstion] = ext
  end

  opts.on('--output-extension EXT',
          "Output extention (default: #{options[:output_extension]})") do |ext|
    options[:output_extenstion] = ext
  end

  opts.on('-s',
          '--severity LEVEL',
          TextileCompiler::SEVERITY_LEVELS.keys,
          'Log severity level (no argument for the list)') do |lvl|
    if lvl.nil?
      puts "Log severity level:"
      TextileCompiler::SEVERITY_LEVELS.keys.each { |l| puts " - #{l}" }
      exit
    else
      TextileCompiler.severity_level = lvl
    end
  end

end

opts.parse!(ARGV)
ARGV.map! { |arg| Pathname.new(arg) }

TextileCompiler::Compiler.new(TextileCompiler::Textile.new).compile(*ARGV)