require 'rexml/document'
require 'rexml/element'
require 'amrita2'
require 'amrita2/testsupport'

include Amrita2
include Amrita2::Filters
include Amrita2::Runtime

context "DictionaryData" do
  setup do
    @t = Amrita2::Template.new('<span am:src="aaa" />')
  end
  
  specify "Hash" do
    result = "Amrita2"
    @t.render_with(:aaa=>'Amrita2').should_be_samexml_as(result)
  end
  specify "Struct" do
    result = "Amrita2"
    @t.render_with(Struct.new(:aaa).new('Amrita2')).should_be_samexml_as(result)
  end
  specify "Binding is a DictionaryData too" do
    aaa = 'Amrita2'
    @t.render_with(binding).should_be_samexml_as('Amrita2')
  end
  
  specify "Binding and instance variable" do
    @aaa = 'Amrita2'
    @t.render_with(binding).should_be_samexml_as('Amrita2')
  end
  
  specify "Binding checks local first" do
    aaa = 'Amrita2'
    @aaa = 'Amrita1'
    @t.render_with(binding).should_be_samexml_as('Amrita2')
  end
  
  specify "Binding and a method" do
    def self.aaa; 'Amrita2';end;
    @t.render_with(binding).should_be_samexml_as('Amrita2')
  end

  specify "Accepts key contains spaces" do 
    t = Amrita2::Template.new('<span am:src="key with space" />')
    result = "Amrita2"
    t.render_with(:"key with space"=>'Amrita2').should_be_samexml_as("Amrita2")
  end
  
  specify "Accepts key contains not-word-character" do 
    t = Amrita2::Template.new('<span am:src="Time.local(2008,1,23,9,23,12)" />')
    t.render_with(binding).should_be_samexml_as("Wed Jan 23 09:23:12 +0900 2008")
    t = Amrita2::Template.new('<span am:src="Amrita2::Version::STRING" />')
    t.render_with(binding).should_be_samexml_as(Amrita2::Version::STRING)
  end
end

context "NullObject" do
  specify "nil for Scalar Context" do
    t = Amrita2::Template.new('<div am:src="aaa" />')
    t.test_with(nil) do|r|
      r.should_be_samexml_as "<div />"
    end
    t.test_with(:aaa=>nil) do|r|
      r.should_be_samexml_as "<div />"
    end
  end
  
  specify "false for Scalar Context" do
    t = Amrita2::Template.new('<div am:src="aaa" />')
    proc { t.render_with(false)}.should raise_error
    proc { t.render_with(:aaa=>false)}.should raise_error
  end
  
  specify "nil for Dictionary Context" do
    t = Amrita2::Template.new('<div class="outer" am:src="aaa"><div class="inner" am:src="bbb" /></div>')
    t.test_with(nil) do|r|
      r.should_be_samexml_as '<div class = "outer"><div class = "inner"></div></div>'
    end
    t.test_with(:aaa=>nil) do|r|
      r.should_be_samexml_as '<div class = "outer"><div class = "inner"></div></div>'
    end
    proc { t.render_with(false)}.should raise_error
    proc { t.render_with(:aaa=>false)}.should raise_error
  end
  
  specify "AcceptData[nil]" do
    t = Amrita2::Template.new('<div am:src="aaa|AcceptData[nil]" />')
    t.test_with(:aaa=>nil) do|r|
      r.should == ''
    end
  end
  
  specify "AcceptData[nil]" do
    t = Amrita2::Template.new('<div class="outer" am:src="aaa|AcceptData[nil]"><div class="inner" am:src="bbb" /></div>')
    data = {
      :aaa => [
               { :bbb=>'1'},
               nil,
               { :bbb=>'2'},
              ]
    }
    t.test_with(data) do|r|
      r.should == '<div class = "outer"><div class = "inner">1</div></div><div class = "outer"><div class = "inner">2</div></div>'
    end
  end
end

