class Temple::HTML::Fast

def attr_easily_compilable?(exp)

def attr_easily_compilable?(exp)
  exp[1] == :basicattr and
  exp[2][0] == :static
end

def compile(exp)

def compile(exp)
  case exp[0]
  when :multi, :capture
    send("on_#{exp[0]}", *exp[1..-1])
  when :html
    send("on_#{exp[1]}", *exp[2..-1])
  else
    exp
  end
end

def html4?

def html4?
  @options[:format] == :html4
end

def html5?

def html5?
  @options[:format] == :html5
end

def html?

def html?
  html5? or html4?
end

def initialize(options = {})

def initialize(options = {})
  @options = DEFAULT_OPTIONS.merge(options)
  
  unless [:xhtml, :html4, :html5].include?(@options[:format])
    raise "Invalid format #{@options[:format].inspect}"
  end
  
end

def merge_basicattrs(attrs)

def merge_basicattrs(attrs)
  result = []
  position = {}
  
  attrs.each do |(html, type, (name_type, name), value)|
    if pos = position[name]
      case name
      when 'class', 'id'
        value = [:multi,
          result[pos].last,  # previous value
          [:static, (name == 'class' ? ' ' : '_')], # delimiter
          value]             # new value
      end
      
      result[pos] = [name, value]
    else
      position[name] = result.size
      result << [name, value]
    end
  end
  
  final = []
  result.each_with_index do |(name, value), index|
    final << [:html, :basicattr, [:static, name], value]
  end
  final
end

def on_attrs(*exp)

def on_attrs(*exp)
  if exp.all? { |e| attr_easily_compilable?(e) }
    [:multi, *merge_basicattrs(exp).map { |e| compile(e) }]
  else
    raise "[:html, :attrs] currently only support basicattrs"
  end
end

def on_basicattr(name, value)

def on_basicattr(name, value)
  [:multi,
    [:static, " "],
    name,
    [:static, "="],
    [:static, @options[:attr_wrapper]],
    value,
    [:static, @options[:attr_wrapper]]]
end

def on_capture(name, exp)

def on_capture(name, exp)
  [:capture, name, compile(exp)]
end

def on_comment(content)

def on_comment(content)
  [:multi,
    [:static, "<!--"],
    compile(content),
    [:static, "-->"]]
end

def on_doctype(type)

def on_doctype(type)
  trailing_newlines = type[/(\A|[^\r])(\n+)\Z/, 2].to_s
  
  text = type.to_s.downcase.strip
  if text.index("xml") == 0
    if html?
      return [:multi].concat([[:newline]] * trailing_newlines.size)
    end
    
    wrapper = @options[:attr_wrapper]
    str = "<?xml version=#{wrapper}1.0#{wrapper} encoding=#{wrapper}#{text.split(' ')[1] || "utf-8"}#{wrapper} ?>"
  end
  
  str = "<!DOCTYPE html>" if html5?
  
  str ||= if xhtml?
    case text
    when /^1\.1/;     '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
    when /^5/;        '<!DOCTYPE html>'
    when "strict";    '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
    when "frameset";  '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">'
    when "mobile";    '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'
    when "basic";     '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">'
    else              '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
    end
  elsif html4?
    case text
      when "strict";    '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">'
      when "frameset";  '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">'
      else              '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">'
    end
  end
  
  str << trailing_newlines
  [:static, str]
end

def on_multi(*exp)

def on_multi(*exp)
  [:multi, *exp.map { |e| compile(e) }]
end

def on_tag(name, attrs, content)

def on_tag(name, attrs, content)
  ac = @options[:autoclose].include?(name)
  result = [:multi]
  result << [:static, "<#{name}"]
  result << compile(attrs)
  result << [:static, " /"] if ac && xhtml?
  result << [:static, ">"]
  result << compile(content)
  result << [:static, "</#{name}>"] if !ac
  result
end

def xhtml?

def xhtml?
  @options[:format] == :xhtml
end