var Util = require('../../util');

var G = require('../../renderer');

var Group = G.Group;
var DomUtil = Util.DomUtil;
var OFFSET = 5;

var Range = function Range(cfg) {
  Range.superclass.constructor.call(this, cfg);
};

Util.extend(Range, Group);
Util.augment(Range, {
  getDefaultCfg: function getDefaultCfg() {
    return {
      /**
       * 范围
       * @type {Array}
       */
      range: null,

      /**
       * 中滑块属性
       * @type {ATTRS}
       */
      middleAttr: null,

      /**
       * 背景
       * @type {G-Element}
       */
      backgroundElement: null,

      /**
       * 下滑块
       * @type {G-Element}
       */
      minHandleElement: null,

      /**
       * 上滑块
       * @type {G-Element}
       */
      maxHandleElement: null,

      /**
       * 中块
       * @type {G-Element}
       */
      middleHandleElement: null,

      /**
       * 当前的激活的元素
       * @type {G-Element}
       */
      currentTarget: null,

      /**
       * 布局方式： horizontal，vertical
       * @type {String}
       */
      layout: 'vertical',

      /**
       * 宽
       * @type {Number}
       */
      width: null,

      /**
       * 高
       * @type {Number}
       */
      height: null,

      /**
       * 当前的PageX
       * @type {Number}
       */
      pageX: null,

      /**
       * 当前的PageY
       * @type {Number}
       */
      pageY: null
    };
  },
  _initHandle: function _initHandle(type) {
    var self = this;
    var handle = self.addGroup();
    var layout = self.get('layout');
    var handleStyle = self.get('handleStyle');
    var img = handleStyle.img;
    var iconWidth = handleStyle.width;
    var iconHeight = handleStyle.height;
    var text;
    var handleIcon;
    var triggerCursor;

    if (layout === 'horizontal') {
      var _iconWidth = handleStyle.width;
      triggerCursor = 'ew-resize';
      handleIcon = handle.addShape('Image', {
        attrs: {
          x: -_iconWidth / 2,
          y: 0,
          width: _iconWidth,
          height: iconHeight,
          img: img,
          cursor: triggerCursor
        }
      });
      text = handle.addShape('Text', {
        attrs: Util.mix({
          x: type === 'min' ? -(_iconWidth / 2 + OFFSET) : _iconWidth / 2 + OFFSET,
          y: iconHeight / 2,
          textAlign: type === 'min' ? 'end' : 'start',
          textBaseline: 'middle',
          text: type === 'min' ? this.get('minText') : this.get('maxText'),
          cursor: triggerCursor
        }, this.get('textStyle'))
      });
    } else {
      triggerCursor = 'ns-resize';
      handleIcon = handle.addShape('Image', {
        attrs: {
          x: 0,
          y: -iconHeight / 2,
          width: iconWidth,
          height: iconHeight,
          img: img,
          cursor: triggerCursor
        }
      });
      text = handle.addShape('Text', {
        attrs: Util.mix({
          x: iconWidth / 2,
          y: type === 'min' ? iconHeight / 2 + OFFSET : -(iconHeight / 2 + OFFSET),
          textAlign: 'center',
          textBaseline: 'middle',
          text: type === 'min' ? this.get('minText') : this.get('maxText'),
          cursor: triggerCursor
        }, this.get('textStyle'))
      });
    }

    this.set(type + 'TextElement', text);
    this.set(type + 'IconElement', handleIcon);
    return handle;
  },
  _initSliderBackground: function _initSliderBackground() {
    var backgroundElement = this.addGroup();
    backgroundElement.initTransform();
    backgroundElement.translate(0, 0);
    backgroundElement.addShape('Rect', {
      attrs: Util.mix({
        x: 0,
        y: 0,
        width: this.get('width'),
        height: this.get('height')
      }, this.get('backgroundStyle'))
    });
    return backgroundElement;
  },
  _beforeRenderUI: function _beforeRenderUI() {
    var backgroundElement = this._initSliderBackground();

    var minHandleElement = this._initHandle('min');

    var maxHandleElement = this._initHandle('max');

    var middleHandleElement = this.addShape('rect', {
      attrs: this.get('middleAttr')
    });
    this.set('middleHandleElement', middleHandleElement);
    this.set('minHandleElement', minHandleElement);
    this.set('maxHandleElement', maxHandleElement);
    this.set('backgroundElement', backgroundElement);
    backgroundElement.set('zIndex', 0);
    middleHandleElement.set('zIndex', 1);
    minHandleElement.set('zIndex', 2);
    maxHandleElement.set('zIndex', 2);
    middleHandleElement.attr('cursor', 'move');
    this.sort();
  },
  _renderUI: function _renderUI() {
    if (this.get('layout') === 'horizontal') {
      this._renderHorizontal();
    } else {
      this._renderVertical();
    }
  },
  _transform: function _transform(layout) {
    var range = this.get('range');
    var minRatio = range[0] / 100;
    var maxRatio = range[1] / 100;
    var width = this.get('width');
    var height = this.get('height');
    var minHandleElement = this.get('minHandleElement');
    var maxHandleElement = this.get('maxHandleElement');
    var middleHandleElement = this.get('middleHandleElement');

    if (minHandleElement.resetMatrix) {
      minHandleElement.resetMatrix();
      maxHandleElement.resetMatrix();
    } else {
      minHandleElement.initTransform();
      maxHandleElement.initTransform();
    }

    if (layout === 'horizontal') {
      middleHandleElement.attr({
        x: width * minRatio,
        y: 0,
        width: (maxRatio - minRatio) * width,
        height: height
      });
      minHandleElement.translate(minRatio * width, 0);
      maxHandleElement.translate(maxRatio * width, 0);
    } else {
      middleHandleElement.attr({
        x: 0,
        y: height * (1 - maxRatio),
        width: width,
        height: (maxRatio - minRatio) * height
      });
      minHandleElement.translate(0, (1 - minRatio) * height);
      maxHandleElement.translate(0, (1 - maxRatio) * height);
    }
  },
  _renderHorizontal: function _renderHorizontal() {
    this._transform('horizontal');
  },
  _renderVertical: function _renderVertical() {
    this._transform('vertical');
  },
  _bindUI: function _bindUI() {
    this.on('mousedown', Util.wrapBehavior(this, '_onMouseDown'));
  },
  _isElement: function _isElement(target, name) {
    // 判断是否是该元素
    var element = this.get(name);

    if (target === element) {
      return true;
    }

    if (element.isGroup) {
      var elementChildren = element.get('children');
      return elementChildren.indexOf(target) > -1;
    }

    return false;
  },
  _getRange: function _getRange(diff, range) {
    var rst = diff + range;
    rst = rst > 100 ? 100 : rst;
    rst = rst < 0 ? 0 : rst;
    return rst;
  },
  _limitRange: function _limitRange(diff, limit, range) {
    range[0] = this._getRange(diff, range[0]);
    range[1] = range[0] + limit;

    if (range[1] > 100) {
      range[1] = 100;
      range[0] = range[1] - limit;
    }
  },
  _updateStatus: function _updateStatus(dim, ev) {
    var totalLength = dim === 'x' ? this.get('width') : this.get('height');
    dim = Util.upperFirst(dim);
    var range = this.get('range');
    var page = this.get('page' + dim);
    var currentTarget = this.get('currentTarget');
    var rangeStash = this.get('rangeStash');
    var layout = this.get('layout');
    var sign = layout === 'vertical' ? -1 : 1;
    var currentPage = ev['page' + dim];
    var diffPage = currentPage - page;
    var diffRange = diffPage / totalLength * 100 * sign;
    var diffStashRange;
    var minRange = this.get('minRange');
    var maxRange = this.get('maxRange');

    if (range[1] <= range[0]) {
      if (this._isElement(currentTarget, 'minHandleElement') || this._isElement(currentTarget, 'maxHandleElement')) {
        range[0] = this._getRange(diffRange, range[0]);
        range[1] = this._getRange(diffRange, range[0]);
      }
    } else {
      if (this._isElement(currentTarget, 'minHandleElement')) {
        range[0] = this._getRange(diffRange, range[0]);

        if (minRange) {
          // 设置了最小范围
          if (range[1] - range[0] <= minRange) {
            this._limitRange(diffRange, minRange, range);
          }
        }

        if (maxRange) {
          // 设置了最大范围
          if (range[1] - range[0] >= maxRange) {
            this._limitRange(diffRange, maxRange, range);
          }
        }
      }

      if (this._isElement(currentTarget, 'maxHandleElement')) {
        range[1] = this._getRange(diffRange, range[1]);

        if (minRange) {
          // 设置了最小范围
          if (range[1] - range[0] <= minRange) {
            this._limitRange(diffRange, minRange, range);
          }
        }

        if (maxRange) {
          // 设置了最大范围
          if (range[1] - range[0] >= maxRange) {
            this._limitRange(diffRange, maxRange, range);
          }
        }
      }
    }

    if (this._isElement(currentTarget, 'middleHandleElement')) {
      diffStashRange = rangeStash[1] - rangeStash[0];

      this._limitRange(diffRange, diffStashRange, range);
    }

    this.emit('sliderchange', {
      range: range
    });
    this.set('page' + dim, currentPage);

    this._renderUI();

    this.get('canvas').draw(); // need delete

    return;
  },
  _onMouseDown: function _onMouseDown(ev) {
    var currentTarget = ev.currentTarget;
    var originEvent = ev.event;
    var range = this.get('range');
    originEvent.stopPropagation();
    originEvent.preventDefault();
    this.set('pageX', originEvent.pageX);
    this.set('pageY', originEvent.pageY);
    this.set('currentTarget', currentTarget);
    this.set('rangeStash', [range[0], range[1]]);

    this._bindCanvasEvents();
  },
  _bindCanvasEvents: function _bindCanvasEvents() {
    var containerDOM = this.get('canvas').get('containerDOM');
    this.onMouseMoveListener = DomUtil.addEventListener(containerDOM, 'mousemove', Util.wrapBehavior(this, '_onCanvasMouseMove'));
    this.onMouseUpListener = DomUtil.addEventListener(containerDOM, 'mouseup', Util.wrapBehavior(this, '_onCanvasMouseUp')); // @2018-06-06 by blue.lb 添加mouseleave事件监听，让用户在操作出滑块区域后有一个“正常”的效果，可以正常重新触发滑块的操作流程

    this.onMouseLeaveListener = DomUtil.addEventListener(containerDOM, 'mouseleave', Util.wrapBehavior(this, '_onCanvasMouseUp'));
  },
  _onCanvasMouseMove: function _onCanvasMouseMove(ev) {
    var layout = this.get('layout');

    if (layout === 'horizontal') {
      this._updateStatus('x', ev);
    } else {
      this._updateStatus('y', ev);
    }
  },
  _onCanvasMouseUp: function _onCanvasMouseUp() {
    this._removeDocumentEvents();
  },
  _removeDocumentEvents: function _removeDocumentEvents() {
    this.onMouseMoveListener.remove();
    this.onMouseUpListener.remove();
    this.onMouseLeaveListener.remove();
  }
});
module.exports = Range;