#!/usr/bin/ruby

###
### kwartz -- a template system for web-designer and web-programmer
###
### Copyright (C) 2004 kuwata-lab
### All rights reserved.
### author::  kwa(at)kuwata-lab.com
### id::      $Id: kwartz,v 0.29 2004/05/09 03:50:23 kwatch Exp kwatch $
###

### This project is subsidized by Exploratory Software Project of IPA
### (Information-Technology Promotion Agency Japan).
### See http://www.ipa.go.jp/about/english/index.html for IPA.

### 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

require 'kwartz'
#require 'kwartz/compiler
#require 'kwartz/converter
#require 'kwartz/scanner
#require 'kwartz/parser
#require 'kwartz/translator
#require 'kwartz/translator/ruby
#require 'kwartz/translator/ruby2
#require 'kwartz/translator/php'
#require 'kwartz/translator/jsp'
#require 'kwartz/translator/eruby'
#require 'kwartz/translator/erb'
#require 'kwartz/translator/erbscan'
#require 'kwartz/translator/velocity'
#require 'kwartz/util'


## main class
class Main

    SCRIPT_VERSION    = ('$Revision: 0.29 $' =~ /\d+(?:\.\d+)+/ && $&)
    SCRIPT_LASTUPDATE = ('$Date: 2004/05/09 03:50:23 $' =~ /\d+[-\/]\d+[-\/]\d+/ && $&)

    def version_msg()
	msg = <<END
#{@command}: #{SCRIPT_VERSION} (#{SCRIPT_LASTUPDATE}), kwartz.rb: #{Kwartz::VERSION} (#{Kwartz::LAST_UPDATE})
END
	return msg
    end

    def usage_msg
	msg = <<END
Usage1 (normal mode):
  #{@command} [options...] file.html > file.output
Usage2 (batch mode):
  #{@command} -O output-suffix [-P plogic-suffix] [-T] [-S] [options...] *.html

Options:
  -h, --help       : print help
  -v               : print version
  -a action        : compile / convert / translate / analyze (default: compile)
  -l lang          : ruby/ruby2/php/jsp/eruby/erb/erbscan/velocity
  -s               : auto-sanitizing (this is equal to '--escape=true')
  -p plogic-file   : presentation logic file
  -O output-suffix : (batch-modde) suffix of output file
  -P plogic-suffix : (batch-modde) suffix of presentation logic file
  -T               : (batch-modde) compare timestamp
  -S               : (batch-modde) suppress messages
  --escape=true          : auto-sanitizing
  --delete_idattr=true   : delete 'id="name"', as well as 'id="mark:name"'
  --enable_eruby=true    : enable eRuby in presentation logic (requires ERB)
  --odd_value=value      : odd  value in FOREACH or LIST (default "'odd'")
  --even_value=value     : even value of FOREACH or LIST (default "'even'")
  --attr_name=attr       : use attribute name as marking (default 'kd')
  --charset=charset      : prints '<%@ page contentType="...">' when jsp
  --header=string        : header string (default '<%@ taglib ...>' when jsp)
  --footer=string        : footer string (default nil)
  --include_path=dir1,dir2,...  : path list for 'include' directive
  --load_path=dir1,dir2,...     : path list for 'load' directive

Examples:
 * compile sample.html into php script with presentation logic sample.plogic
      $ #{@command} -l php -p sample.plogic sample.html > sample.php
 * compile sample.html into JSP with charset 'EUC-JP'
      $ #{@command} -l jsp sample.html --charset=EUC-JP > sample.jsp
 * compile all html file into eruby script, with each presentation logic file
      $ #{@command} -l eruby -O .rhtml -P .plogic *.html
 * convert sample.html into intermediate code
      $ #{@command} -a convert sample.html
