=begin
= rd/rd2man-lib.rb
=end

require "rd/rdvisitor"
require "rd/version"

unless [].respond_to? :collect!
  class Array
    alias collect! filter
  end
end

module RD
  class RD2MANVisitor < RDVisitor
    include AutoLabel
    include MethodParse

    SYSTEM_NAME = "RDtool -- RD2ManVisitor"
    SYSTEM_VERSION = "$Version: "+RD::VERSION+"$"
    VERSION = Version.new_from_version_string(SYSTEM_NAME, SYSTEM_VERSION)

    def self.version
      VERSION
    end

    # must-have constants
    OUTPUT_SUFFIX = "1"
    INCLUDE_SUFFIX = ["1"]

    attr_accessor :man_section

    def initialize
      @enumcounter = 0
      @index = {}
      @filename = nil
      @man_section = OUTPUT_SUFFIX
    end

    def visit(tree)
      prepare_labels(tree, "")
      super(tree)
    end

    def apply_to_DocumentElement(element, content)
      content = content.join
      title = guess_title
      title = title.sub(/\.rd$/i, '').upcase
      <<"EOT"
.\\" DO NOT MODIFY THIS FILE! it was generated by rd2
.TH #{title} #{output_suffix} "#{Time.now.strftime '%Y-%m-%d'}"
#{content}
EOT
    end # "

    def apply_to_Headline(element, title)
      title = title.join(" ")
      element.level <= 1 ? ".SH #{title}\n" : ".SS #{title}\n"
    end

    # RDVisitor#apply_to_Include

    def apply_to_TextBlock(element, content)
      if RD::DescListItem === element.parent ||
          RD::ItemListItem === element.parent ||
          RD::EnumListItem === element.parent ||
          first_textblock_in_section?(element)
        return content.join
      else
        return ".PP\n" + content.join
      end
    end

    def first_textblock_in_section?(element)
      parent = element.parent
      return false unless parent.respond_to?(:children)

      index = parent.children.index(element)
      return false unless index && index > 0

      parent.children[index - 1].is_a?(Headline)
    end
    private :first_textblock_in_section?

    def apply_to_Verbatim(element)
      content = []
      element.each_line do |i|
        content.push(apply_to_String(i))
      end
      # Can we use BLOCKQUOTE such like?
      %Q[.nf\n\\&    #{content.join("\\&    ")}.fi\n]
    end

    def apply_to_ItemList(element, items)
      items.collect! do |x| x.sub(/\n\n/, "\n") end
      items = items.join(".IP\n.B\n\\(bu\n")  # "\\(bu" -> "" ?
      ".IP\n.B\n\\(bu\n" + items
    end

    def apply_to_EnumList(element, items)
      @enumcounter = 0
      items.join
    end

    def apply_to_DescList(element, items)
      items.map{ |i| i =~ /\n$/ ? i : i + "\n" }.join("")
    end

    def apply_to_MethodList(element, items)
      items.map{ |i| i =~ /\n$/ ? i : i + "\n" }.join("")
    end

    def apply_to_ItemListItem(element, content)
      content.map{ |c| c =~ /\n$/ ? c : c + "\n" }.join("")
    end

    def apply_to_EnumListItem(element, content)
      @enumcounter += 1
      %Q[.TP\n#{@enumcounter}.\n#{content.join("\n")}]
    end

    def apply_to_DescListItem(element, term, description)
      refer(element)
      if description.empty?
        ".TP\n.B\n#{term.join(" ")}"
      else
        %[.TP\n.B\n#{term.join(" ")}\n#{description.join("\n")}].chomp
      end
    end

    def apply_to_MethodListItem(element, term, description)
      term = parse_method(term)  # maybe: term -> element.term
      refer(element)
      if description.empty?
        ".TP\n.B\n#{term.join(" ")}"
      else
        %[.TP\n.B\n#{term.join(" ")}\n#{description.join("\n")}]
      end
    end

    def parse_method(method)
      klass, kind, method, args = MethodParse.analize_method(method)

      if kind == :function
        klass = kind = nil
      else
        kind = MethodParse.kind2str(kind)
      end

      case method
      when "[]"
        args.strip!
        args.sub!(/^\((.*)\)$/, '\\1')
        "#{klass}#{kind}[#{args}]"
      when "[]="
        args.strip!
        args.sub!(/^\((.*)\)$/, '\\1')
        args, val = /^(.*),([^,]*)$/.match(args)[1,2]
        args.strip!
        val.strip!

        "#{klass}#{kind}[#{args}] = #{val}"
      else
        "#{klass}#{kind}#{method}#{args}"
      end
    end
    private :parse_method

    def apply_to_StringElement(element)
      apply_to_String(element.content)
    end

    def apply_to_Emphasis(element, content)
      %Q[\\fI#{content.join}\\fP]
    end

    def apply_to_Code(element, content)
      %{\\&\\fB#{content.join.sub(/\./, '\\.')}\\fP}
    end

    def apply_to_Var(element, content)
      content.join
    end

    def apply_to_Keyboard(element, content)
      content.join
    end

    def apply_to_Index(element, content)
      tmp = []
      element.each do |i|
        tmp.push(i) if i.is_a?(String)
      end
      key = meta_char_escape(tmp.join)
      if @index.has_key?(key)
        # warning?
        ""
      else
        @index[key] = @index.size
        %{\\&\\fB#{content.join.sub(/\./, '\\.')}\\fP}
      end
    end

    def apply_to_Reference(element, content)
      case element.label
      when Reference::URL
        apply_to_RefToURL(element, content)
      when Reference::RDLabel
        if element.label.filename
          apply_to_RefToOtherFile(element, content)
        else
          apply_to_RefToElement(element, content)
        end
      end
    end

    def apply_to_RefToElement(element, content)
      content = content.join
      content.sub(/^function#/, "")
    end

    def apply_to_RefToOtherFile(element, content)
      content.join
    end

    def apply_to_RefToURL(element, content)
      content.join
    end

    def apply_to_Footnote(element, content)
      ""
    end

    def apply_to_Verb(element)
      apply_to_String(element.content)
    end

    def apply_to_String(element)
      meta_char_escape(element)
    end

    def meta_char_escape(str)
      str.gsub(/[-\\]/, '\\\\\\&').gsub(/^[.']/, '\\&') # '
    end
    private :meta_char_escape

    def guess_title
      path = if @input_filename != "-"
               @input_filename
             elsif @filename
               @filename
             end
      return "Untitled" unless path

      File.basename(path).sub(/\.[^.]+\z/, "")
    end
    private :guess_title

    def output_suffix
      @man_section || OUTPUT_SUFFIX
    end


  end # RD2MANVisitor
end # RD

$Visitor_Class = RD::RD2MANVisitor
$RD2_Sub_OptionParser = "rd/rd2man-opt"

=begin
== script info.
 RD to MAN translate library for rdfmt.rb
 $Id: rd2man-lib.rb,v 1.9 2003/08/02 15:45:49 tosh Exp $
 Copyright 2000 WATANABE Hirofumi <eban@os.rim.or.jp>
           2012 Youhei SASAKI <uwabami@gfd-dennou.org>
=end
