import { destroyObject } from "../../Source/Cesium.js";
import { OrderedGroundPrimitiveCollection } from "../../Source/Cesium.js";

describe("Scene/OrderedGroundPrimitiveCollection", function () {
  var updateCallOrder;

  beforeEach(function () {
    updateCallOrder = [];
  });

  function MockPrimitive() {}

  MockPrimitive.prototype.update = function () {
    updateCallOrder.push(this);
  };

  MockPrimitive.prototype.isDestroyed = function () {
    return false;
  };
  MockPrimitive.prototype.destroy = function () {
    return destroyObject(this);
  };

  it("constructs", function () {
    var collection = new OrderedGroundPrimitiveCollection();
    expect(collection.length).toBe(0);
    expect(collection.show).toBe(true);
  });

  it("add throws without primitive", function () {
    expect(function () {
      var collection = new OrderedGroundPrimitiveCollection();
      collection.add();
    }).toThrowDeveloperError();
  });

  it("add throws if zIndex is not a number", function () {
    expect(function () {
      var collection = new OrderedGroundPrimitiveCollection();
      collection.add(new MockPrimitive(), "3");
    }).toThrowDeveloperError();
  });

  it("adds a primitive", function () {
    var collection = new OrderedGroundPrimitiveCollection();
    collection.add(new MockPrimitive());
    expect(collection.length).toBe(1);
  });

  it("add handles multiple zIndexes", function () {
    var collection = new OrderedGroundPrimitiveCollection();
    var p1 = collection.add(new MockPrimitive());
    var p2 = collection.add(new MockPrimitive(), 0);
    var p3 = collection.add(new MockPrimitive(), 2);
    var p4 = collection.add(new MockPrimitive(), 1);
    expect(collection.length).toBe(4);

    var array = collection._collectionsArray;
    expect(array.length).toBe(3);
    expect(array[0].length).toBe(2);
    expect(array[0].get(0)).toBe(p1);
    expect(array[0].get(1)).toBe(p2);
    expect(array[1].length).toBe(1);
    expect(array[1].get(0)).toBe(p4);
    expect(array[2].length).toBe(1);
    expect(array[2].get(0)).toBe(p3);
  });

  it("add works with negative zIndexes", function () {
    var collection = new OrderedGroundPrimitiveCollection();
    var p1 = collection.add(new MockPrimitive(), 0);
    var p2 = collection.add(new MockPrimitive(), -3);
    var p3 = collection.add(new MockPrimitive(), -1);
    var p4 = collection.add(new MockPrimitive(), -3);
    expect(collection.length).toBe(4);

    var array = collection._collectionsArray;
    expect(array.length).toBe(3);
    expect(array[0].length).toBe(2);
    expect(array[0].get(0)).toBe(p2);
    expect(array[0].get(1)).toBe(p4);
    expect(array[1].length).toBe(1);
    expect(array[1].get(0)).toBe(p3);
    expect(array[2].length).toBe(1);
    expect(array[2].get(0)).toBe(p1);
  });

  it("set throws without primitive", function () {
    expect(function () {
      var collection = new OrderedGroundPrimitiveCollection();
      collection.set(undefined, 3);
    }).toThrowDeveloperError();
  });

  it("set throws without zIndex", function () {
    expect(function () {
      var collection = new OrderedGroundPrimitiveCollection();
      collection.set(new MockPrimitive(), undefined);
    }).toThrowDeveloperError();
  });

  it("set throws if zIndex is not a number", function () {
    expect(function () {
      var collection = new OrderedGroundPrimitiveCollection();
      collection.set(new MockPrimitive(), "3");
    }).toThrowDeveloperError();
  });

  it("set adds primitive if it is not in the collection", function () {
    var collection = new OrderedGroundPrimitiveCollection();
    collection.set(new MockPrimitive(), 3);
    expect(collection.length).toBe(1);
  });

  it("set changes a primitives index", function () {
    var collection = new OrderedGroundPrimitiveCollection();
    var p1 = collection.add(new MockPrimitive(), 0);
    var p2 = collection.add(new MockPrimitive(), 0);
    var p3 = collection.add(new MockPrimitive(), 2);
    var p4 = collection.add(new MockPrimitive(), 1);
    expect(collection.length).toBe(4);

    collection.set(p4, 2);

    expect(collection.length).toBe(4);

    var array = collection._collectionsArray;
    expect(array.length).toBe(2);
    expect(array[0].length).toBe(2);
    expect(array[0].get(0)).toBe(p1);
    expect(array[0].get(1)).toBe(p2);
    expect(array[1].length).toBe(2);
    expect(array[1].get(0)).toBe(p3);
    expect(array[1].get(1)).toBe(p4);
  });

  it("set works with negative indexes", function () {
    var collection = new OrderedGroundPrimitiveCollection();
    var p1 = collection.add(new MockPrimitive(), 0);
    var p2 = collection.add(new MockPrimitive(), 0);
    expect(collection.length).toBe(2);

    collection.set(p2, -1);

    var array = collection._collectionsArray;
    expect(array.length).toBe(2);
    expect(array[0].length).toBe(1);
    expect(array[0].get(0)).toBe(p2);
    expect(array[1].length).toBe(1);
    expect(array[1].get(0)).toBe(p1);
  });

  it("set throws without primitive", function () {
    expect(function () {
      var collection = new OrderedGroundPrimitiveCollection();
      collection.set(undefined, 3);
    }).toThrowDeveloperError();
  });

  it("removes a primitive", function () {
    var collection = new OrderedGroundPrimitiveCollection();
    var p = collection.add(new MockPrimitive());
    var result = collection.remove(p);
    expect(result).toBe(true);
    expect(collection.length).toBe(0);
    expect(collection._collectionsArray.length).toBe(0);
    expect(p.isDestroyed()).toBe(true);
  });

  it("removes handles multiple zIndexes", function () {
    var collection = new OrderedGroundPrimitiveCollection();
    var p1 = collection.add(new MockPrimitive(), 0);
    var p2 = collection.add(new MockPrimitive(), 2);
    var p3 = collection.add(new MockPrimitive(), 2);
    var p4 = collection.add(new MockPrimitive(), 1);
    expect(collection.length).toBe(4);

    var array = collection._collectionsArray;
    expect(array.length).toBe(3);
    collection.remove(p3);
    expect(array.length).toBe(3);
    collection.remove(p2);
    expect(array.length).toBe(2);
    expect(array[0].get(0)).toBe(p1);
    expect(array[1].get(0)).toBe(p4);
  });

  it("removes null", function () {
    var collection = new OrderedGroundPrimitiveCollection();
    expect(collection.remove()).toEqual(false);
  });

  it("removeAll removes and destroys all primitives", function () {
    var collection = new OrderedGroundPrimitiveCollection();
    var p1 = collection.add(new MockPrimitive(), 0);
    var p2 = collection.add(new MockPrimitive(), 0);
    var p3 = collection.add(new MockPrimitive(), 2);
    var p4 = collection.add(new MockPrimitive(), 1);
    expect(collection.length).toBe(4);
    collection.removeAll();
    expect(collection.length).toBe(0);
    expect(p1.isDestroyed()).toBe(true);
    expect(p2.isDestroyed()).toBe(true);
    expect(p3.isDestroyed()).toBe(true);
    expect(p4.isDestroyed()).toBe(true);
  });

  it("contains primitive", function () {
    var collection = new OrderedGroundPrimitiveCollection();
    var p1 = collection.add(new MockPrimitive());

    expect(collection.contains(p1)).toBe(true);
  });

  it("does not contain primitive", function () {
    var collection = new OrderedGroundPrimitiveCollection();
    var p1 = new MockPrimitive();

    expect(collection.contains(p1)).toBe(false);
  });

  it("does not contain undefined", function () {
    var collection = new OrderedGroundPrimitiveCollection();
    expect(collection.contains()).toEqual(false);
  });

  it("update is called in the correct order", function () {
    var collection = new OrderedGroundPrimitiveCollection();
    var p1 = collection.add(new MockPrimitive(), 0);
    var p2 = collection.add(new MockPrimitive(), 3);
    var p3 = collection.add(new MockPrimitive(), 1);
    var p4 = collection.add(new MockPrimitive(), 2);
    collection.update();
    expect(updateCallOrder).toEqual([p1, p3, p4, p2]);

    updateCallOrder = [];
    collection.set(p1, 4);
    collection.update();
    expect(updateCallOrder).toEqual([p3, p4, p2, p1]);

    updateCallOrder = [];
    collection.set(p2, 0);
    collection.update();
    expect(updateCallOrder).toEqual([p2, p3, p4, p1]);

    updateCallOrder = [];
    collection.set(p4, -1);
    collection.update();
    expect(updateCallOrder).toEqual([p4, p2, p3, p1]);
  });

  it("update is not called when show is false", function () {
    var collection = new OrderedGroundPrimitiveCollection();
    collection.add(new MockPrimitive(), 0);
    collection.add(new MockPrimitive(), 3);
    collection.show = false;
    collection.update();
    expect(updateCallOrder).toEqual([]);
  });

  it("destroys", function () {
    var collection = new OrderedGroundPrimitiveCollection();
    expect(collection.isDestroyed()).toBe(false);
    collection.destroy();
    expect(collection.isDestroyed()).toBe(true);
  });
});
