require 'rexml/document'
require 'amrita2'
require 'amrita2/macro'
require 'amrita2/testsupport'

include Amrita2::Runtime

context "Amrita2 has Macro" do
  class Hello < Amrita2::Macro::Base
    include Amrita2
    #TemplateText = <<-END
    #    <span macro:src="greeting" />, macro world!
    #END
    TemplateText = <<-END
        <<:greeting>>, macro world!
    END
  end

  specify " " do
    text = <<-END
    <span><hello greeting="Hello" /> <span am:src="msg" /></span>
    END
    t = Amrita2::Template.new(text)
    t.add_macro(Hello.new)
    t.test_with(:msg => "Enjoy it!") do |result|
      result.should_be_samexml_as "Hello, macro world! Enjoy it!"
    end
  end
end


context "Macro can contain dynamic element" do
  class Hello2 < Amrita2::Macro::Base
    include Amrita2

    TemplateText = <<-END.gsub(/\s+/m, ' ')
      <span macro:src="greeting" />, macro world!
      <span target_src="msg" />
    END
  end

  specify " " do
    text = <<-END
    <%(BeforeCompile) use_macro(Hello2) %>
    <span><hello2 greeting='Hello'/> </span>
    END
    t = Amrita2::Template.new(text)
    t.add_macro(Hello2.new)
    
    t.test_with(:msg => "Enjoy it!") do |result|
      result.should_be_samexml_as "Hello, macro world! Enjoy it!  \n"
    end
  end
end

context "two macros in one template" do
  class Hello3 < Amrita2::Macro::Base
    include Amrita2

    TemplateText = <<-END
      <span macro:src="hello">
        <span macro:src="greeting" />, macro world!
        <span macro:filter="Attr[:target_src=>:amrita_id]" />
      </span>
    END
    Option = {
      :tag => :hello,
      :use_tag => true
    }
  end

  specify " " do
    text = <<-END
    <ul>
      <li><hello greeting="Good morning" amrita_id="msg1"/></li>
      <li><hello greeting="Hello"        amrita_id="msg2"/></li>
    </ul>
    END
    t = Amrita2::Template.new(text)
    t.add_macro(Hello3.new)
    t.test_with(:msg1 => "Enjoy it!", :msg2=> "It's great, isn't it?") do |result|
      result.should_be_samexml_as <<-END
      <ul>
        <li>Good morning, macro world! Enjoy it!</li>
        <li>Hello, macro world! It's great, isn't it?</li>
      </ul>
      END
    end #"
  end
end

context "Macro can expand child elements" do
  class Hello4 < Amrita2::Macro::Base
    include Amrita2
    TemplateText = <<-END
      <p macro:src="hello">
         <span macro:src="msg" />, macro world! 
         <span macro:src="contents" />
      </p>
    END
    
    Option = {
      :tag=>:hello,
      :use_tag => true,
      :use_contents=>:contents
    }

  end

  specify " " do
    text = <<-END
    <ul>
      <li><hello msg="Good morning"><span am:src="msg1" /><em am:src="msg2" /></hello></li>
      <li><hello msg="Hello"       ><strong am:src="msg3" /></hello></li>
    </ul>
    END
    t = Amrita2::Template.new(text)
    t.add_macro(Hello4.new)
    t.test_with(:msg1 => "Try it.", :msg2=>"Enjoy it!", :msg3=> "It's great, isn't it?") do |result|
      result.should_be_samexml_as <<-END
      <ul>
        <li><p>Good morning, macro world!  Try it.<em>Enjoy it!</em> </p></li>
        <li><p>Hello, macro world! <strong>It's great, isn't it?</strong> </p></li>
      </ul>
      END
    end # "
  end
end