context "True" do
  specify "don't accept true for default" do
    t = Amrita2::Template.new('<div am:src="aaa" />')
    proc { t.render_with(true) }.should raise_error
  end
  
  specify "true for Scalar Context" do
    t = Amrita2::Template.new('<div am:src="aaa|AcceptData[true]" />')
    t.test_with(nil) do|r|
      r.should_be_samexml_as "<div />"
    end
  end
  
  specify "true for Dictionary Context" do
    t = Amrita2::Template.new('<div class="outer" am:src="aaa|AcceptData[true]"><div class="inner" am:src="bbb" /></div>')
    t.test_with(:aaa=>true) do|r|
      r.should_be_samexml_as '<div class = "outer"><div class = "inner"></div></div>'
    end
    t.test_with(:aaa=>{ :bbb=>1 }) do|r|
      r.should_be_samexml_as '<div class = "outer"><div class = "inner">1</div></div>'
    end
    t.test_with(:aaa=>nil) do|r|
      r.should_be_samexml_as '<div class = "outer"><div class = "inner"></div></div>'
    end
    proc { t.render_with(:aaa=>false)}.should raise_error
  end
end

# Hook
context "HookObject" do
  specify "use stream" do
    #t = Amrita2::Template.new('<div am:src="aaa|AcceptData[:hook]" />')
    t = Amrita2::Template.new('<<div :aaa|AcceptData[:hook]>>')

    hook = Amrita2::Core::Hook.new do
      stream << "hook can write to stream direct"
      render_me_with("hook can render self")
      stream << "and add anything after that"
    end
    
    t.test_with(:aaa=>hook) do|r|
      r.should_be_samexml_as "hook can write to stream direct<div>hook can render self</div>and add anything after that"
    end
  end
  
  specify "control" do
    t = Amrita2::Template.new('<span am:src="aaa|AcceptData[:hook]" />')

    hook = Amrita2::Core::Hook.new do
      stream << "("
      [7,8,9].each do |n|
        render_me_with(n)
      end
      stream << ")"
    end
    
    t.test_with(:aaa=>hook) do|r|
      r.should_be_samexml_as "(789)"
    end
  end
  
  specify "hook in erb" do
    t = Amrita2::Template.new <<-END
    <ul>
    <%
      hook_in_erb = Amrita2::Core::Hook.new do
        [3, 4, 5].each do |n|
          render_me_with(n)
        end
      end
    %>
    <li am:src="hook_in_erb|AcceptData[:hook]" />
    </ul>
    END

    t.test_with(binding) do |r|
      r.should_be_samexml_as "<ul><li>3</li><li>4</li><li>5</li></ul>"
    end
  end
  
  specify "render child" do
    t = Amrita2::Template.new <<-END
    <%
      odd_even = Amrita2::Core::Hook.new do
        list.each_with_index do |item, n|
          if (item % 2) == 0
            render_child(:even, :item => item )
          else
            render_child(:odd,  :item => item )
          end
          stream << " and " if n < list.size - 1
        end
      end
    %>
    <span am:src="odd_even|AcceptData[:hook]">
       <span am:src="odd"><span am:src="item" /> is odd</span>
       <span am:src="even"><span am:src="item" /> is even</span>
    </span>
    END
    
    list=[4, 1, 7, 8]
    t.test_with(binding) do |r|
      r.strip.should == "4 is even and 1 is odd and 7 is odd and 8 is even"
    end
    
    list=[1,2,3]
    t.test_with(binding) do |r|
      r.strip.should_be_samexml_as "1 is odd and 2 is even and 3 is odd"
    end
    
  end
  
  specify "use element as string" do
    t = Amrita2::Template.new('<div am:src="aaa|AcceptData[:hook]"><a href="http://amrita2.rubyforge.org">Amrita2</a></div>')

    hook = Amrita2::Core::Hook.new do
      stream << "[[#{element_s}]]"
    end
    
    t.test_with(:aaa=>hook) do|r|
      r.should_be_samexml_as "[[<div><a href='http://amrita2.rubyforge.org'>Amrita2</a></div>]]"
    end
  end
  
  specify "use element " do
    t = Amrita2::Template.new('<div am:src="aaa|AcceptData[:hook]"><a href="http://amrita2.rubyforge.org">Amrita2</a></div>')

    hook = Amrita2::Core::Hook.new do
      stream << "[[#{element_s }]]"
    end
    
    t.test_with(:aaa=>hook) do|r|
      r.should_be_samexml_as "[[<div><a href='http://amrita2.rubyforge.org'>Amrita2</a></div>]]"
    end
  end
end