/**
 * @fileOverview 自定义的 shape
 * @author dxq613@gmail.com
 * @author sima.zhang1990@gmail.com
 */

const Util = require('../../util');
const Shape = require('./shape');
const ShapeUtil = require('../util/shape');
const Global = require('../../global');

function _parseValue(value) {
  if (!Util.isArray(value)) {
    value = [ value ];
  }
  const min = value[0]; // 最小值
  const max = value[value.length - 1]; // 最大值
  const min1 = value.length > 1 ? value[1] : min;
  const max1 = value.length > 3 ? value[3] : max;
  const median = value.length > 2 ? value[2] : min1;

  return {
    min, // 最小值
    max, // 最大值
    min1,
    max1,
    median
  };
}

function addPoints(from, to) {
  Util.each(from, subArr => {
    to.push({
      x: subArr[0],
      y: subArr[1]
    });
  });
}

function getAttrs(cfg) {
  const defaultAttrs = Global.shape.schema;
  const lineAttrs = Util.mix({}, defaultAttrs, cfg.style);
  ShapeUtil.addStrokeAttrs(lineAttrs, cfg);
  return lineAttrs;
}

function getFillAttrs(cfg) {
  const defaultAttrs = Global.shape.schema;
  const lineAttrs = Util.mix({}, defaultAttrs, cfg.style);
  ShapeUtil.addFillAttrs(lineAttrs, cfg);
  if (cfg.color) {
    lineAttrs.stroke = cfg.color || lineAttrs.stroke;
  }
  return lineAttrs;
}

function getBoxPoints(x, y, width) {
  const points = [];
  let pointsArray;
  let obj;
  if (Util.isArray(y)) { // 2维
    obj = _parseValue(y);
    pointsArray = [
      [ x - width / 2, obj.max ],
      [ x + width / 2, obj.max ],
      [ x, obj.max ],
      [ x, obj.max1 ],
      [ x - width / 2, obj.min1 ],
      [ x - width / 2, obj.max1 ],
      [ x + width / 2, obj.max1 ],
      [ x + width / 2, obj.min1 ],
      [ x, obj.min1 ],
      [ x, obj.min ],
      [ x - width / 2, obj.min ],
      [ x + width / 2, obj.min ],
      [ x - width / 2, obj.median ],
      [ x + width / 2, obj.median ]
    ];
  } else { // 只有一个维度
    y = y || 0.5;
    obj = _parseValue(x);
    pointsArray = [
      [ obj.min, y - width / 2 ],
      [ obj.min, y + width / 2 ],
      [ obj.min, y ],
      [ obj.min1, y ],
      [ obj.min1, y - width / 2 ],
      [ obj.min1, y + width / 2 ],
      [ obj.max1, y + width / 2 ],
      [ obj.max1, y - width / 2 ],
      [ obj.max1, y ],
      [ obj.max, y ],
      [ obj.max, y - width / 2 ],
      [ obj.max, y + width / 2 ],
      [ obj.median, y - width / 2 ],
      [ obj.median, y + width / 2 ]
    ];
  }
  addPoints(pointsArray, points);
  return points;
}

function _sortValue(value) {
  if (!Util.isArray(value)) {
    value = [ value ];
  }
  // 从大到小排序
  const sorted = value.sort((a, b) => (a < b ? 1 : -1));

  const length = sorted.length;
  if (length < 4) {
    const min = sorted[length - 1];
    for (let i = 0; i < (4 - length); i++) {
      sorted.push(min);
    }
  }

  return sorted;
}

// 获取K线图的points
function getCandlePoints(x, y, width) {
  const yValues = _sortValue(y);
  const points = [{
    x,
    y: yValues[0]
  }, {
    x,
    y: yValues[1]
  }, {
    x: x - width / 2,
    y: yValues[2]
  }, {
    x: x - width / 2,
    y: yValues[1]
  }, {
    x: x + width / 2,
    y: yValues[1]
  }, {
    x: x + width / 2,
    y: yValues[2]
  }, {
    x,
    y: yValues[2]
  }, {
    x,
    y: yValues[3]
  }]; // 按照顺时针连接
  return points;
}

