import ArrayVisualization from '../../helix/javascript/array_summary/array_visualization';
import $ from 'jquery';
import 'jasmine-jquery';
import * as PanelExports from '../../helix/javascript/array_summary/panel';

describe("The array visualization", function () {
  let Panel;
  let isDualTilt = false;
  let subject;
  let containerSpy;
  let subarrayDisplaySpy;

  beforeEach(function () {
    const panel = jasmine.createSpyObj("shape",
      ["dispatchEvent", "zoom", "setOverlay", "on", "select", "deselect", "redrawOverlays"]);
    spyOn(PanelExports, 'Panel').and.returnValue(panel);
    Panel = PanelExports.Panel;
    subarrayDisplaySpy = jasmine.createSpyObj("SubarrayDisplay", ["didModifyPanels"]);

    let panelData = [
      {'x': 1, 'y': 1, 'width': 1, 'height': 1, 'data': {'ballast': 3, 'seismic_anchors': 3}},
      {'x': 1, 'y': 2, 'width': 1, 'height': 1, 'data': {'ballast': 4, 'seismic_anchors': 2}},
      {'x': 1, 'y': 1, 'width': 1, 'height': 1, 'data': {'ballast': 7, 'seismic_anchors': 0}},
      {'x': 2, 'y': 1, 'width': 1, 'height': 1, 'data': {'ballast': 1, 'seismic_anchors': 1}},
      {'x': 2, 'y': 2, 'width': 1, 'height': 1, 'data': {'ballast': 6, 'seismic_anchors': 0}}
    ];

    let buildings = [[ {'x': -60,  'y': 60,  'rotation': 0.0},
        {'x': 60,  'y': 60,   'rotation': 0.0},
        {'x': 60,  'y': -60,  'rotation': 0.0},
        {'x': -60, 'y': -60, 'rotation': 0.0}]];

    subject = new ArrayVisualization(panelData, isDualTilt, subarrayDisplaySpy, buildings);
  });

  describe('#init', function () {
    beforeEach(function () {
      containerSpy = jasmine.createSpyObj("container", ["addChild", "removeChild", "dispatchEvent"]);
      spyOn(createjs, "Container").and.returnValue(containerSpy);
      subject.init();
    });

    it("creates a panel for each panel in the visualization", function () {
      expect(Panel.calls.count()).toEqual(5);
      expect(Panel.calls.argsFor(0)).toEqual([{
        'x': 1,
        'y': 1,
        'width': 1,
        'height': 1,
        'data': {'ballast': 3, 'seismic_anchors': 3}
      }, isDualTilt, 10, true]);
      expect(Panel.calls.argsFor(1)).toEqual([{
        'x': 1,
        'y': 2,
        'width': 1,
        'height': 1,
        'data': {'ballast': 4, 'seismic_anchors': 2}
      }, isDualTilt, 10, true]);
      expect(Panel.calls.argsFor(2)).toEqual([{
        'x': 1,
        'y': 1,
        'width': 1,
        'height': 1,
        'data': {'ballast': 7, 'seismic_anchors': 0}
      }, isDualTilt, 10, true]);
      expect(Panel.calls.argsFor(3)).toEqual([{
        'x': 2,
        'y': 1,
        'width': 1,
        'height': 1,
        'data': {'ballast': 1, 'seismic_anchors': 1}
      }, isDualTilt, 10, true]);
      expect(Panel.calls.argsFor(4)).toEqual([{
        'x': 2,
        'y': 2,
        'width': 1,
        'height': 1,
        'data': {'ballast': 6, 'seismic_anchors': 0}
      }, isDualTilt, 10, true]);
    });

    it("adds the panels and buildings to the container", function () {
      expect(containerSpy.addChild.calls.count()).toEqual(6);
    });

    it("adds the container to the stage", function () {
      expect(subject.stage.children).toContain(containerSpy);
    });

    describe("selecting a panel", function () {
      let panel;
      beforeEach(function () {
        panel = subject.panels[0];
        subject.selectPanel(0);
      });

      it("marks the panel as selected", function () {
        expect(panel.select).toHaveBeenCalled();
      });

      it("deselects this panel when another panel is selected", function () {
        subject.selectPanel(1);
        expect(panel.deselect).toHaveBeenCalled();
      });

      it("deselects the panel when it is selected again", function () {
        panel.select.calls.reset();
        panel.deselect.calls.reset();
        subject.selectPanel(0);
        expect(panel.deselect).toHaveBeenCalled();
        expect(panel.select).not.toHaveBeenCalled();
      });
    });

    describe("panning", function () {
      describe("dragging on the canvas", function () {
        beforeEach(function () {
          let event = new createjs.Event("pressmove");
          event.stageX = 5;
          event.stageY = 3;
          subject.stage.dispatchEvent(event);
        });

        it("does nothing on the first invocation", function () {
          expect(containerSpy.x).toEqual(0);
          expect(containerSpy.y).toEqual(0);
        });

        describe("the subsequent pressmove after the first", function () {
          beforeEach(function () {
            let event = new createjs.Event("pressmove");
            event.stageX = 10;
            event.stageY = 5;
            subject.stage.dispatchEvent(event);
          });

          it("moves the container based on the delta of the this and the previous pressmove", function () {
            expect(containerSpy.x).toEqual(5);
            expect(containerSpy.y).toEqual(2);
          });

          describe("ending the pressmove and starting again", function () {
            beforeEach(function () {
              subject.stage.dispatchEvent("pressup");

              let event = new createjs.Event("pressmove");
              event.stageX = 9;
              event.stageY = 3;
              subject.stage.dispatchEvent(event);
            });

            it("does not move the container again", function () {
              expect(containerSpy.x).toEqual(5);
              expect(containerSpy.y).toEqual(2);
            });

            it("moves the container based on the delta of this on subsequent pressmove events", function () {
              let event = new createjs.Event("pressmove");
              event.stageX = 15;
              event.stageY = 33;
              subject.stage.dispatchEvent(event);
              expect(containerSpy.x).toEqual(11);
              expect(containerSpy.y).toEqual(32);
            });
          });
        });
      });
    });

    describe("zooming", function () {
      it("changes the scale of the container", function () {
        subject.setZoom(5);

        expect(subject.container.scaleX).toEqual(5);
        expect(subject.container.scaleY).toEqual(5);
      });
    });

    describe("changing the overlays", function () {
      it("changes the selected overlays on the Panel object", function () {
        subject.setOverlay("ooga");

        subject.panels.forEach(function (panel) {
          expect(panel.setOverlay).toHaveBeenCalledWith("ooga");
        });
      });
    });

    describe("adding seismic anchors", function () {
      describe("when no panel is selected", function () {
        beforeEach(function () {
          subject.addSeismicAnchor();
        });

        it("does nothing", function () {
          expect(subject.panelData[0].data.seismic_anchors).toEqual(3);
          expect(subject.panelData[1].data.seismic_anchors).toEqual(2);
          expect(subject.panelData[2].data.seismic_anchors).toEqual(0);
          expect(subject.panelData[3].data.seismic_anchors).toEqual(1);
          expect(subject.panelData[4].data.seismic_anchors).toEqual(0);

          for (let i = 0; i < subject.panels.length; i++) {
            expect(subject.panels[i].redrawOverlays).not.toHaveBeenCalled();
          }
        });

        it("does not call the seismic monitor spy", function () {
          expect(subarrayDisplaySpy.didModifyPanels).not.toHaveBeenCalled();
        });
      });

      describe("when a panel is selected", function () {
        beforeEach(function () {
          subject.selectPanel(0);
          subject.addSeismicAnchor();
        });

        it("increases the number of seismic anchors for that panel by one", function () {
          expect(subject.panelData[0].data.seismic_anchors).toEqual(4);
        });

        it("refreshes the text on the panel object", function () {
          expect(subject.panels[0].redrawOverlays).toHaveBeenCalled();
        });

        it("calls the seismic monitor spy", function () {
          expect(subarrayDisplaySpy.didModifyPanels).toHaveBeenCalledWith(subject.panelData);
        });
      });
    });

    describe("removing seismic anchors", function () {
      describe("when no panel is selected", function () {
        beforeEach(function () {
          subject.removeSeismicAnchor();
        });

        it("does nothing", function () {
          expect(subject.panelData[0].data.seismic_anchors).toEqual(3);
          expect(subject.panelData[1].data.seismic_anchors).toEqual(2);
          expect(subject.panelData[2].data.seismic_anchors).toEqual(0);
          expect(subject.panelData[3].data.seismic_anchors).toEqual(1);
          expect(subject.panelData[4].data.seismic_anchors).toEqual(0);

          for (let i = 0; i < subject.panels.length; i++) {
            expect(subject.panels[i].redrawOverlays).not.toHaveBeenCalled();
          }
        });

        it("does not call the seismic monitor spy", function () {
          expect(subarrayDisplaySpy.didModifyPanels).not.toHaveBeenCalled();
        });
      });

      describe("when a panel with no seismic anchors is selected", function () {
        beforeEach(function () {
          subject.selectPanel(2);
          subject.removeSeismicAnchor();
        });

        it("does nothing", function () {
          expect(subject.panelData[0].data.seismic_anchors).toEqual(3);
          expect(subject.panelData[1].data.seismic_anchors).toEqual(2);
          expect(subject.panelData[2].data.seismic_anchors).toEqual(0);
          expect(subject.panelData[3].data.seismic_anchors).toEqual(1);
          expect(subject.panelData[4].data.seismic_anchors).toEqual(0);

          for (let i = 0; i < subject.panels.length; i++) {
            expect(subject.panels[i].redrawOverlays).not.toHaveBeenCalled();
          }
        });

        it("does not call the seismic monitor spy", function () {
          expect(subarrayDisplaySpy.didModifyPanels).not.toHaveBeenCalled();
        });
      });

      describe("when a panel with seismic anchors is selected", function () {
        beforeEach(function () {
          subject.selectPanel(1);
          subject.removeSeismicAnchor();
        });

        it("increases the number of seismic anchors for that panel by one", function () {
          expect(subject.panelData[1].data.seismic_anchors).toEqual(1);
        });

        it("refreshes the text on the panel object", function () {
          expect(subject.panels[1].redrawOverlays).toHaveBeenCalled();
        });

        it("calls the seismic monitor spy", function () {
          expect(subarrayDisplaySpy.didModifyPanels).toHaveBeenCalledWith(subject.panelData);
        });
      });
    });

    describe("refreshing the panels", function () {
      let panelData = [
        {'x': 1, 'y': 1, 'width': 1, 'height': 1, 'data': {'ballast': 3, 'seismic_anchors': 3}},
        {'x': 1, 'y': 2, 'width': 1, 'height': 1, 'data': {'ballast': 4, 'seismic_anchors': 2}},
        {'x': 1, 'y': 1, 'width': 1, 'height': 1, 'data': {'ballast': 7, 'seismic_anchors': 0}},
        {'x': 2, 'y': 1, 'width': 1, 'height': 1, 'data': {'ballast': 1, 'seismic_anchors': 1}},
        {'x': 2, 'y': 2, 'width': 1, 'height': 1, 'data': {'ballast': 6, 'seismic_anchors': 0}}
      ];
      beforeEach(function () {

        subject.refreshPanels(panelData);
      });

      it("removes the existing panels from the container", function () {
        expect(containerSpy.removeChild.calls.count()).toEqual(5);
      });

      it("tells the subarray_display that we modified the panels", function () {
        expect(subarrayDisplaySpy.didModifyPanels).toHaveBeenCalledWith(panelData);
      });

      it("creates new panels and adds them to the container", function () {
        expect(Panel.calls.count()).toEqual(10);
        expect(Panel.calls.argsFor(5)).toEqual([{
          'x': 1,
          'y': 1,
          'width': 1,
          'height': 1,
          'data': {'ballast': 3, 'seismic_anchors': 3}
        }, isDualTilt, 10, true]);
        expect(Panel.calls.argsFor(6)).toEqual([{
          'x': 1,
          'y': 2,
          'width': 1,
          'height': 1,
          'data': {'ballast': 4, 'seismic_anchors': 2}
        }, isDualTilt, 10, true]);
        expect(Panel.calls.argsFor(7)).toEqual([{
          'x': 1,
          'y': 1,
          'width': 1,
          'height': 1,
          'data': {'ballast': 7, 'seismic_anchors': 0}
        }, isDualTilt, 10, true]);
        expect(Panel.calls.argsFor(8)).toEqual([{
          'x': 2,
          'y': 1,
          'width': 1,
          'height': 1,
          'data': {'ballast': 1, 'seismic_anchors': 1}
        }, isDualTilt, 10, true]);
        expect(Panel.calls.argsFor(9)).toEqual([{
          'x': 2,
          'y': 2,
          'width': 1,
          'height': 1,
          'data': {'ballast': 6, 'seismic_anchors': 0}
        }, isDualTilt, 10, true]);
      });
    });
  });
});