context "Amazon Link Macro" do
  class Amazon < Amrita2::Macro::Base
    include Amrita2
    ElementName = "book"
    TemplateText = <<-END
      <span>
        <a macro:src = "book|NVar[:isbn, :content]"
           target_src = "book|NVar[:$1, :$2]"
           href="http://www.amazon.co.jp/exec/obidos/ASIN/$$1/">
          $$2
        </a>
      </span>
    END
    Option = {
      :tag=>:book,
      :use_tag => true,
      :use_contents=>true
    }
  end      

  specify " " do
    text = <<-END
    <div>
       <book isbn="isbn" content="title" />
    </div>
    END
#    
#   after macro expansion
#   <div><a href='http://www.amazon.co.jp/exec/obidos/ASIN/$1/'
#           am:src='book|NVar[:isbn_no, :title]'>$2</a></div>
#   
    t = Amrita2::Template.new(text) do |e, name, filters|
      filters << Amrita2::Filters::MacroFilter[Amazon]
    end
    
    data = {
      :book=>{
        :isbn=>'4798013951',
        :title=>'Ruby on Rails for dummies'
      }
    }
    #t.set_trace(STDOUT)
    t.test_with(data) do |result|
      result.should_be_samexml_as <<-END
        <div>
          <a href="http://www.amazon.co.jp/exec/obidos/ASIN/4798013951/">Ruby on Rails for dummies</a>
        </div>
      END
    end
  end
end

context "Macro with erb" do
  class Formula < Amrita2::Macro::Base
    include Amrita2
    TemplateText = <<-END
      <span macro:src = "formula">
        <span macro:skipif="$_[:op] != '+'">
          <span macro:filter="NVar[:name, :term1, :term2]"
                target_src="$1">
             <%%= $_[:$2] %%> + <%%= $_[:$3] %%> = <%%= $_[:$2].to_i + $_[:$3].to_i %%>
          </span>
        </span>
        <span macro:skipif="$_[:op] != '-'">
          <span macro:filter="NVar[:name, :term1, :term2]"
                target_src="$1">
             <%%= $_[:$2] %%> - <%%= $_[:$3] %%> = <%%= $_[:$2].to_i - $_[:$3].to_i %%>
          </span>
        </span>
      </span>
    END

    Option = {
      :tag => :formula,
      :use_tag => true
    }
  end

  specify " " do
    text = <<-END
      <formula name="plus" op="+" term1="term1" term2="term2"/>/
      <formula name="minus" op="-" term1="num1" term2="num2"/>
    END

    t = Amrita2::Template.new(text,:inline_ruby) do |e, name, filters|
      filters << Amrita2::Filters::MacroFilter[Formula]
    end
    
#    
#   after macro expansion
#    <span target_src='plus'>
#      <%%= $_[:term1] %> + <%%= $_[:term2] %> = <%%= $_[:term1].to_i + $_[:term2].to_i %>
#    </span>
#    <span target_src='minus'>
#      <%%= $_[:num1] %> - <%%= $_[:num2] %> = <%%= $_[:num1].to_i - $_[:num2].to_i %>
#    </span>
#   

    data = {
      :plus => { 
        :term1 => 10,
        :term2 => 20,
      },
      :minus => { 
        :num1 => 30,
        :num2 => 5
      }
    }
    #t.set_trace(STDOUT)
    t.test_with(data) do |result|
      r = result.gsub(/[\s\n]*/, "")
      r.should == '10+20=30/30-5=25'
    end
  end
end

