'use strict';

/**
 * @ignore
 * @class L.HistoryControl
 * @classdesc
 * @extends {L.Control}
 */
(function() {
  L.HistoryControl = L.Control.extend({
    options: {
      maxMovesToSave: 20, //set to 0 for unlimited
      shouldSaveMoveInHistory: function() {
        return true;
      } //by default save everything
    },

    initialize: function(map, options) {
      L.Util.setOptions(this, options);

      this._map = map;
      this._shouldSave = true;  // 是否需要记录操作 前图、后图操作的时候不需要记录,否则需要记录
      this._state.maxMovesToSave = this.options.maxMovesToSave;

      this._updateDisabled();
      this._rnothtmlwhite = (/[^\x20\t\r\n\f]+/g);
      // this.addMapListeners();
    },

    onRemove: function(map) {
      map.off('movestart');
    },

    performActionWithoutTriggeringEvent: function(action) {
      var ignoring = this._state.ignoringEvents;
      this._state.ignoringEvents = true;
      if (this._isFunction(action)) {
        action();
      }
      this._state.ignoringEvents = ignoring;
    },

    moveWithoutTriggeringEvent: function(zoomCenter) {
      var _this = this;
      this.performActionWithoutTriggeringEvent(function() {
        _this._map.setView(zoomCenter.centerPoint, zoomCenter.zoom);
      });
    },

    goBack: function() {
      return this._invokeBackOrForward('historyback', this._state.history, this._state.future);
    },

    goForward: function() {
      return this._invokeBackOrForward('historyforward', this._state.future, this._state.history);
    },

    clearHistory: function() {
      this._state.history.items = [];
      this._updateDisabled();
    },

    clearFuture: function() {
      this._state.future.items = [];
      this._updateDisabled();
    },

    _map: null,
    _state: {
      backDisabled: null,
      forwardDisabled: null,
      ignoringEvents: false,
      maxMovesToSave: 0,
      history: {
        items: []
      },
      future: {
        items: []
      }
    },

    _updateDisabled: function() {
      var backDisabled = (this._state.history.items.length === 0);
      var forwardDisabled = (this._state.future.items.length === 0);
      if (backDisabled !== this._state.backDisabled) {
        this._state.backDisabled = backDisabled;
        this._map.fire('historyback' + (backDisabled ? 'disabled' : 'enabled'));
      }
      if (forwardDisabled !== this._state.forwardDisabled) {
        this._state.forwardDisabled = forwardDisabled;
        this._map.fire('historyforward' + (forwardDisabled ? 'disabled' : 'enabled'));
      }
      if (!this.options.useExternalControls) {
        this._setButtonDisabled(this._backButton, backDisabled);
        this._setButtonDisabled(this._forwardButton, forwardDisabled);
      }
    },
    _setButtonDisabled: function(button, condition) {
      if (button) {
        var $button = document.querySelector(button);
        var className = 'leaflet-disabled';
        if (condition) {
          this._addClass($button, className);
        } else {
          this._removeClass($button, className);
        }
      }
    },
    _pop: function(stack) {
      stack = stack.items;
      if (Array.isArray(stack) && stack.length > 0) {
        return stack.splice(stack.length - 1, 1)[0];
      }
      return undefined;
    },
    _push: function(stack, value) {
      var maxLength = this._state.maxMovesToSave;
      stack = stack.items;
      if (Array.isArray(stack)) {
        stack.push(value);
        if (maxLength > 0 && stack.length > maxLength) {
          stack.splice(0, 1);
        }
      }
    },

    _invokeBackOrForward: function(eventName, stackToPop, stackToPushCurrent) {
      var self = this;

      // 设置_shouldSave标志, 200毫秒后，自动重置为需要记录操作
      self._shouldSave = false;
      setTimeout(function() {
        self._shouldSave = true;
      }, 200);

      var response = this._popStackAndUseLocation(stackToPop, stackToPushCurrent);
      if (response) {
        this._map.fire(eventName, response);
        return true;
      }

      return false;
    },

    _popStackAndUseLocation: function(stackToPop, stackToPushCurrent) {
      //check if we can pop
      if (Array.isArray(stackToPop.items) && stackToPop.items.length > 0) {
        var current = this._buildZoomCenterObjectFromCurrent(this._map);
        //get most recent
        var previous = this._pop(stackToPop);
        //save where we currently are in the 'other' stack
        this._push(stackToPushCurrent, current);
        this.moveWithoutTriggeringEvent(previous);

        return {
          previousLocation: previous,
          currentLocation: current
        };
      }
    },

    _buildZoomCenterObjectFromCurrent: function(map) {
      return new L.ZoomCenter(map.getZoom(), map.getCenter());
    },

    addMapListeners: function() {
      var self = this;
      this._map.on('movestart', function(e) {
        if (!self._state.ignoringEvents) {

          var current = self._buildZoomCenterObjectFromCurrent(e.target);
          if (self.options.shouldSaveMoveInHistory(current) && self._shouldSave) {
            self._state.future.items = [];
            self._push(self._state.history, current);
          }
        }

        self._updateDisabled();
      });
    },
    /**
     * @private
     * @function L.HistoryControl.prototype._isFunction
     * @description 判断是否为函数
     */
    _isFunction(obj) {
      return typeof obj === 'function' && typeof obj.nodeType !== 'number' &&
        typeof obj.item !== 'function';
    },
    /**
     * @private
     * @function L.HistoryControl.prototype._addClass
     * @description dom 添加 classname
     */
    _addClass(dom, className) {
      var classes = this._classesToArray(className);
      var curValue = this._getClass(dom);
      var cur = dom.nodeType === 1 && (' ' + this._stripAndCollapse(curValue) + ' ');
      var clazz, j, finalValue;
      if (cur) {
        j = 0;
        while ((clazz = classes[j++])) {
          if (cur.indexOf(' ' + clazz + ' ') < 0) {
            cur += clazz + ' ';
          }
        }
        finalValue = this._stripAndCollapse(cur);
        if (curValue !== finalValue) {
          dom.setAttribute('class', finalValue);
        }
      }
    },
    /**
     * @private
     * @function L.HistoryControl.prototype._removeClass
     * @description dom 删除 classname
     */
    _removeClass(dom, className) {
      var classes = this._classesToArray(className);
      var curValue = this._getClass(dom);
      var cur = cur = dom.nodeType === 1 && (' ' + this._stripAndCollapse(curValue) + ' ');
      var clazz, j, finalValue;
      if (cur) {
        j = 0;
        while ((clazz = classes[j++])) {

          while (cur.indexOf(' ' + clazz + ' ') > -1) {
            cur = cur.replace(' ' + clazz + ' ', ' ');
          }
        }

        finalValue = this._stripAndCollapse(cur);
        if (curValue !== finalValue) {
          dom.setAttribute('class', finalValue);
        }
      }
    },
    /**
     * @private
     * @function L.HistoryControl.prototype._classesToArray
     * @description classname 转为 数组
     */
    _classesToArray(value) {
      if (Array.isArray(value)) {
        return value;
      }
      if (typeof value === 'string') {
        return value.match(this._rnothtmlwhite) || [];
      }
      return [];
    },
    /**
     * @private
     * @function L.HistoryControl.prototype._getClass
     * @description 获取classname
     */
    _getClass(elem) {
      return elem.getAttribute && elem.getAttribute('class') || '';
    },
    /**
     * @private
     * @function L.HistoryControl.prototype._stripAndCollapse
     */
    _stripAndCollapse(value) {
      var tokens = value.match(this._rnothtmlwhite) || [];
      return tokens.join(' ');
    }
  });

  L.HistoryControl.getInstance = function(map, options) {
    if (!L.HistoryControl.instance) {
      L.HistoryControl.instance = new L.HistoryControl(map, options);
    }

    return L.HistoryControl.instance;
  };
}());

(function() {
  L.ZoomCenter = L.Class.extend({
    initialize: function(zoom, centerPoint) {
      this.zoom = zoom;
      this.centerPoint = centerPoint;
    }
  });
}());
