"use strict";

describe('history', function() {
  var mockConfigurator = {
    getConfAndDelegate: function() {},
    provideResource: function() {}
  };

  var mockKC = {
    initCaptures: function() {}
  };

  beforeEach(module("arethusa.core"));

  beforeEach(module("arethusa.hist", function($provide) {
    $provide.value('configurator', mockConfigurator);
    $provide.value('keyCapture', mockKC);
  }));

  var history, state;
  var undone, redone;
  beforeEach(inject(function(_history_, _state_) {
    history = _history_;
    state   = _state_;
    history.init();
    undone = 0;
    redone = 0;
  }));

  function MockEvent(type) {
    this.exec = function() { redone++; };
    this.undo = function() { undone++; };
    this.type = type;
  }

  describe('this.canUndo', function() {
    it('is false on init', function() {
      expect(history.canUndo).toBeFalsy();
    });

    it('is true when element to undo is present', function() {
      history.saveEvent(new MockEvent());
      expect(history.canUndo).toBeTruthy();
    });

    it('is false when elements are present but we traversed the whole history', function() {
      history.saveEvent(new MockEvent());
      history.undo();
      expect(history.canUndo).toBeFalsy();
    });

    it('is true when we are on the end of the history and redo a step', function() {
      history.saveEvent(new MockEvent());
      history.undo();
      expect(history.canUndo).toBeFalsy();
      history.redo();
      expect(history.canUndo).toBeTruthy();
    });
  });

  describe('this.canRedo', function() {
    it('is false on init', function() {
      history.init();
      expect(history.canRedo).toBeFalsy();
    });

    it('is true after we have undone an event', function() {
      history.saveEvent(new MockEvent());
      expect(history.canRedo).toBeFalsy();
      history.undo();
      expect(history.canRedo).toBeTruthy();
    });

    it('is false when we are at the beginning of the history chain again', function() {
      history.saveEvent(new MockEvent());
      expect(history.canRedo).toBeFalsy();
      history.undo();
      expect(history.canRedo).toBeTruthy();
      history.redo();
      expect(history.canRedo).toBeFalsy();
    });
  });

  describe('this.undo()', function() {
    it('calls undo function of current event in history', function() {
      history.saveEvent(new MockEvent());
      expect(undone).toEqual(0);
      history.undo();
      expect(undone).toEqual(1);
    });

    it('calls the undo function in state.silent mode', function() {
      var silentMode = true;
      // An undo function usually triggers a tokenChange
      state.on('tokenChange', function() { silentMode = false; });
      history.saveEvent(new MockEvent());
      history.undo();
      expect(silentMode).toBeTruthy();
    });
  });

  describe('this.redo()', function() {
    it('calls exec function of an undone element', function() {
      expect(undone).toEqual(0);
      expect(redone).toEqual(0);
      history.saveEvent(new MockEvent());

      history.undo();
      expect(undone).toEqual(1);
      history.redo();
      expect(redone).toEqual(1);
    });
  });

  describe('this.save()', function() {
    it('saves an event to the history', function() {
      expect(history.events.length).toEqual(0);
      history.saveEvent(new MockEvent());
      expect(history.events.length).toEqual(1);
    });

    it('does not save events in state.silent mode', function() {
      expect(history.events.length).toEqual(0);
      state.silent = true;
      history.saveEvent(new MockEvent());
      expect(history.events.length).toEqual(0);
    });

    it('never saves more items than defined throught history.maxSize', function() {
      history.maxSize = 2;
      history.saveEvent(new MockEvent());
      history.saveEvent(new MockEvent());
      expect(history.events.length).toEqual(2);
      history.saveEvent(new MockEvent());
      expect(history.events.length).toEqual(2);
    });

    it('pops the oldest history event when maxSize is reached', function() {
      var a, b, c;
      a = new MockEvent();
      b = new MockEvent();
      c = new MockEvent();

      history.maxSize = 2;

      history.saveEvent(a);
      history.saveEvent(b);
      expect(history.events).toContain(a);
      expect(history.events).toContain(b);

      history.saveEvent(c);
      expect(history.events).not.toContain(a);
      expect(history.events).toContain(b);
      expect(history.events).toContain(c);
    });

    it('does not act like a tree', function() {
      var a, b, c, d;
      a = new MockEvent();
      b = new MockEvent();
      c = new MockEvent();
      d = new MockEvent();

      history.saveEvent(a);
      history.saveEvent(b);
      history.saveEvent(c);

      history.undo(); // we're now at b again

      history.saveEvent(d);
      expect(history.events).toContain(a);
      expect(history.events).toContain(b);
      expect(history.events).not.toContain(c);
      expect(history.events).toContain(d);
    });
  });
});


@@ -5006,14 +5006,730 @@
 );%0A  %7D);
+%0A%0A  describe('watches', function() %7B%0A    it('all events issued through state.change and saves them', function() %7B%0A      var event = %7B property: 'head.id', newVal: 1, oldVal: 2 %7D;%0A%0A      expect(history.events.length).toEqual(0);%0A      state.change(%7B%7D, 'head.id', 1, 2);%0A      expect(history.events.length).toEqual(1);%0A    %7D);%0A%0A    it('all tokenAdded events', function() %7B%0A      expect(history.events.length).toEqual(0);%0A      state.broadcast('tokenAdded', %7B%7D);%0A      expect(history.events.length).toEqual(1);%0A    %7D);%0A%0A    it('all tokenRemoved events', function() %7B%0A      expect(history.events.length).toEqual(0);%0A      state.broadcast('tokenRemoved', %7B%7D);%0A      expect(history.events.length).toEqual(1);%0A    %7D);%0A  %7D);
 %0A%7D);%0A%0A

Add specs for history watches