import * as echarts from 'echarts/lib/echarts';
import { createTextStyle } from 'echarts/lib/label/labelStyle';
import graphicGL from '../../util/graphicGL';
import Lines3DGeometry from '../../util/geometry/Lines3D';
import retrieve from '../../util/retrieve';
import LabelsMesh from '../../util/mesh/LabelsMesh';
var firstNotNull = retrieve.firstNotNull;
var dimIndicesMap = {
  // Left to right
  x: 0,
  // Far to near
  y: 2,
  // Bottom to up
  z: 1
};

function Grid3DAxis(dim, linesMaterial) {
  var linesMesh = new graphicGL.Mesh({
    geometry: new Lines3DGeometry({
      useNativeLine: false
    }),
    material: linesMaterial,
    castShadow: false,
    ignorePicking: true,
    renderOrder: 2
  });
  var axisLabelsMesh = new LabelsMesh();
  axisLabelsMesh.material.depthMask = false;
  var rootNode = new graphicGL.Node();
  rootNode.add(linesMesh);
  rootNode.add(axisLabelsMesh);
  this.rootNode = rootNode;
  this.dim = dim;
  this.linesMesh = linesMesh;
  this.labelsMesh = axisLabelsMesh;
  this.axisLineCoords = null;
  this.labelElements = [];
}

var otherDim = {
  x: 'y',
  y: 'x',
  z: 'y'
};