context "Macro producing erb" do
  class ErbTest < Amrita2::Macro::Base
    include Amrita2
    TemplateText = <<-'END'
      <div>
        <% var_defined_in_erb_of_macro = value_of_macro_ref.to_i * 10 %>
        <img macro:filter="NVar[:host, :var_defined_in_erb_of_macro]" src="http://$1/img$2.png" />

        <%% var_defined_in_erb_of_template = value_of_model.to_i * 10 %>
        <img macro:filter="NVar[:host]"
           target_filter="NVar[:var_defined_in_erb_of_template]"
           src="http://$1.com/img$$1.png" />
  
        <%% var_generated_with_macro_and_model_value = "#{ value_of_model + <%= value_of_macro_ref %>}" %>
        <img macro:filter="NVar[:host]"
           target_filter="NVar[:var_generated_with_macro_and_model_value]"
           src="http://$1/img$$1.png" />
      </div>
    END

    Option = {
      :tag => :erbtest
    }
    
    def preprocess_element(mt, element)
      host = element.attributes["host"]
      value_of_macro_ref = element.attributes["value_of_macro_ref"]
      mt.render_with(binding)
    end

  end

  specify " " do
    text = <<-END
      <erbtest host="some.host.com" value_of_macro_ref="10" />
    END

    #<div>
    #  <img src='http://some.host.com/img100.png'/>
    #
    #  <![CDATA[<% var_defined_in_erb_of_template = value_of_model.to_i * 10 %>]]>
    #  <img am:filter='NVar[:var_defined_in_erb_of_template]' src='http://some.host.com.com/img$1.png'/>
    #
    #  <![CDATA[<% var_generated_with_macro_and_model_value = "#{  value_of_model + 10}" %>]]>
    #  <img am:filter='NVar[:var_generated_with_macro_and_model_value]' src='http://some.host.com/img$1.png'/>
    #
    #</div>

    t = Amrita2::Template.new(text,:inline_ruby) do |e, name, filters|
      filters << Amrita2::Filters::MacroFilter[ErbTest]
    end

    value_of_model = 5
    #t.set_trace(STDOUT)
    t.test_with(binding) do |result|
      result.should_be_samexml_as <<-END
        <div>
          <img src = "http://some.host.com/img100.png" />
          <img src='http://some.host.com.com/img50.png'/>
          <img src='http://some.host.com/img15.png'/>
        </div>
      END
    end
  end
end

context "Table" do
  class Table < Amrita2::Macro::Base
    include Amrita2
    TemplateText = <<-END
      <table>
        <tr><th macro:src='header'/></tr>
        <tr target_src='detail'>
          <td macro:src="column|Attr[:target_src=>'column_id']">
            <span macro:src="contents" />
          </td>
        </tr>
      </table>
    END

    Option = {
      :tag => "m:table"
    }

    def preprocess_element(mt, element)
      cols = element.search("column").collect do |e|
        e.as_amrita_dictionary(:use_contents=>:contents)
      end

      headers = cols.collect do |d|
        d[:header]
      end

      data = {
        :header => headers,
        :column => cols,
      }
      
      #p data
      #mt.set_trace(STDOUT)
      mt.render_with(data)
    end
  end

  specify " " do
    text = <<-END
      <m:table>
        <column header='AAA' column_id='aaa' />
        <column header='BBB' column_id='bbb'>
          <a am:filter="NVar[:url, :title]" href="$1">$2</a>
        </column>
      </m:table>
    END
    t = Amrita2::Template.new(text)
    t.add_macro(Table.new)

    #<table>
    #  <tr><th>AAA</th><th>BBB</th></tr>
    #    <tr am:src='detail'>
    #      <td am:src='aaa'>
    #      </td>
    #      <td am:src='bbb'>
    #        <a am:filter='NVar[:url, :title]' href='$1'>$2</a>
    #      </td>
    #  </tr>
    #</table>
    
    data = {
      :detail => [
        { :aaa=>'a1', :bbb=>{ :url=>'url1', :title=>'b1'} },
        { :aaa=>'a2', :bbb=>{ :url=>'url2', :title=>'b2'} },
        { :aaa=>'a3', :bbb=>{ :url=>'url3', :title=>'b3'} },
      ]
    }
    t.test_with(data) do |result|
      result.should_be_samexml_as <<-END
      <table>
        <tr><th>AAA</th><th>BBB</th></tr>
        <tr>
          <td>a1</td><td>
            <a href='url1'>b1</a>
          </td>
        </tr><tr>
          <td>a2</td><td>
            <a href='url2'>b2</a>
          </td>
        </tr><tr>
          <td>a3</td><td>
            <a href='url3'>b3</a>
          </td>
        </tr>
      </table>
      END
    end
  end
end


