# encoding: UTF-8

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


describe "Content" do
  before do
    @site = setup_site
    class C < ::Piece; end
    class P < ::Page; end

    C.box :things
    P.box :box1
    P.box :box2
  end

  after do
    Object.send(:remove_const, :C) rescue nil
    Object.send(:remove_const, :P) rescue nil
    teardown_site
  end

  describe "Content instances" do
    it "evaluate instance code" do
      @instance = C.create({
        :instance_code => "def monkey; 'magic'; end"
      })
      @instance.monkey.must_equal 'magic'
      id = @instance.id
      @instance = ::Content[id]
      @instance.monkey.must_equal 'magic'
    end
  end
  describe "pieces" do
    before do
      @instance = C.new
    end

    after do
      ::Content.delete rescue nil
    end

    it "be initialised empty" do
      @instance.contents.to_a.must_equal []
    end

    it "provide a #target method poiting to itself" do
      @instance.target.must_equal @instance
    end

    it "accept addition of child content" do
      e = C.new
      @instance.things << e
      @instance.contents.length.must_equal 1
      @instance.things.contents.length.must_equal 1
      @instance.contents.first.must_equal e
      @instance.contents.first.container.must_equal @instance.things
      @instance.contents.first.owner.must_equal @instance
      @instance.contents.first.parent.must_equal @instance
      e.visibility_path.must_equal "#{@instance.id}"
      @instance.contents.first.visibility_path.must_equal "#{@instance.id}"
    end

    it "accept addition of multiple children" do
      e = C.new
      f = C.new
      @instance.things << e
      @instance.things << f
      @instance.contents.length.must_equal 2
      @instance.things.contents.length.must_equal 2
      @instance.contents.first.must_equal e
      @instance.things.contents.first.must_equal e
      @instance.contents.last.must_equal f
      @instance.things.contents.last.must_equal f
      @instance.contents.first.container.must_equal @instance.things
      @instance.contents.last.container.must_equal @instance.things
      @instance.contents.first.parent.must_equal @instance
      @instance.contents.last.parent.must_equal @instance
      @instance.contents.first.owner.must_equal @instance
      @instance.contents.last.owner.must_equal @instance
      @instance.contents.first.visibility_path.must_equal "#{@instance.id}"
      @instance.contents.last.visibility_path.must_equal "#{@instance.id}"
    end

    it "allow for a deep hierarchy" do
      e = C.new
      f = C.new
      @instance.things << e
      e.things << f
      @instance.contents.length.must_equal 1
      @instance.contents.first.must_equal e
      e.owner.id.must_equal @instance.id
      e.parent.id.must_equal @instance.id
      e.container.must_equal @instance.things
      e.visibility_path.must_equal "#{@instance.id}"

      f.owner.id.must_equal e.id
      f.parent.id.must_equal e.id
      f.container.must_equal e.things
      f.visibility_path.must_equal "#{@instance.id}.#{e.id}"
    end

    it "persist hierarchy" do
      e = C.new
      f = C.new
      e.things << f
      @instance.things << e
      @instance.save
      e.save
      f.save

      i = C[@instance.id]
      e = C[e.id]
      f = C[f.id]

      i.contents.length.must_equal 1
      i.contents.first.must_equal e

      e.container.must_equal i.things
      e.owner.must_equal i
      e.parent.must_equal i
      f.container.must_equal e.things
      f.parent.must_equal e
      f.owner.must_equal e
      e.entry.must_equal i.contents.first
      f.entry.must_equal e.contents.first
      e.contents.first.must_equal f
    end

    it "have a list of child nodes" do
      e = C.new
      f = C.new
      e.things << f
      @instance.things << e
      @instance.save
      e.save
      f.save

      i = C[@instance.id]
      e = C[e.id]
      f = C[f.id]
      i.contents.to_a.must_equal [e]
      e.contents.to_a.must_equal [f]
    end

    it "provide a list of non-page contents" do
      p = P.new

      c1 = C.new
      c2 = C.new
      c3 = C.new
      p1 = P.new
      p2 = P.new
      p3 = P.new

      p.box1 << c1
      p.box1 << c2
      p.box1 << p1

      p.box2 << p3
      p.box2 << c3

      [p, c1, c2, c3, p1, p2, p3].each { |c| c.save; c.reload }

      p = P[p.id]

      p.pieces.must_equal [c1, c2, c3]
    end


    it "allow for testing of position" do
      e = C.new
      f = C.new
      g = C.new
      @instance.things << e
      @instance.things << f
      @instance.things << g
      assert e.first?
      refute f.first?
      refute g.first?
      refute e.last?
      refute f.last?
      assert g.last?
    end

    it "know their next neighbour" do
      e = C.new
      f = C.new
      g = C.new
      @instance.things << e
      @instance.things << f
      @instance.things << g
      e.next.must_equal f
      f.next.must_equal g
      g.next.must_be_nil
    end

    it "know their previous neighbour" do
      e = C.new
      f = C.new
      g = C.new
      @instance.things << e
      @instance.things << f
      @instance.things << g
      e.previous.must_be_nil
      f.previous.must_equal e
      g.previous.must_equal f
      g.prev.must_equal f
    end

    it "record the depth of the nodes" do
      a = C.new
      b = C.new
      c = C.new

      a.depth.must_equal 0
      b.depth.must_equal 0
      c.depth.must_equal 0

      a.things << b
      b.things << c

      b.depth.must_equal 1
      c.depth.must_equal 2
    end


  end
  describe "Deletion" do
    before do
      C.delete
      @a = C.new(:label => 'a')
      @b = C.new(:label => 'b')
      @c = C.new(:label => 'c')
      @d = C.new(:label => 'd')
      @a.things << @b
      @a.things << @d
      @b.things << @c
      @a.save
      @b.save
      @c.save
      @d.save
      @a = C[@a.id]
      @b = C[@b.id]
      @c = C[@c.id]
      @d = C[@d.id]
      C.count.must_equal 4
      @ids = [@a, @b, @c, @d].map {|c| c.id }
    end
    it "recurse all the way" do
      @a.destroy
      C.count.must_equal 0
    end

    it "recurse" do
      @b.destroy
      C.count.must_equal 2
      @a.reload
      @a.contents.length.must_equal 1
      @a.contents.first.must_equal @d.reload
      C.all.map { |c| c.id }.sort.must_equal [@a, @d].map { |c| c.id }.sort
    end

    it "work through pieces" do
      @a.things.length.must_equal 2
      @a.things.first.destroy
      C.count.must_equal 2
      @a.things.length.must_equal 1
    end
  end

  describe "Moving" do
    before do
      C.delete
      @r = C.new(:label => 'r')
      @a = C.new(:label => 'a')
      @b = C.new(:label => 'b')
      @c = C.new(:label => 'c')
      @d = C.new(:label => 'd')
      @r.things << @a
      @r.things << @c
      @a.things << @b
      @c.things << @d
      [@r, @a, @b, @c, @d].each { |c| c.save; c.reload }
    end

    after do
      C.delete
    end

    it "default to adding at the end" do
      @b.parent.must_equal @a
      @r.things.adopt(@b)
      @b.reload
      @r.reload
      @b.parent.must_equal @r
      @b.container.must_equal @r.things
      @b.depth.must_equal 1
      @a.reload
      @a.things.count.must_equal 0
      @r.reload
      @r.things.last.must_equal @b
    end

    it "allow for adding in any position" do
      @b.parent.must_equal @a
      @r.things.adopt(@b, 1)
      @b.reload
      @r.reload
      @b.parent.must_equal @r
      @b.container.must_equal @r.things
      @b.depth.must_equal 1
      @a.reload
      @a.things.count.must_equal 0
      @r.reload
      @r.things[1].must_equal @b
      @r.things.adopt(@d, 0)
      @d.reload
      @r.reload
      @r.things[0].must_equal @d
    end

    it "re-set the visibility path" do
      @r.things.adopt(@b)
      @b.reload
      @b.visibility_path.must_equal @r.id.to_s
    end

    it "ensure that child pages have their visibility paths updated" do
      skip "Implement this"
    end
  end
end