# encoding: UTF-8

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


class SlotsTest < MiniTest::Spec
  include Spontaneous

  context "Slot containers" do
    setup do
      class ::SlotClass < Content; end
      class ::ContentClass < Content; end
      ContentClass.field :description
    end

    teardown do
      Object.send(:remove_const, :SlotClass)
      Object.send(:remove_const, :ContentClass)
    end

    should "start empty" do
      SlotClass.slots.length.should == 0
    end

    should "have a flag showing there are no defined slots" do
      SlotClass.has_slots?.should be_false
    end

    should "be definable with a name" do
      SlotClass.slot :images0
      SlotClass.slots.length.should == 1
      SlotClass.slots.first.name.should == :images0
      SlotClass.has_slots?.should be_true
    end

    should "accept a custom instance class" do
      SlotClass.slot :images1, :type => SlotClass
      SlotClass.slots.first.instance_class.superclass.should == SlotClass
    end

    should "accept a custom instance class as a string" do
      SlotClass.slot :images2, :type => 'SlotClass'
      SlotClass.slots.first.instance_class.superclass.should == SlotClass
    end

    should "accept a custom instance class as a symbol" do
      SlotClass.slot :images3, :type => :SlotClass
      SlotClass.slots.first.instance_class.superclass.should == SlotClass
    end

    should "have 'title' option" do
      SlotClass.slot :images4, :title => "Custom Title"
      @instance = SlotClass.new
      @instance.pieces.first.slot_name.should == "Custom Title"
    end

    should "accept values for the slot's fields" do
      SlotClass.slot :images4, :type => :ContentClass, :fields => { :description => "Neato" }

      @instance = SlotClass.new
      @instance.images4.fields.description.value.should == "Neato"
    end

    should "allow access to groups of slots" do
      SlotClass.slot :images5, :tag => :main
      SlotClass.slot :posts, :tag => :main
      SlotClass.slot :comments
      SlotClass.slot :last, :tag => :main
      @instance = SlotClass.new
      @instance.slots.tagged(:main).length.should == 3
      @instance.slots.tagged('main').map {|e| e.label.to_sym }.should == [:images5, :posts, :last]
    end

    context "with superclasses" do
      setup do
        SlotClass.slot :images6, :tag => :main

        @subclass1 = Class.new(SlotClass) do
          slot :monkeys, :tag => :main
          slot :apes
        end
        @subclass2 = Class.new(@subclass1) do
          slot :peanuts
        end
      end
      should "inherit slots from its superclass" do
        @subclass2.slots.length.should == 4
        @subclass2.slots.map { |s| s.name }.should == [:images6, :monkeys, :apes, :peanuts]
        @subclass2.slots.tagged(:main).length.should == 2
        instance = @subclass2.new
        instance.slots.length.should == 4
      end

      should "allow customisation of the slot order" do
        new_order = [:peanuts, :apes, :images6, :monkeys]
        @subclass2.slot_order *new_order
        @subclass2.slots.map { |s| s.name }.should == new_order
      end

      should "take order of instance slots from class defn" do
        new_order = [:peanuts, :apes, :images6, :monkeys]
        instance = @subclass2.create
        @subclass2.slot_order *new_order
        instance = @subclass2[instance.id]
        instance.slots.map { |e| e.label.to_sym }.should == new_order
      end
    end

    # should "default to the name of the slot for the style name" do
    #   SlotClass.slot :images
    #   instance = SlotClass.new
    #   instance.images.style.filename.should == "images.html.cut"
    # end
    should "default to a template-less style for slots without a style" do
      SlotClass.slot :images7
      instance = SlotClass.new
      instance.images7.style.class.should == Spontaneous::Plugins::Styles::AnonymousStyle
    end

    should "accept a custom template name" do
      SlotClass.slot :images8, :style => :anonymous_slot
      instance = SlotClass.new
      instance.images8.style.filename.should == "anonymous_slot.html.cut"
    end

    should "take template path from slot's parent for anonymous slots" do
      SlotClass.slot :images9, :style => :anonymous_slot
      SlotClass.slot :posts
      instance = SlotClass.new
      instance.images9.style.path.should == "slot_class/anonymous_slot"
      # instance.posts.style.path.should #== "#{Spontaneous.template_root}/slot_class/posts.html.cut"
    end

    context "anonymous slots" do
      setup do
        class ::AllowedType < Content; end
        SlotClass.slot :images10 do
          allow AllowedType

          def monkey
            "magic"
          end
        end
      end

      teardown do
        Object.send(:remove_const, :AllowedType)
      end

      should "allow configuration of allowed types for anonymous slots" do
        SlotClass.slots.first.instance_class.allowed.length.should == 1
      end

      should "allow methods in slot definitions" do
        instance = SlotClass.new
        instance.images10.monkey.should == "magic"
      end

      should "correctly save pieces" do
        instance = SlotClass.new
        c1 = AllowedType.new
        c2 = AllowedType.new
        c3 = AllowedType.new
        instance.images10 << c1
        instance.images10 << c2
        instance.images10 << c3

        instance.save
        instance.images10.save
        c1.save
        c2.save
        c3.save

        instance = SlotClass[instance.id]
        instance.images10.pieces.length.should == 3
      end
    end

    context "slots with definied classes" do
      setup do
        class ::AllowedType < Content; end
        SlotClass.slot :images11, :type => AllowedType do
          allow AllowedType

          def monkey
            "magic"
          end
        end
      end

      teardown do
        Object.send(:remove_const, :AllowedType)
      end

      should "allow per-slot definitions" do
        SlotClass.slots.first.instance_class.allowed.length.should == 1
        instance = SlotClass.new
        instance.images11.monkey.should == "magic"
        instance = SlotClass[instance.id]
        instance.images11.monkey.should == "magic"
      end
    end
    context "" do
      setup do
        SlotClass.slot :images12
        @instance = SlotClass.new
      end

      should "provide a test for existance of named slot" do
        @instance.slot?(:images12).should be_true
        @instance.slot?(:none).should be_false
      end

      should "instantiate a corresponding piece in new instances" do
        @instance.pieces.length.should == 1
        # @instance.pieces.first.class.should == Piece
        @instance.pieces.first.label.should == :images12
        @instance.pieces.first.slot_name.should == "Images12"
      end

      should "have a #slots method for accessing slots" do
        @instance.slots.length.should == 1
        @instance.slots.first.label.should == :images12
        @instance.slots.first.slot_id.should == "images12"
        @instance.slots[:images12].should == @instance.slots.first
      end

      should "have shortcut methods for accessing slots by name" do
        @instance.slots.images12.should == @instance.slots.first
        @instance.images12.should == @instance.slots.first
      end

      should "persist slots" do
        @instance.save
        @instance = SlotClass[@instance.id]
        @instance.slots.length.should == 1
        @instance.slots.first.label.should == :images12
        @instance.slots[:images12].should == @instance.slots.first
        @instance.slots.images12.should == @instance.slots.first
        @instance.images12.should == @instance.slots.first
      end

      should "update list of slots on instance if slot added after creation" do
        @instance.save
        SlotClass.slot :posts
        @instance = SlotClass[@instance.id]
        @instance.slots.length.should == 2
        @instance.slots.first.label.should == :images12
        @instance.slots.last.label.should == :posts
        @instance.slots[:images12].should == @instance.slots.first
        @instance.slots[:posts].should == @instance.slots.last
        @instance.slots.images12.should == @instance.slots.first
        @instance.slots.posts.should == @instance.slots.last
        @instance.images12.should == @instance.slots.first
        @instance.posts.should == @instance.slots.last
      end

      ## waiting on entry deletion routines
      should "update list of slots on instance if slot removed after creation"
      # should "update list of slots on instance if slot removed after creation" do
      #   @instance.save
      #   SlotClass.slot :posts
      #   @instance = SlotClass[@instance.id]
      #   @instance.slots.length.should == 2
      #   SlotClass.slots.shift
      #   p SlotClass.slots
      #   @instance = SlotClass[@instance.id]
      #   @instance.slots.length.should == 1
      #   @instance.slots.first.label.should == "posts"
      #   @instance.slots[:posts].should == @instance.slots.first
      #   @instance.slots.posts.should == @instance.slots.first
      #   @instance.posts.should == @instance.slots.first
      # end
    end

    context "addition of slots" do
      should "be possible after creation" do
        SlotClass.slot :posts
        instance = SlotClass.new
        instance.save
        SlotClass.slot :images
        instance = SlotClass[instance.id]
        instance.images.should_not be_nil
      end
    end
  end
end