function getBoxPath(points) {
  const path = [
    [ 'M', points[0].x, points[0].y ],
    [ 'L', points[1].x, points[1].y ],
    [ 'M', points[2].x, points[2].y ],
    [ 'L', points[3].x, points[3].y ],
    [ 'M', points[4].x, points[4].y ],
    [ 'L', points[5].x, points[5].y ],
    [ 'L', points[6].x, points[6].y ],
    [ 'L', points[7].x, points[7].y ],
    [ 'L', points[4].x, points[4].y ], // 封闭 z
    [ 'Z' ],
    [ 'M', points[8].x, points[8].y ],
    [ 'L', points[9].x, points[9].y ],
    [ 'M', points[10].x, points[10].y ],
    [ 'L', points[11].x, points[11].y ],
    [ 'M', points[12].x, points[12].y ],
    [ 'L', points[13].x, points[13].y ]
  ];
  return path;
}

function getCandlePath(points) {
  const path = [
    [ 'M', points[0].x, points[0].y ],
    [ 'L', points[1].x, points[1].y ],
    [ 'M', points[2].x, points[2].y ],
    [ 'L', points[3].x, points[3].y ],
    [ 'L', points[4].x, points[4].y ],
    [ 'L', points[5].x, points[5].y ],
    [ 'Z' ],
    [ 'M', points[6].x, points[6].y ],
    [ 'L', points[7].x, points[7].y ]
  ];
  return path;
}

const Schema = Shape.registerFactory('schema', {
  defaultShapeType: '',
  getActiveCfg(type, cfg) {
    if (type === 'box') {
      const lineWidth = cfg.lineWidth || 1;
      return {
        lineWidth: lineWidth + 1
      };
    }
    const opacity = cfg.fillOpacity || cfg.opacity || 1;
    return {
      fillOpacity: opacity - 0.15,
      strokeOpacity: opacity - 0.15
    };
  },
  getSelectedCfg(type, cfg) {
    if (cfg && cfg.style) {
      return cfg.style;
    }
    return this.getActiveCfg(type, cfg);
  }
});

// 箱线图
Shape.registerShape('schema', 'box', {
  getPoints(pointInfo) {
    return getBoxPoints(pointInfo.x, pointInfo.y, pointInfo.size);
  },
  draw(cfg, container) {
    const attrs = getAttrs(cfg);
    let path = getBoxPath(cfg.points);
    path = this.parsePath(path);
    return container.addShape('path', {
      attrs: Util.mix(attrs, {
        path
      })
    });
  },
  getMarkerCfg(cfg) {
    return {
      symbol(x, y, r) {
        const yValues = [ y - 6, y - 3, y, y + 3, y + 6 ];
        const points = getBoxPoints(x, yValues, r);
        return [
          [ 'M', points[0].x + 1, points[0].y ],
          [ 'L', points[1].x - 1, points[1].y ],
          [ 'M', points[2].x, points[2].y ],
          [ 'L', points[3].x, points[3].y ],
          [ 'M', points[4].x, points[4].y ],
          [ 'L', points[5].x, points[5].y ],
          [ 'L', points[6].x, points[6].y ],
          [ 'L', points[7].x, points[7].y ],
          [ 'L', points[4].x, points[4].y ],
          [ 'Z' ],
          [ 'M', points[8].x, points[8].y ],
          [ 'L', points[9].x, points[9].y ],
          [ 'M', points[10].x + 1, points[10].y ],
          [ 'L', points[11].x - 1, points[11].y ],
          [ 'M', points[12].x, points[12].y ],
          [ 'L', points[13].x, points[13].y ]
        ];
      },
      radius: 6,
      lineWidth: 1,
      stroke: cfg.color
    };
  }
});

// K线
Shape.registerShape('schema', 'candle', {
  getPoints(pointInfo) {
    return getCandlePoints(pointInfo.x, pointInfo.y, pointInfo.size);
  },
  draw(cfg, container) {
    const attrs = getFillAttrs(cfg);
    let path = getCandlePath(cfg.points);
    path = this.parsePath(path);
    return container.addShape('path', {
      attrs: Util.mix(attrs, {
        path
      })
    });
  },
  getMarkerCfg(cfg) {
    return {
      symbol(x, y, r) {
        y = [ y + 7.5, y + 3, y - 3, y - 7.5 ];
        const points = getCandlePoints(x, y, r);
        return [
          [ 'M', points[0].x, points[0].y ],
          [ 'L', points[1].x, points[1].y ],
          [ 'M', points[2].x, points[2].y ],
          [ 'L', points[3].x, points[3].y ],
          [ 'L', points[4].x, points[4].y ],
          [ 'L', points[5].x, points[5].y ],
          [ 'Z' ],
          [ 'M', points[6].x, points[6].y ],
          [ 'L', points[7].x, points[7].y ]
        ];
      },
      lineWidth: 1,
      stroke: cfg.color,
      fill: cfg.color,
      radius: 6
    };
  }
});

module.exports = Schema;
