# encoding: UTF-8

require File.expand_path('../../test_helper', __FILE__)


describe "Styles" do

  before do
    @site = setup_site
    @template_root = File.expand_path(File.join(File.dirname(__FILE__), "../fixtures/styles"))
    @site.paths.add(:templates, @template_root)
    @renderer = S::Output::Template::PreviewRenderer.new
    S::Output.renderer = @renderer
  end

  after do
    teardown_site
  end

  describe "styles for" do

    before do
      ::Content.delete

      ::Page.box :box1

      class ::MissingClass < ::Piece; end
      class ::TemplateClass < ::Piece; end
      class ::TemplateSubClass1 < TemplateClass; end
      class ::TemplateSubClass2 < TemplateClass; end
      class ::InvisibleClass < ::Piece; end
    end

    after do
      ::Content.delete
      Object.send(:remove_const, :MissingClass) rescue nil
      Object.send(:remove_const, :TemplateClass) rescue nil
      Object.send(:remove_const, :TemplateSubClass1) rescue nil
      Object.send(:remove_const, :TemplateSubClass2) rescue nil
      Object.send(:remove_const, :InvisibleClass) rescue nil
    end

    describe "pieces" do


      describe "default styles" do
        before do
          @page  = ::Page.new
          @piece = TemplateClass.new
          @page.box1 << @piece
        end

        it "return anonymous style if no templates are found" do
          piece = MissingClass.new
          piece.style.class.must_equal Spontaneous::Style::Default
          # piece.style.template.must_be_instance_of(Proc)
          piece.style.template.call.must_equal ""
        end

        it "derive path from owning class and name" do
          assert_correct_template(@piece, @template_root / 'template_class')
        end

        it "render using correct template" do
          @piece.render.must_equal "template_class.html.cut\n"
        end

        # should "be able to give a list of available formats" do
        #   skip("Need to re-implement the format functionality")
        #   @piece.style.formats.must_equal [:epub, :html, :pdf]
        # end

        it "simply render an empty string if no templates are available" do
          piece = InvisibleClass.new
          @page.box1 << piece
          piece.render.must_equal ""
        end
      end


      describe "named styles" do
        before do
          @page  = ::Page.new
          @piece = TemplateClass.new
          @page.box1 << @piece
        end

        it "use template found in class directory if exists" do
          TemplateClass.style :named1
          assert_correct_template(@piece, @template_root / 'template_class/named1')
          @piece.render.must_equal "template_class/named1.html.cut\n"
        end

        it "use template in template root with correct name if it exists" do
          TemplateClass.style :named2
          assert_correct_template(@piece, @template_root / 'named2')
          @piece.render.must_equal "named2.html.cut\n"
        end

        it "allow passing of directory/stylename" do
          TemplateClass.style :'orange/apple'
          # piece.style.template.must_equal 'orange/apple'
          assert_correct_template(@piece, @template_root / 'orange/apple')
          @piece.render.must_equal "orange/apple.html.cut\n"
        end

        it "default to styles marked as 'default'" do
          TemplateClass.style :named1
          TemplateClass.style :named2, :default => true
          assert_correct_template(@piece, @template_root / 'named2')
          # @piece.style.template.must_equal 'named2'
          @piece.render.must_equal "named2.html.cut\n"
        end
      end

      describe "switching styles" do
        before do
          TemplateClass.style :named1
          TemplateClass.style :named2, :default => true
          @page  = ::Page.new
          @piece = TemplateClass.new
          @page.box1 << @piece
          assert_correct_template(@piece, @template_root / 'named2')
          # @piece.style.template.must_equal 'named2'
          @piece.render.must_equal "named2.html.cut\n"
        end

        it "be possible" do
          @piece.style = :named1
          assert_correct_template(@piece, @template_root / 'template_class/named1')
          @piece.render.must_equal "template_class/named1.html.cut\n"
        end

        it "persist" do
          @piece.style = :named1
          @piece.save
          @piece = Content[@piece.id]
          # @piece.style.template.must_equal 'template_class/named1'
          assert_correct_template(@piece, @template_root / 'template_class/named1')
        end
      end

      describe "inheriting styles" do
        it "use default for sub class if it exists" do
          piece = TemplateSubClass1.new
          assert_correct_template(piece, @template_root / 'template_sub_class1')
        end

        it "fall back to default style for superclass if default for class doesn't exist" do
          piece = TemplateSubClass2.new
          assert_correct_template(piece, @template_root / 'template_class')
          # piece.style.template.must_equal 'template_class'
        end
        it "fall back to defined default style for superclass if default for class doesn't exist" do
          TemplateClass.style :named1
          piece = TemplateSubClass2.new
          # piece.style.template.must_equal 'template_class/named1'
          assert_correct_template(piece, @template_root / 'template_class/named1')
        end
      end




      # describe "inline templates" do
      #   before do
      #     @class = Class.new(Content)
      #   end
      #   should "be definiable" do
      #     @class.style :simple
      #     @class.styles.length.must_equal 1
      #     t = @class.styles.first
      #     t.name.must_equal :simple
      #   end

      #   should "have configurable filenames" do
      #     @class.style :simple, :filename => "funky"
      #     t = @class.styles.first
      #     t.filename.must_equal "funky.html.cut"
      #   end

      #   should "have sane default titles" do
      #     @class.style :simple_style
      #     t = @class.styles.first
      #     t.title.must_equal "Simple Style"
      #   end

      #   should "have configurable titles" do
      #     @class.style :simple, :title => "A Simple Style"
      #     t = @class.styles.first
      #     t.title.must_equal "A Simple Style"
      #   end

      #   should "be accessable by name" do
      #     @class.style :simple
      #     @class.style :complex
      #     @class.styles[:simple].must_equal @class.styles.first
      #   end

      #   should "have #styles as a shortcut for #inliine_styles" do
      #     @class.style :simple
      #     @class.styles.must_equal @class.styles
      #   end

      #   should "take the first style as the default" do
      #     @class.style :simple
      #     @class.style :complex
      #     @class.styles.default.must_equal @class.styles[:simple]
      #   end

      #   should "honour the :default flag" do
      #     @class.style :simple
      #     @class.style :complex, :default => true
      #     @class.styles.default.must_equal @class.styles[:complex]
      #   end
      # end

      # describe "assigned styles" do
      #   before do
      #     class ::StyleTestClass < Content
      #       style :first_style
      #       style :default_style, :default => true
      #     end

      #     @a = StyleTestClass.new
      #     @b = StyleTestClass.new
      #     @a << @b
      #   end

      #   after do
      #     Object.send(:remove_const, :StyleTestClass)
      #   end

      #   should "assign the default style" do
      #     @a.pieces.first.style.must_equal ::StyleTestClass.styles.default
      #   end

      #   should "persist" do
      #     @a.save
      #     @b.save
      #     @a = StyleTestClass[@a.id]
      #     @a.pieces.first.style.must_equal ::StyleTestClass.styles.default
      #   end

      #   should "be settable" do
      #     @a.pieces.first.style = StyleTestClass.styles[:first_style]
      #     @a.save
      #     @a = StyleTestClass[@a.id]
      #     @a.pieces.first.style.must_equal ::StyleTestClass.styles[:first_style]
      #   end

      #   describe "direct piece access" do
      #     before do
      #       @a.pieces.first.style = StyleTestClass.styles[:first_style]
      #       @a.save
      #       piece_id = @a.pieces.first.target.id
      #       @piece = StyleTestClass[piece_id]
      #     end

      #     should "be accessible directly for pieces" do
      #       @piece.style.must_equal ::StyleTestClass.styles[:first_style]
      #     end

      #     should "not be settable directly on bare pieces" do
      #       lambda { @piece.style = ::StyleTestClass.styles.default }.must_raise(NoMethodError)
      #     end
      #   end
      # end

      describe "inline templates" do
        before do
          Page.add_output :pdf
          class ::InlineTemplateClass < Piece
            field :title

            template 'html: {{title}}'
            template :pdf, 'pdf: {{title}}'
          end

          @page = ::Page.new
          @a = InlineTemplateClass.new
          @page.box1 << @a
          @a.title = "Total Title"
        end

        after do
          Object.send(:remove_const, :InlineTemplateClass) rescue nil
        end

        it "be used to render the content" do
          @a.render.must_equal  "html: Total Title"
        end

        it "be used to render the content with the right format" do
          @a.render(:pdf).must_equal  "pdf: Total Title"
        end
      end

      # describe "default styles" do
      #   class ::DefaultStyleClass < Spontaneous::Box
      #     field :title
      #   end

      #   class ::WithDefaultStyleClass < Content
      #     field :title
      #   end
      #   class ::WithoutDefaultStyleClass < Content
      #     field :title
      #     box :with_style, :type => :DefaultStyleClass
      #   end
      #   before do
      #     Content.delete

      #     @with_default_style = WithDefaultStyleClass.new
      #     @with_default_style.title = "Total Title"
      #     @without_default_style = WithoutDefaultStyleClass.new
      #     @without_default_style.title = "No Title"
      #     @without_default_style.with_style.title = "Box Title"
      #     # @without_default_style.with_style.path = "Box Title"
      #   end

      #   after do
      #     Content.delete
      #     # Object.send(:remove_const, :DefaultStyleClass)
      #     # Object.send(:remove_const, :WithDefaultStyleClass)
      #     # Object.send(:remove_const, :WithoutDefaultStyleClass)
      #   end

      #   should "be used when available" do
      #     @with_default_style.render.must_equal "Title: Total Title\\n"
      #   end

      #   should "be used by boxes too" do
      #     @without_default_style.with_style.render.must_equal "Title: Box Title\\n"
      #   end

      #   should "fallback to anonymous style when default style template doesn't exist" do
      #     @without_default_style.render.must_equal "Title: Box Title\\n"
      #   end
      # end
    end

    describe "boxes" do
      before do
        class ::BoxA < ::Box; end
        class ::BoxB < ::Box; end
      end

      after do
        Object.send(:remove_const, :BoxA) rescue nil
        Object.send(:remove_const, :BoxB) rescue nil
      end

      describe "anonymous boxes" do
        before do
          TemplateClass.box :results
          TemplateClass.box :entities
          @page  = ::Page.new
          @piece = TemplateClass.new
          @page.box1 << @piece
        end

        it "use template with their name inside container class template dir if it exists" do
          @piece.results << TemplateClass.new
          assert_correct_template(@piece.results, @template_root / 'template_class/results')
          @piece.results.render.must_equal "template_class/results.html.cut\n"
        end

        it "render a simple list of content if named template doesn't exist" do
          @piece.entities << TemplateClass.new
          @piece.entities << TemplateClass.new
          @piece.entities.render.must_equal "template_class.html.cut\n\ntemplate_class.html.cut\n"
          @piece.entities.style.template.call.must_equal '${ render_content }'
        end


        it "use a named template if given" do
          TemplateClass.box :things do
            style :named1
          end
          @piece = TemplateClass.new
          @page.box1 << @piece
          assert_correct_template(@piece.things, @template_root / 'template_class/named1')
          @piece.things.render.must_equal "template_class/named1.html.cut\n"

          TemplateClass.box :dongles do
            style :named2
          end
          @piece = TemplateClass.new
          @page.box1 << @piece
          assert_correct_template(@piece.dongles, @template_root / 'named2')
          @piece.dongles.render.must_equal "named2.html.cut\n"
        end

        it "use styles assigned in a subclass" do
          ::TemplateSubClass = Class.new(TemplateClass)
          ::TemplateSubSubClass = Class.new(TemplateSubClass)

          TemplateSubClass.box :bananas
          TemplateSubClass.box :apples, :style => :apples
          TemplateSubClass.box :oranges do
            style :oranges
          end

          Dir.mktmpdir do |template_root|
            @site.paths.add(:templates, template_root / "templates")


            piece = TemplateSubSubClass.new
            @page.box1 << piece

            # make sure we're running in a 'virgin' template dir
            assert Proc === piece.bananas.template, "Expected Proc not #{piece.bananas.template}"


            [[piece.bananas, %w(template_sub_sub_class/bananas template_sub_class/bananas)],
             [piece.apples, %w(template_sub_sub_class/apples template_sub_class/apples apples)],
             [piece.oranges, %w(template_sub_sub_class/oranges template_sub_class/oranges oranges)]
            ].each do |box, test_templates|
              test_templates.each do |test_template|
                path = template_root / "templates" / test_template
                FileUtils.mkdir_p(File.dirname(path))
                FileUtils.touch(path + '.html.cut')

                assert_correct_template(box, template_root / "templates" / test_template)

                FileUtils.rm_r(template_root / "templates")
              end
            end
          end


          Object.send(:remove_const, :TemplateSubClass) rescue nil
          Object.send(:remove_const, :TemplateSubSubClass) rescue nil
        end
      end

      describe "boxes with a specified class" do
        before do
          TemplateClass.box :entities, :type => :BoxA
          TemplateClass.box :results, :type => :BoxB
          @page  = ::Page.new
          @piece = TemplateClass.new
          @page.box1 << @piece
        end

        it "use the box name template if it exists" do
          assert_correct_template(@piece.results, @template_root / 'template_class/results')
          @piece.results.render.must_equal "template_class/results.html.cut\n"
        end

        it "use the box classes default template if box name template is missing" do
          assert_correct_template(@piece.entities, @template_root / 'box_a')
          @piece.entities.render.must_equal "box_a.html.cut\n"
        end

        it "find templates for box subclasses with specified types defined in a supertype" do
          Object.send(:remove_const, :TemplateSubClass) rescue nil
          Object.send(:remove_const, :BoxASubclass) rescue nil
          class ::BoxASubclass < BoxA; end
          TemplateClass.box :lastly, :type => :BoxASubclass
          class ::TemplateSubClass < TemplateClass
          end
          piece = TemplateSubClass.new
          @page.box1 << piece
          assert_correct_template(piece.lastly, @template_root / 'box_a')
          Object.send(:remove_const, :BoxASubclass) rescue nil
          Object.send(:remove_const, :TemplateSubClass) rescue nil
        end

        describe "with configured styles" do
          before do
            BoxA.style :runny
            BoxA.style :walky
          end

          it "be configurable to use a specific style" do
            TemplateClass.box :sprinters, :type => :BoxA, :style => :runny
            TemplateClass.box :strollers, :type => :BoxA, :style => :walky
            page = ::Page.new
            piece = TemplateClass.new
            page.box1 << piece
            assert_correct_template(piece.strollers, @template_root / 'template_class/walky')
            assert_correct_template(piece.sprinters, @template_root / 'box_a/runny')
          end
        end
      end
    end
  end
end