export default {
  data() {
    return {
      deviation: 5, // 对齐误差范围
      xLines: [],
      yLines: [],
    };
  },
  methods: {
    getMax(arr) {
      return Math.max.apply(null, arr);
    },
    getMin(arr) {
      return Math.min.apply(null, arr);
    },
    getPoints(item) {
      // 权重关系：先左后右
      // 具体：左上 > 左下 > 中心 > 右上 > 右下
      return [
        { x: item.x, y: item.y },
        { x: item.x, y: item.y + item.h },
        { x: item.x + item.w / 2, y: item.y + item.h / 2 },
        { x: item.x + item.w, y: item.y },
        { x: item.x + item.w, y: item.y + item.h },
      ];
    },
    rebuild(elements, curElement, actionType = "move") {
      this.clear();
      const curPoints = this.getPoints(curElement);
      const envPoints = elements
        .filter((item) => item.id !== curElement.id)
        .map((item) => this.getPoints(item));
      let fitPoints = [];
      // 提取可能的辅助线
      // y线分三种：左中右
      // x线分三种：上中下
      let xMaybeLines = {},
        yMaybeLines = {};
      const yPointTypes = {
        0: "left",
        1: "left",
        2: "center",
        3: "right",
        4: "right",
      };
      const xPointTypes = {
        0: "top",
        1: "bottom",
        2: "center",
        3: "top",
        4: "bottom",
      };
      envPoints.forEach((points) => {
        points.forEach((point, pindex) => {
          // 中心点的对齐误差值取半数误差值
          const deviation = pindex === 2 ? this.deviation / 2 : this.deviation;
          const curPoint = curPoints[pindex];
          if (
            curPoint.x <= point.x + deviation &&
            curPoint.x >= point.x - deviation
          ) {
            if (!yMaybeLines[yPointTypes[pindex]])
              yMaybeLines[yPointTypes[pindex]] = [];
            yMaybeLines[yPointTypes[pindex]].push({
              pindex,
              x: point.x,
              y: Math.min(curPoint.y, point.y),
              h: Math.abs(curPoint.y - point.y),
              offset: Math.abs(curPoint.x - point.x),
            });
          }
          if (
            curPoint.y <= point.y + deviation &&
            curPoint.y >= point.y - deviation
          ) {
            if (!xMaybeLines[xPointTypes[pindex]])
              xMaybeLines[xPointTypes[pindex]] = [];
            xMaybeLines[xPointTypes[pindex]].push({
              pindex,
              x: Math.min(curPoint.x, point.x),
              y: point.y,
              w: Math.abs(curPoint.x - point.x),
              offset: Math.abs(curPoint.y - point.y),
            });
          }
        });
      });
      // 过滤误差过大的辅助线，即取误差最小的辅助线
      let yLines = [];
      Object.values(yMaybeLines).forEach((lines) => {
        lines.sort((a, b) => a.offset - b.offset);
        const validX = lines[0].x;
        const validLines = lines.filter((line) => line.x === validX);
        validLines.forEach((line) => {
          const pindex = line.pindex;
          if (!fitPoints[pindex]) fitPoints[pindex] = {};
          fitPoints[pindex].x = validX;
        });
        yLines = [...yLines, ...validLines];
      });
      let xLines = [];
      Object.values(xMaybeLines).forEach((lines) => {
        lines.sort((a, b) => a.offset - b.offset);
        const validY = lines[0].y;
        const validLines = lines.filter((line) => line.y === validY);
        validLines.forEach((line) => {
          const pindex = line.pindex;
          if (!fitPoints[pindex]) fitPoints[pindex] = {};
          fitPoints[pindex].y = validY;
        });
        xLines = [...xLines, ...validLines];
      });

      // 合并辅助线
      let yLinesMap = {};
      yLines.forEach((line) => {
        if (!yLinesMap[line.x]) yLinesMap[line.x] = [];
        yLinesMap[line.x].push(line);
      });
      this.yLines = Object.values(yLinesMap).map((lines) => {
        const lowH = this.getMax(lines.map((l) => l.y + l.h));
        const topY = this.getMin(lines.map((l) => l.y));
        return {
          left: lines[0].x + "px",
          top: topY + "px",
          height: lowH - topY + "px",
        };
      });
      let xLinesMap = {};
      xLines.forEach((line) => {
        if (!xLinesMap[line.y]) xLinesMap[line.y] = [];
        xLinesMap[line.y].push(line);
      });
      this.xLines = Object.values(xLinesMap).map((lines) => {
        const rightW = this.getMax(lines.map((l) => l.x + l.w));
        const leftX = this.getMin(lines.map((l) => l.x));
        return {
          left: leftX + "px",
          top: lines[0].y + "px",
          width: rightW - leftX + "px",
        };
      });

      // 计算自动贴合后的坐标点
      if (actionType === "move") {
        // 移动模式时，算偏移量
        // 按照getPoints中设置的点顺序权重进行计算
        // 只要获得结果，便停止计算
        let xOffset = null,
          yOffset = null;
        curPoints.forEach((point, pindex) => {
          const fitPoint = fitPoints[pindex] || {};
          if (xOffset === null && fitPoint.x) {
            xOffset = fitPoint.x - point.x;
          }
          if (yOffset === null && fitPoint.y) {
            yOffset = fitPoint.y - point.y;
          }
        });
        return {
          x: curElement.x + xOffset,
          y: curElement.y + yOffset,
          w: curElement.w,
          h: curElement.h,
        };
      } else {
        // 变形模式时，算贴合点
        const newPoints = curPoints.map((point, pindex) => {
          const fitPoint = fitPoints[pindex] || {};
          return {
            x: Object.prototype.hasOwnProperty.call(fitPoint, "x")
              ? fitPoint.x
              : point.x,
            y: Object.prototype.hasOwnProperty.call(fitPoint, "y")
              ? fitPoint.y
              : point.y,
          };
        });
        return {
          x: newPoints[0].x,
          y: newPoints[0].y,
          w: newPoints[4].x - newPoints[0].x,
          h: newPoints[4].y - newPoints[0].y,
        };
      }
    },
    clear() {
      this.xLines = [];
      this.yLines = [];
    },
  },
};
