# Copyright (C) 2003-2005 Kouichirou Eto, All rights reserved.

$LOAD_PATH.unshift("../../compat") unless $LOAD_PATH.include?("../../compat")
require "htree"
$LOAD_PATH << "../../lib" unless $LOAD_PATH.include?("../../lib")
require "qwik/htree-template"

module HTree
  module Container
    def split_name_num(name)
      name = name.sub(%r|(^//)|, "")

      if /^(\w+)\[(\d+)\]$/ =~ name
	return [$1, $2.to_i]
      end
      [name, 1]
    end

    def find_nth_element(num=1, *names)
      i = 1
      traverse_element(*names) {|e|
	return e if i == num
	i += 1
      }
      nil
    end

    def get_tag(tag)
      tag, num = split_name_num(tag)
      names = html_tags(tag)
      find_nth_element(num, *names)
    end

    def each_in_class(klass)
      klass, knum = split_name_num(klass)
      k = 1
      klass_path = nil
      make_loc.traverse_element {|l|
	if klass_path.nil?
	  if l.to_node.get_attr("class") == klass
	    if k == knum
	      klass_path = l.path
	    else
	      k += 1
	    end
	  end
	elsif l.path.include?(klass_path)
	  yield l
	end
      }
    end

    def get_class_tag(klass, tag)
      tag, num = split_name_num(tag)
      i = 1
      each_in_class(klass) {|l|
	ar = l.path.split("/")
	e = ar.last
	if e == tag
	  return l.to_node if i == num
	  i += 1
	end
      }
      nil
    end

    def each_class(klass) # obsolete
      each_has_attr("class", klass, &b)
    end

    def get_class(klass) # obsolete
      get_has_attr("class", klass)
    end

    def each_has_attr(attr, value)
      make_loc.traverse_element {|l|
	if l.to_node.get_attr(attr) == value
	  yield(l.to_node)
	end
      }
    end

    def get_has_attr(attr, value)
      each_has_attr(attr, value) {|l|
	return l.to_node
      }
      nil
    end

    def get_a_path(path)
      if /\A(.*)\[(.+)\]\z/ =~ path
	tag = $1
	select = $2
	if /\A@([a-z]+)='([a-z]+)'\z/ =~ select
	  attr = $1
	  value = $2
#	  if attr == "class"
#	    return get_class(cont)
#	  end
	  return get_has_attr(attr, value)
	end
      end
      return get_tag(path)
    end

    def get_path(path)
      xml = self
      path.split("/").each {|pa|
	if 0 < pa.length
	  return nil if xml.nil?
	  xml = xml.get_a_path(pa)
	end
      }
      xml
    end

  end

  class Elem
    def attributes_str
      hash_to_str(attributes)
    end

    def hash_to_str(src)
      h = {}
      src.each {|k, v| h[k.to_s] = v.to_s }
      h
    end
  end
end

if $0 == __FILE__
  require "test/unit"
  require "qwik/htree-format-xml"
  $debug = true
end

if $debug
  class TC_QwikHTreeGet < Test::Unit::TestCase
    def assert(e, s)
      return "" if s.nil?
      assert_equal(e, s.format_xml)
    end

    def test_all
      # test_get_tag
      e = HTree::Elem.new("e")

      # test_split_name_num
      assert_equal(["sidebar", 1], e.split_name_num("sidebar"))
      assert_equal(["sidebar", 1], e.split_name_num("sidebar[1]"))
      assert_equal(["sidebar", 2], e.split_name_num("sidebar[2]"))

      # test_get_tag
      h = HTree("<a><b><c>")
      assert("<c/>", h.get_tag("c"))
      assert("<b><c/></b>", h.get_tag("b"))

      # test_each_in_class
      h = HTree("<p class='a'><ta/></p><p class='b'><tb/></p><p class='b'><tb2/></p>")
      h.each_in_class("a") {|l|
	assert_equal("doc()/p[1]/ta", l.path)
	assert("<ta/>", l.to_node)
      }
      h.each_in_class("b") {|l|
	assert_equal("doc()/p[2]/tb", l.path)
	assert("<tb/>", l.to_node)
      }
      h.each_in_class("b[2]") {|l|
	assert_equal("doc()/p[3]/tb2", l.path)
	assert("<tb2/>", l.to_node)
      }

      assert("<ta/>", h.get_class_tag("a", "ta"))
      assert("<tb/>", h.get_class_tag("b", "tb"))
      assert("<tb2/>", h.get_class_tag("b[2]", "tb2"))

      str = <<"EOS"    
<html><div class="main">
<div class="day"><h2>bh2</h2></div>
<div class="sidebar"><h2>sh2</h2></div>
</div></html>
EOS
      h = HTree(str)
      assert("<html><div class=\"main\">\n<div class=\"day\"><h2>bh2</h2></div>\n<div class=\"sidebar\"><h2>sh2</h2></div>\n</div></html>\n", h)
      assert("<h2>bh2</h2>", h.get_tag("h2"))
      assert("<h2>sh2</h2>", h.get_tag("h2[2]"))
      assert("<h2>bh2</h2>", h.get_class_tag("day", "h2"))
      assert("<h2>sh2</h2>", h.get_class_tag("sidebar", "h2"))

      # test_get_tag2
      h = HTree("<a><b>tb</b><b>tb2</b><c>")
      assert("<b>tb</b>", h.get_tag("b"))
      assert_equal(nil, h.get_tag("nosuchtag"))
      assert("<b>tb</b>", h.get_tag("b[1]"))
      assert("<b>tb2</b>", h.get_tag("b[2]"))
      assert("<b>tb</b>", h.get_tag("//b"))

      # test_xpath
      str = <<"EOS"
<html><div class="main">
<div class="day"><h2>bh2</h2></div>
<div class="sidebar"><h2>sh2<b>a</b>sh2a</h2></div>
</div></html>
EOS
      h = HTree(str)
      #assert("<html><div class=\"main\">\n<div class=\"day\"><h2>bh2</h2></div>\n<div class=\"sidebar\"><h2>sh2</h2></div>\n</div></html>\n", h)
      #assert("<h2>sh2</h2>", h.get_class_tag("sidebar", "h2"))
      #assert("<h2>sh2<b>a</b>sh2a</h2>", h.get_class("sidebar"))
      assert("<div class=\"sidebar\"><h2>sh2<b>a</b>sh2a</h2></div>",
	     h.get_class("sidebar"))
      assert_instance_of(HTree::Elem, h.get_class("sidebar"))
      assert("<b>a</b>", h.get_class("sidebar").get_tag("b"))
      assert("<div class=\"sidebar\"><h2>sh2<b>a</b>sh2a</h2></div>",
	     h.get_a_path("div[@class='sidebar']"))
      assert("<b>a</b>", h.get_a_path("div[@class='sidebar']").get_a_path("b"))
      assert("<div class=\"sidebar\"><h2>sh2<b>a</b>sh2a</h2></div>",
	     h.get_path("//div[@class='sidebar']"))
      assert("<b>a</b>", h.get_path("//div[@class='sidebar']/b"))

      str = <<"EOS"
<a href="t1" alt="t2">t3</a>
EOS
      h = HTree(str)
      assert_instance_of(HTree::Doc, h)
      e = h.get_tag("a")
      assert_instance_of(HTree::Elem, e)
      assert("<a href=\"t1\" alt=\"t2\">t3</a>", e)
      #assert_equal({href=>{text "t1"}, alt=>{text "t2"}}, e.attributes)
      assert_equal({"href"=>"t1", "alt"=>"t2"}, e.attributes_str)

      # test_xpath_attr
      str = <<"EOS"
<html><div class="main">
<div id="menu"><h2>menuh2</h2></div>
</div></html>
EOS
      h = HTree(str)
      assert("<div id=\"menu\"><h2>menuh2</h2></div>",
	     h.get_has_attr("id", "menu"))
      assert_instance_of(HTree::Elem, h.get_has_attr("id", "menu"))
      assert("<div id=\"menu\"><h2>menuh2</h2></div>",
	     h.get_path("//div[@id='menu']"))
    end
  end
end