context "Table and Amazon" do
  specify " " do
    text = <<-END
      <m:table>
        <column header='No' column_id='no' />
        <column header='Title'>
          <book isbn="isbn" content="title" />
        </column>
      </m:table>
    END
    t = Amrita2::Template.new(text)
    t.add_macro(Table.new)
    t.add_macro(Amazon.new)

    #<table>
    #  <tr><th>No</th><th>Title</th></tr>
    #  <tr am:src='detail'>
    #    <td am:src='no'/>
    #    <td>
    #      <a href='http://www.amazon.co.jp/exec/obidos/ASIN/$1/' am:src='book|NVar[:isbn, :title]'>$2</a>
    #    </td>
    #  </tr>
    #</table>

    data = {
      :detail => [
        { :no=>'1', :book=>{ :isbn=>'isbn1', :title=>'b1'} },
        { :no=>'2', :book=>{ :isbn=>'isbn2', :title=>'b2'} },
        { :no=>'3', :book=>{ :isbn=>'isbn3', :title=>'b3'} },
      ]
    }
    t.test_with(data) do |result|
      #IO.popen("w3m -T text/html", "w") { |f| f.puts result}
      result.should_be_samexml_as <<-END
      <table>
        <tr><th>No</th><th>Title</th></tr>
        <tr>
          <td>1</td>
          <td>
            <a href='http://www.amazon.co.jp/exec/obidos/ASIN/isbn1/'>b1</a>
          </td>
        </tr>
        <tr>
          <td>2</td>
          <td>
            <a href='http://www.amazon.co.jp/exec/obidos/ASIN/isbn2/'>b2</a>
          </td>
        </tr>
        <tr>
          <td>3</td>
          <td>
            <a href='http://www.amazon.co.jp/exec/obidos/ASIN/isbn3/'>b3</a>
          </td>
        </tr>
      </table>
      END
    end
  end
end

context "Two columns" do
  # taken from LoginEngine
  class TwoColumn < Amrita2::Macro::Base
    include Amrita2
    ElementName = "twocolumn"
    TemplateText = <<-END
      <table target_src="table|AcceptData[true]">
        <span macro:src="rows" >
          <tr macro:filter="Attr[:class=>:tr_class]">
            <td macro:filter="Attr[:class=>:prompt_class]"><label macro:src="title" /></td>
            <td macro:filter="Attr[:class=>:value_class, :body=>:contents]" />
          </tr><br />
        </span>
      </table>
    END

    Option = {
      :tag => :twocolumn
    }
    
    def preprocess_element(mt, element)
      table = element.as_amrita_dictionary
      rows = element.search("row").collect do |c|
        h = c.as_amrita_dictionary(:use_contents=>:contents)
        h[:tr_class] = table[:tr_class] || "two_columns"
        h[:prompt_class] = table[:prompt_class] || "prompt"
        h[:value_class] = table[:value_class] || "value"
        h
      end

      mt.render_with(binding)
    end
  end

  specify " " do
    text = <<-END
    <twocolumn tr_class="two_columns" prompt_class="prompt" value_class="value">
      <row title="Login ID:"><input name="user[login]" size="30" type="text" /></row>
      <row title="Password:"><input name="user[password]" size="30" type="password" value="" /></row>
    </twocolumn>
    END
    
    text = <<-END
    <twocolumn>
      <row title="Login ID:"><input name="user[login]" size="30" type="text" /></row>
      <row title="Password:"><input name="user[password]" size="30" type="password" value="" /></row>
    </twocolumn>
    END
    
    t = Amrita2::Template.new(text)
    t.add_macro(TwoColumn)
    t.test_with(:table=>true) do |result|
      result.should_be_samexml_as <<-END
      <table>
        <tr class="two_columns">
          <td class="prompt"><label>Login ID:</label></td>
          <td class="value"><input name="user[login]" size="30" type="text" /></td>
        </tr>
        <br />
        <tr class="two_columns">
          <td class="prompt"><label>Password:</label></td>
          <td class="value"><input name="user[password]" size="30" type="password" value="" /></td>
        </tr>
        <br />
      </table>
      END
    end
  end
end