(function (window) {
  DirectionEnum();
  window.ResizableFixedAspectBox = ResizableFixedAspectBox;

  /**
   * 固定宽高比的可调节尺寸盒子
   * @param {HTMLDivElement} element
   * @param {Object} config
   */
  function ResizableFixedAspectBox(element, config) {
    var el = element;
    var aspect = el.offsetWidth / el.offsetHeight;
    var aspectReverse = 1 / aspect; // 避免频繁的除法计算
    config = Object.assign(
      {
        top: true,
        right: true,
        bottom: true,
        left: true,
        topLeft: true,
        topRight: true,
        bottomRight: true,
        bottomLeft: true,
        isFlipVertical: false,
      },
      config || {},
    );
    var cfg = loadConfig();
    var direction = '';
    var positionX = null;
    var positionY = null;
    var targetWidth = el.offsetWidth;
    var targetHeight = el.offsetHeight;
    var handlers = initDirectionHandlers();

    this.updateConfig = function (data) {
      config = Object.assign(config, data);
      cfg = loadConfig();
    };

    this.init = function () {
      el.onmousemove = onTargetMouseMove;
      el.onmouseup = onTargetMouseUp;
      el.onmousedown = function (e) {
        el.onmousemove = null;
        updatePosition(e);

        if (cfg.dirctions.indexOf(direction) > -1) {
          startResizing();
        }
      };
    };
    this.uninit = function () {
      el.onmousedown = null;
      el.onmousemove = null;
    };

    function updatePosition(e) {
      positionX = e.clientX;
      positionY = e.clientY;
    }

    function onTargetMouseMove(e) {
      direction = checkStartDirection(e);
      if (!direction) {
        el.style.cursor = 'default';
      } else {
        el.style.cursor = direction + '-resize';
      }
    }
    function onTargetMouseUp(e) {
      el.onmousemove = onTargetMouseMove;
    }

    function startResizing() {
      // 鼠标事件交由document全局处理
      el.onmouseup = null;

      document.onmousemove = function (e) {
        var fn = handlers[direction];
        fn && fn(e);
        updatePosition(e);
      };
      document.onmouseup = function (e) {
        this.onmousemove = null;
        this.onmouseup = null;
        // 鼠标事件交还给目标element处理
        el.onmousemove = onTargetMouseMove;
        el.onmouseup = onTargetMouseUp;
      };
    }

    function initDirectionHandlers() {
      var map = {};
      // map[DirectionEnum.TOP] = topFn;
      map[DirectionEnum.RIGHT] = rightFn;
      map[DirectionEnum.BOTTOM] = bottomFn;
      map[DirectionEnum.LEFT] = leftFn;
      // map[DirectionEnum.TOP_LEFT] = topLeftFn;
      // map[DirectionEnum.TOP_RIGHT] = topRightFn;
      map[DirectionEnum.BOTTOM_RIGHT] = bottomRightFn;
      map[DirectionEnum.BOTTOM_LEFT] = bottomLeftFn;
      return map;
    }

    function topFn(e) {
      /* 暂不需要 */
    }
    function rightFn(e) {
      var width = el.offsetWidth + e.clientX - positionX;
      updateWidth(width);
    }
    function leftFn(e) {
      var increment = positionX - e.clientX;
      var width = el.offsetWidth + increment;
      updateWidth(width);
      // el.style.left = e.clientX + "px"; // 如果是左固定，动态更新left偏移量
    }
    function bottomFn(e) {
      var increment = e.clientY - positionY;
      var height = targetHeight + increment;
      updateHeight(height);
    }
    function topLeftFn(e) {
      /* 暂不需要 */
    }
    function topRightFn(e) {
      /* 暂不需要 */
    }
    function bottomRightFn(e) {
      rightFn(e);
    }
    function bottomLeftFn(e) {
      leftFn(e);
    }
    function updateWidth(val) {
      var w = limitW(val);
      var h = aspectReverse * w;
      var lh = limitH(h);
      if (lh != h) {
        h = lh;
        w = aspect * h;
      }
      updateSize(w, h);
    }
    function updateHeight(val) {
      var h = limitH(val);
      var w = aspect * h;
      var lw = limitW(w);
      if (lw != w) {
        w = lw;
        h = aspectReverse * w;
      }
      updateSize(w, h);
    }
    function updateSize(width, height) {
      targetWidth = width;
      targetHeight = height;
      el.style.width = width + 'px';
      el.style.height = height + 'px';
      cfg.onResize && cfg.onResize(width, height);
    }
    function limitW(val) {
      return Math.min(Math.max(cfg.minWidth, val), cfg.maxWidth);
    }
    function limitH(val) {
      return Math.min(Math.max(cfg.minHeight, val), cfg.maxHeight);
    }

    // 确定起始方向
    function checkStartDirection(e) {
      var x, y, offset, dir;
      dir = '';

      x = e.offsetX;
      y = e.offsetY;

      // 针对摄像头画面垂直翻转的情况，特殊处理
      if (config.isFlipVertical) {
        y = targetHeight - e.offsetY;
      }

      offset = 6;

      if (y <= 0 || x < 0 || y > targetHeight) {
        return dir;
      }

      if (y < offset) dir = 'n';
      else if (y > el.offsetHeight - offset) dir = 's';
      if (x < offset) dir = 'w';
      else if (x > el.offsetWidth - offset) dir = 'e';

      return dir;
    }

    function loadConfig() {
      var arr = [];
      checkDirection(config.top, DirectionEnum.TOP);
      checkDirection(config.right, DirectionEnum.RIGHT);
      checkDirection(config.bottom, DirectionEnum.BOTTOM);
      checkDirection(config.left, DirectionEnum.LEFT);
      checkDirection(config.topLeft, DirectionEnum.TOP_LEFT);
      checkDirection(config.topRight, DirectionEnum.TOP_RIGHT);
      checkDirection(config.bottomRight, DirectionEnum.BOTTOM_RIGHT);
      checkDirection(config.bottomLeft, DirectionEnum.BOTTOM_LEFT);

      cfg = {};
      cfg.dirctions = arr;
      cfg.minWidth = config.minWidth || 100;
      cfg.minHeight = config.minHeight || 100;
      cfg.maxWidth = config.maxWidth || el.parentElement.offsetWidth * 0.9;
      cfg.maxHeight =
        config.maxHeight ||
        (el.parentElement.offsetHeight || window.innerWidth) * 0.9;
      cfg.onResize = config.onResize;

      return cfg;

      function checkDirection(checked, value) {
        if (checked === true) {
          arr.push(value);
        }
      }
    }
  }

  function DirectionEnum() {
    // 映射为上北下南左西右东方向
    DirectionEnum.TOP = 'n';
    DirectionEnum.RIGHT = 'e';
    DirectionEnum.BOTTOM = 's';
    DirectionEnum.LEFT = 'w';
    DirectionEnum.TOP_LEFT = 'nw';
    DirectionEnum.TOP_RIGHT = 'ne';
    DirectionEnum.BOTTOM_RIGHT = 'se';
    DirectionEnum.BOTTOM_LEFT = 'sw';
  }
})(window);
