#! /usr/bin/env ruby
=begin
  rgettext.rb - Generate a .pot file.

  Copyright (C) 2003-2010  Masao Mutoh
  Copyright (C) 2001,2002  Yasushi Shoji, Masao Mutoh

      Yasushi Shoji   <yashi at atmark-techno.com>
      Masao Mutoh     <mutomasa at gmail.com>

  You may redistribute it and/or modify it under the same
  license terms as Ruby or LGPL.
=end

require 'optparse'
require 'gettext'
require 'rbconfig'

module GetText

  module RGetText #:nodoc:
    extend GetText

    bindtextdomain("rgettext")

    # constant values
    VERSION = GetText::VERSION

    @ex_parsers = []
    [
      ["glade.rb", "GladeParser"],
      ["erb.rb", "ErbParser"],
#      ["ripper.rb", "RipperParser"],
      ["ruby.rb", "RubyParser"] # Default parser.
    ].each do |f, klass|
      begin
        require "gettext/tools/parser/#{f}"
        @ex_parsers << GetText.const_get(klass)
      rescue
        $stderr.puts _("'%{klass}' is ignored.") % {:klass => klass}
        $stderr.puts $! if $DEBUG
      end
    end

    module_function

    # Add an option parser
    # the option parser module requires to have target?(file) and parser(file, ary) method.
    #
    #  require 'gettext/tools/rgettext'
    #  module FooParser
    #    module_function
    #    def target?(file)
    #      File.extname(file) == '.foo'  # *.foo file only.
    #    end
    #    def parse(file)
    #      :
    #      ary = []
    #      # Simple message
    #      po = PoMessage.new(:normal)
    #      po.msgid = "hello"
    #      po.sources = ["foo.rb:200", "bar.rb:300"]
    #      po.add_comment("Comment for the message")
    #      ary << po
    #      # Plural message
    #      po = PoMessage.new(:plural)
    #      po.msgid = "An apple"
    #      po.msgid_plural = "Apples"
    #      po.sources = ["foo.rb:200", "bar.rb:300"]
    #      ary << po
    #      # Simple message with the message context
    #      po = PoMessage.new(:msgctxt)
    #      po.msgctxt = "context"
    #      po.msgid = "hello"
    #      po.sources = ["foo.rb:200", "bar.rb:300"]
    #      ary << po
    #      # Plural message with the message context.
    #      po = PoMessage.new(:msgctxt_plural)
    #      po.msgctxt = "context"
    #      po.msgid = "An apple"
    #      po.msgid_plural = "Apples"
    #      po.sources = ["foo.rb:200", "bar.rb:300"]
    #      ary << po
    #      return ary
    #    end
    #  end
    #
    #  GetText::RGetText.add_parser(FooParser)
    def add_parser(klass)
      @ex_parsers.insert(0, klass)
    end

    def generate_pot_header # :nodoc:
      time = Time.now.strftime("%Y-%m-%d %H:%M")
      off = Time.now.utc_offset
      sign = off <= 0 ? '-' : '+'
      time += sprintf('%s%02d%02d', sign, *(off.abs / 60).divmod(60))

      <<TITLE
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\\n"
"POT-Creation-Date: #{time}\\n"
"PO-Revision-Date: #{time}\\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n"
"Language-Team: LANGUAGE <LL@li.org>\\n"
"MIME-Version: 1.0\\n"
"Content-Type: text/plain; charset=UTF-8\\n"
"Content-Transfer-Encoding: 8bit\\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\\n"
TITLE
    end

    def generate_pot(paths) # :nodoc:
      pomessages = parse(paths)
      str = ""
      pomessages.each do |target|
        str << target.to_po_str
      end
      str
    end

    def parse(paths) # :nodoc:
      pomessages = []
      paths = [paths] if paths.kind_of? String
      paths.each do |path|
        begin
          @ex_parsers.each do |klass|
            if klass.target?(path)
              if klass.method(:parse).arity == 1
                targets = klass.parse(path)
              else
                # For backward compatibility.
                targets = klass.parse(path, [])
              end

              targets.each{|pomessage|
                if pomessage.kind_of? Array
                  pomessage = PoMessage.new_from_ary(pomessage)
                end

                # Save the previous target.
                existing = pomessages.empty? ? nil : pomessages.index(pomessages.find {|t| t == pomessage})
                if existing
                  pomessage = pomessages[existing].merge(pomessage)
                  pomessages[existing] = pomessage
                else
                  pomessages << pomessage
                end
              }
              break
            end
          end
        rescue
          puts _("Error parsing %{path}") % {:path => path}
          raise
        end
      end
      pomessages
    end

    def check_options # :nodoc:
      output = STDOUT

      opts = OptionParser.new
      opts.banner = _("Usage: %s input.rb [-r parser.rb] [-o output.pot]") % $0
      opts.separator("")
      opts.separator(_("Extract translatable strings from given input files."))
      opts.separator("")
      opts.separator(_("Specific options:"))

      opts.on("-o", "--output=FILE", _("write output to specified file")) do |out|
        unless FileTest.exist? out
          output = File.new(File.expand_path(out), "w+")
        else
          $stderr.puts(_("File '%s' already exists.") % out)
          exit 1
        end
      end

      opts.on("-r", "--require=library", _("require the library before executing rgettext")) do |out|
        require out
      end

      opts.on("-d", "--debug", _("run in debugging mode")) do
        $DEBUG = true
      end

      opts.on_tail("--version", _("display version information and exit")) do
        puts "#{$0} #{VERSION}"
        puts "#{File.join(Config::CONFIG["bindir"], Config::CONFIG["RUBY_INSTALL_NAME"])} #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
        exit
      end

      opts.parse!(ARGV)

      if ARGV.size == 0
        puts opts.help
        exit 1
      end

      [ARGV, output]
    end

    def run(paths = nil, out = STDOUT)  # :nodoc:
      if paths.is_a? String
        paths = [paths]
      elsif ! paths
        paths, out = check_options
      end
      if paths.size == 0
        raise ArgumentError, _("no input files")
      end
      if out.is_a? String
        File.open(File.expand_path(out), "w+") do |file|
          file.puts generate_pot_header
          file.puts generate_pot(paths)
        end
      else
        out.puts generate_pot_header
        out.puts generate_pot(paths)
      end
      self
    end
  end
  extend self
  # Creates a po-file from targetfiles(ruby-script-files, .rhtml files, glade-2 XML files),
  # then output the result to out. If no parameter is set, it behaves same as command line tools(rgettet).
  #
  # This function is a part of GetText.create_pofiles.
  # Usually you don't need to call this function directly.
  #
  # * paths: An Array of po-file paths or nil.
  # * out: output IO or output path.
  # * Returns: self
  def rgettext(paths = nil, out = STDOUT)
    RGetText.run(paths, out)
    self
  end
end

if $0 == __FILE__
  GetText.rgettext
#  GetText.rgettext($0, "tmp.txt")
end