Grid3DAxis.prototype.update = function (grid3DModel, axisLabelSurface, api) {
  var cartesian = grid3DModel.coordinateSystem;
  var axis = cartesian.getAxis(this.dim);
  var linesGeo = this.linesMesh.geometry;
  var labelsGeo = this.labelsMesh.geometry;
  linesGeo.convertToDynamicArray(true);
  labelsGeo.convertToDynamicArray(true);
  var axisModel = axis.model;
  var extent = axis.getExtent();
  var dpr = api.getDevicePixelRatio();
  var axisLineModel = axisModel.getModel('axisLine', grid3DModel.getModel('axisLine'));
  var axisTickModel = axisModel.getModel('axisTick', grid3DModel.getModel('axisTick'));
  var axisLabelModel = axisModel.getModel('axisLabel', grid3DModel.getModel('axisLabel'));
  var axisLineColor = axisLineModel.get('lineStyle.color'); // Render axisLine

  if (axisLineModel.get('show')) {
    var axisLineStyleModel = axisLineModel.getModel('lineStyle');
    var p0 = [0, 0, 0];
    var p1 = [0, 0, 0];
    var idx = dimIndicesMap[axis.dim];
    p0[idx] = extent[0];
    p1[idx] = extent[1]; // Save some useful info.

    this.axisLineCoords = [p0, p1];
    var color = graphicGL.parseColor(axisLineColor);
    var lineWidth = firstNotNull(axisLineStyleModel.get('width'), 1.0);
    var opacity = firstNotNull(axisLineStyleModel.get('opacity'), 1.0);
    color[3] *= opacity;
    linesGeo.addLine(p0, p1, color, lineWidth * dpr);
  } // Render axis ticksCoords


  if (axisTickModel.get('show')) {
    var lineStyleModel = axisTickModel.getModel('lineStyle');
    var lineColor = graphicGL.parseColor(firstNotNull(lineStyleModel.get('color'), axisLineColor));
    var lineWidth = firstNotNull(lineStyleModel.get('width'), 1.0);
    lineColor[3] *= firstNotNull(lineStyleModel.get('opacity'), 1.0);
    var ticksCoords = axis.getTicksCoords();
    var tickLength = axisTickModel.get('length');

    for (var i = 0; i < ticksCoords.length; i++) {
      var tickCoord = ticksCoords[i].coord;
      var p0 = [0, 0, 0];
      var p1 = [0, 0, 0];
      var idx = dimIndicesMap[axis.dim];
      var otherIdx = dimIndicesMap[otherDim[axis.dim]]; // 0 : x, 1 : y

      p0[idx] = p1[idx] = tickCoord;
      p1[otherIdx] = tickLength;
      linesGeo.addLine(p0, p1, lineColor, lineWidth * dpr);
    }
  }

  this.labelElements = [];
  var dpr = api.getDevicePixelRatio();

  if (axisLabelModel.get('show')) {
    var ticksCoords = axis.getTicksCoords();
    var categoryData = axisModel.get('data');
    var labelMargin = axisLabelModel.get('margin');
    var labels = axis.getViewLabels();

    for (var i = 0; i < labels.length; i++) {
      var tickValue = labels[i].tickValue;
      var formattedLabel = labels[i].formattedLabel;
      var rawLabel = labels[i].rawLabel;
      var tickCoord = axis.dataToCoord(tickValue);
      var p = [0, 0, 0];
      var idx = dimIndicesMap[axis.dim];
      var otherIdx = dimIndicesMap[otherDim[axis.dim]]; // 0 : x, 1 : y

      p[idx] = p[idx] = tickCoord;
      p[otherIdx] = labelMargin;
      var itemTextStyleModel = axisLabelModel;

      if (categoryData && categoryData[tickValue] && categoryData[tickValue].textStyle) {
        itemTextStyleModel = new echarts.Model(categoryData[tickValue].textStyle, axisLabelModel, axisModel.ecModel);
      }

      var textColor = firstNotNull(itemTextStyleModel.get('color'), axisLineColor);
      var textEl = new echarts.graphic.Text({
        style: createTextStyle(itemTextStyleModel, {
          text: formattedLabel,
          fill: typeof textColor === 'function' ? textColor( // (1) In category axis with data zoom, tick is not the original
          // index of axis.data. So tick should not be exposed to user
          // in category axis.
          // (2) Compatible with previous version, which always returns labelStr.
          // But in interval scale labelStr is like '223,445', which maked
          // user repalce ','. So we modify it to return original val but remain
          // it as 'string' to avoid error in replacing.
          axis.type === 'category' ? rawLabel : axis.type === 'value' ? tickValue + '' : tickValue, i) : textColor,
          verticalAlign: 'top',
          align: 'left'
        })
      });
      var coords = axisLabelSurface.add(textEl);
      var rect = textEl.getBoundingRect();
      labelsGeo.addSprite(p, [rect.width * dpr, rect.height * dpr], coords);
      this.labelElements.push(textEl);
    }
  }

  if (axisModel.get('name')) {
    var nameTextStyleModel = axisModel.getModel('nameTextStyle');
    var p = [0, 0, 0];
    var idx = dimIndicesMap[axis.dim];
    var otherIdx = dimIndicesMap[otherDim[axis.dim]];
    var labelColor = firstNotNull(nameTextStyleModel.get('color'), axisLineColor);
    var strokeColor = nameTextStyleModel.get('borderColor');
    var lineWidth = nameTextStyleModel.get('borderWidth'); // TODO start and end

    p[idx] = p[idx] = (extent[0] + extent[1]) / 2;
    p[otherIdx] = axisModel.get('nameGap');
    var textEl = new echarts.graphic.Text({
      style: createTextStyle(nameTextStyleModel, {
        text: axisModel.get('name'),
        fill: labelColor,
        stroke: strokeColor,
        lineWidth: lineWidth
      })
    });
    var coords = axisLabelSurface.add(textEl);
    var rect = textEl.getBoundingRect();
    labelsGeo.addSprite(p, [rect.width * dpr, rect.height * dpr], coords);
    textEl.__idx = this.labelElements.length;
    this.nameLabelElement = textEl;
  }

  this.labelsMesh.material.set('textureAtlas', axisLabelSurface.getTexture());
  this.labelsMesh.material.set('uvScale', axisLabelSurface.getCoordsScale());
  linesGeo.convertToTypedArray();
  labelsGeo.convertToTypedArray();
};

Grid3DAxis.prototype.setSpriteAlign = function (textAlign, textVerticalAlign, api) {
  var dpr = api.getDevicePixelRatio();
  var labelGeo = this.labelsMesh.geometry;

  for (var i = 0; i < this.labelElements.length; i++) {
    var labelEl = this.labelElements[i];
    var rect = labelEl.getBoundingRect();
    labelGeo.setSpriteAlign(i, [rect.width * dpr, rect.height * dpr], textAlign, textVerticalAlign);
  } // name label


  var nameLabelEl = this.nameLabelElement;

  if (nameLabelEl) {
    var rect = nameLabelEl.getBoundingRect();
    labelGeo.setSpriteAlign(nameLabelEl.__idx, [rect.width * dpr, rect.height * dpr], textAlign, textVerticalAlign);
    labelGeo.dirty();
  }

  this.textAlign = textAlign;
  this.textVerticalAlign = textVerticalAlign;
};

export default Grid3DAxis;