#
#   version 1.00  2008.01.24  aike
#
#   setMode(mode) mode:"raw"/"compact"
#   
#   generate HTML with JavaScript library
#     generate(source)
#
#   generate JavaScript library only (for CGI)
#     getJSlibrary(drawflag) flag: true/false
#     getTreeData(source)
#

# ruby_parser needs HOME
if not ENV.has_key?('HOME')
	ENV['HOME'] = ''
end

require 'ruby_parser'
require 'cgi'

class TrettyPrint
  def initialize()
    @mode = 0
    @filename = ""
    @parser = RubyParser.new
    @buf = ""
  end
  attr_accessor :filename

  def setMode(mode)
    if mode == "raw"
      @mode = 0
    elsif mode == "compact"
      @mode = 1
    else
      put "mode error"
    end
  end

  def generate(text)
    s =
      getHTMLheader +
      getJSlibrary(true) +
      getTreeData(text) +
      getHTMLbody
    return s
  end

  def put(s)
    @buf += s
  end

  def putNode(sexp)
    car = getCAR(sexp)
    cdr = getCDR(sexp)

    if car.is_a? Sexp
      put "td();\n"
      putNode(car)
      put "tu();\n"
    else
      putAtom(car, getCAR(cdr))
    end
    if (@mode == 1) and (has_nodelabel(car))
      cdr = getCDR(cdr)
    end
    if (not cdr.nil?) and (not cdr.empty?)
      if (getCAR(cdr).is_a? Sexp)
        putNode(cdr)
      else
        put "td();\n"
        putNode(cdr)
        put "tu();\n"
      end
    end
  end

  def has_nodelabel(item)
    if has_nodelabel_1(item) or has_nodelabel_2(item)
      return true
    else
      return false
    end
  end

  def has_nodelabel_1(item)
    if not item.is_a? Symbol
      return false
    end
    return [:const, :str, :dstr, :evstr, 
            :lvar, :dvar, :gvar, :ivar, :fcall, :vcall, :defn, :class, 
            :lasgn, :iasgn, :gasgn, :cvdecl ].include?(item)
  end

  def has_nodelabel_2(item)
    if not item.is_a? Symbol
      return false
    end
    return [:lit].include?(item)
  end


  def getCAR(sexp)
    if sexp.is_a? Sexp
      return sexp[0]
    else
      return nil
    end
  end

  def getCDR(sexp)
    if sexp.is_a? Sexp
      return sexp[1...sexp.length]
    else
      return nil
    end
  end

  def putAtom(item, nextitem)
    if item.nil?
      putItem("(nil)")
            
    elsif item.is_a? Symbol
      s = "[" + item.to_s + "]"
      if @mode == 1	# compact mode
        if has_nodelabel_1(item)
          s = s + ' "' + nextitem.to_s + '"'
        elsif  has_nodelabel_2(item)
          s = s + " " + nextitem.to_s + ""
        end
      end
      putItem(s)
      
    else
      putItem(item.to_s)
      
    end
  end

  def putItem(item)
    s = item
    s = CGI::escapeHTML(s)
    s = s.gsub("\\", "&#x5C;&#x5C;")
    s = s.gsub("\t", "&#x5C;t")
    s = s.gsub("\a", "&#x5C;a")
    s = s.gsub("\r", "&#x5C;r")
    s = s.gsub("\n", "&#x5C;n")
    s = s.gsub("'",  "&#x27;")

    put "ta('" + s + "');\n"
  end

  def getHTMLheader
    @buf = ""
    put "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"
    put "<html>\n"
    put "<head>\n"
    put "<meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n"
    put "<title>" + @filename + "</title>\n"
    return @buf
  end

  def getJSlibrary(flag)
    @buf = ""
    put "<link rel=\"stylesheet\" type=\"text/css\" href=\"./yui/treeview.css\">\n"
    put "<script type=\"text/javascript\" src=\"./yui/yahoo-min.js\" ></script>\n"
    put "<script type=\"text/javascript\" src=\"./yui/event-min.js\" ></script>\n"
    put "<script type=\"text/javascript\" src=\"./yui/treeview-min.js\" ></script>\n"
    put "<script type=\"text/javascript\">\n"
    if not flag
      put "function drawTree() {}\n"
    else
      put "var treeTail;\n"
      put "var treeParent;\n"
      put "var treeStack = [];\n"
      put "\n"
      put "function drawTree() {\n"
      put "	var tree = new YAHOO.widget.TreeView(\"Tree\");\n"
      put "	var root = tree.getRoot();\n"
      put "	treeParent = root;\n"
      put "	treeDef();\n"
      put "	tree.draw();\n"
      put "}\n"
      put "\n"
      put "function ta(s) { // add node\n"
      put "	var n = new YAHOO.widget.TextNode(s, treeParent, false);\n"
      put "	treeTail = n;\n"
      put "}\n"
      put "\n"
      put "function td() { // down node\n"
      put "	treeStack.push(treeParent);\n"
      put "	treeParent = treeTail;\n"
      put "}\n"
      put "\n"
      put "function tu() { // up node\n"
      put "	treeTail = treeParent;\n"
      put "	treeParent = treeStack.pop();\n"
      put "}\n"
      put "\n"
    end
    put "</script>\n"
    return @buf
  end

  def getTreeData(text)
    sexp = @parser.parse(text)
    @buf = ""
    put "<script type=\"text/javascript\">\n"
    put "function treeDef() {\n"
    putNode(sexp)
    put "}\n"
    put "</script>\n"
    return @buf
  end

  def getHTMLbody
    @buf = ""
    put "<body onload=\"drawTree();\">\n"
    put "<h1>" + @filename + "</h1>\n"
    put "<div id=\"Tree\"></div>\n"
    put "</body>\n"
    put "</html>\n"
    return @buf
  end
end