END
#Options:
#  --create_foreach_macro : create macros for ':foreach' or ':list' directive
#  --header_text=string   : header text (default '<%@ taglib ...>' when jsp)
#  --footer_text=string   : footer text (default nil)
#  --header_plcode=code   : header PL code (default nil)
#  --footer_plcode=code   : footer PL code (default nil)
#  --header_rawcode=code  : header raw-code (default '<%@ taglib ...>' when jsp)
#  --footer_rawcode=code  : footer raw-code (default nil)
#Examples:
# * compile sample.html with odd/even value '#FFCCCC'/'#CCCCFF' of FOREACH or LIST
#      $ #{@command} --odd_value="'#FFCCCC'" --even_value="'#CCCCFF'" sample.html
#END
	return msg
    end

    def main(argv=ARGV)
	## parse ARGV
	envstr  = ENV['KWARTZ_OPTIONS']
	argv[0,0] = envstr.split(' ') if envstr
	begin
	    options, @toppings = Kwartz::Util.parse_argv(argv, "shvTS", "alpPO")
	    reflect_options(options)
	    validate_values()
	rescue Kwartz::Util::CommandOptionError => ex
	    $stderr.print "#{@command}: ", ex.message, "\n"
	    #$stderr.print usage_msg()
	    exit 1
	end
	
	## print help or version
	if @flag_help || @flag_version then
	    $stdout.print version_msg() if @flag_version
	    $stdout.print "\n"          if @flag_version && @flag_help
	    $stdout.print usage_msg()   if @flag_help
	    exit 0
	end

	## toppings
	handle_toppings()

	## main logic
	mode = :normal				## default
	mode = :batch if @output_suffix
	case mode 
	when :normal
	    plogic = ''
	    @plogic_filename.split(/,/).each do |filename|
		File.open(filename) { |f| plogic << f.read() }
	    end if @plogic_filename
	    input = ARGF.read()
	    begin
		output = Kwartz::Helper.do_action(@action, input, plogic, @lang, @toppings)
		$stdout.print output
	    rescue => ex
		$stderr.print ex.message, "\n"
	    end
	when :batch
	    plogic_filename = @plogic_filename ? @plogic_filename.split(/,/).first : nil
	    ARGV.each do |input_filename|
		basename = input_filename.sub(/\.\w+$/, '')
		output_filename = basename + @output_suffix
		if @plogic_suffix then
		    plogic_filename = basename + @plogic_suffix
		    plogic_filename = @plogic_filename if !test(?f, plogic_filename)
		end
		begin
		    if @flag_timestamp && newer?(output_filename, input_filename, plogic_filename) then
			s = "[--] #{output_filename} is newer than #{input_filename}"
			s << " and #{plogic_filename}" if plogic_filename
			s << "\n"
		    else
			input  = File.open(input_filename) { |f| f.read() }
			plogic = ''
			plogic = File.open(plogic_filename) { |f| f.read() } if plogic_filename
			output = Kwartz::Helper.do_action(@action, input, plogic, @lang, @toppings)
			File.open(output_filename, 'w') { |f| f.print(output) }
			s = "[OK] #{input_filename}"
			s << " + #{plogic_filename}" if plogic_filename
			s << " => #{output_filename}\n"
		    end
		    $stdout.print s unless @flag_silent
		rescue => ex
		    s = "[ERROR] "
		    s << ex.message
		    s << "\n"
		    $stderr.print s
		end
	    end
	end # /case
    end # /def main

    def initialize(command)
	@command = command
	@toppings = {}
	
	@action          = 'compile'	## -a
	@lang            = 'ruby'	## -l
	@plogic_filename = nil		## -p
	@output_suffix   = nil		## -O
	@plogic_suffix   = nil		## -P
	@flag_sanitize   = false	## -s
	@flag_timestamp  = false	## -T
	@flag_silent     = false	## -S
	@flag_help       = false	## -h
	@flag_version    = false	## -v
    end

    def reflect_options(options)
	options.each do |key, value|
	    case key
	    when ?a  ;  @action          = value
	    when ?l  ;  @lang            = value
	    when ?p  ;  @plogic_filename = value
	    when ?O  ;  @output_suffix   = value
	    when ?P  ;  @plogic_suffix   = value
	    when ?s  ;  @flag_sanitize   = value
	    when ?T  ;  @flag_timestamp  = value
	    when ?S  ;  @flag_silent     = value
	    when ?h  ;  @flag_help       = value
	    when ?v  ;  @flag_version    = value
	    end
	end
    end

    def validate_values()
	Kwartz::assert() if !@action
	case @action
	when 'compile', 'convert', 'translate', 'analyze'
	    # ok
	when 'parse', 'scan', 'delete_directives', 'fetch'
	    # ok
	else
	    msg = "-a #{@action}: invalid action."
	    raise Kwartz::Util::CommandOptionError.new(msg)
	end
	
	Kwartz::assert() if !@lang
	unless Kwartz::Translator.registered?(@lang) then
	    msg = "-l #{@lang}: unsupported language name."
	    raise Kwartz::Util::CommandOptionError.new(msg)
	end
    end

    def handle_toppings()
	## sanitize
	@toppings[:escape] = true if @flag_sanitize

	## header
	header = nil
	case @lang
	when 'jsp'
	    header = ''
	    if cset = @toppings[:charset] then
		header = "<%@ page contentType=\"text/html; charset=#{cset}\" %>\n"
	    end
	    s = "<%@ taglib prefix=\"c\" uri=\"http://java.sun.com/jstl/core\" %>\n"
	    header << (@toppings[:header] || s)
	    @toppings[:header] = header
	#when 'ruby2'
	#    header = "_s = ''\n"
	#    @toppings[:header] ||= header
	end

	## enable eruby
	@toppings[:lang] = @lang if @toppings[:enable_eruby]

	## include_path and load_path
	if value = @toppings[:include_path] then
	    @toppings[:include_path] = value.split(/,/)
	end
	if value = @toppings[:load_path] then
	    @toppings[:load_path] = value.split(/,/)
	end
    end

    def newer?(output_filename, input_filename, plogic_filename)
	return false if !test(?f, output_filename)
	return false if File.mtime(output_filename) <= File.mtime(input_filename)
	if plogic_filename && test(?f, plogic_filename) then
	    return false if File.mtime(output_filename) <= File.mtime(plogic_filename)
	end
	return true
    end

end


## main program
if __FILE__ == $0 then
    command = File.basename($0)
    Main.new(command).main(ARGV)
end

#[EOF]