import * as echarts from 'echarts/lib/echarts';
import ZRTextureAtlasSurface from '../../util/ZRTextureAtlasSurface';
import LabelsMesh from '../../util/mesh/LabelsMesh';
import retrieve from '../../util/retrieve';
import { getItemVisualColor, getItemVisualOpacity } from '../../util/visual';
import { createTextStyle } from 'echarts/lib/label/labelStyle';
var LABEL_NORMAL_SHOW_BIT = 1;
var LABEL_EMPHASIS_SHOW_BIT = 2;

function LabelsBuilder(width, height, api) {
  this._labelsMesh = new LabelsMesh();
  this._labelTextureSurface = new ZRTextureAtlasSurface({
    width: 512,
    height: 512,
    devicePixelRatio: api.getDevicePixelRatio(),
    onupdate: function () {
      api.getZr().refresh();
    }
  });
  this._api = api;

  this._labelsMesh.material.set('textureAtlas', this._labelTextureSurface.getTexture());
}

LabelsBuilder.prototype.getLabelPosition = function (dataIndex, positionDesc, distance) {
  return [0, 0, 0];
};

LabelsBuilder.prototype.getLabelDistance = function (dataIndex, positionDesc, distance) {
  return 0;
};

LabelsBuilder.prototype.getMesh = function () {
  return this._labelsMesh;
};

LabelsBuilder.prototype.updateData = function (data, start, end) {
  if (start == null) {
    start = 0;
  }

  if (end == null) {
    end = data.count();
  }

  if (!this._labelsVisibilitiesBits || this._labelsVisibilitiesBits.length !== end - start) {
    this._labelsVisibilitiesBits = new Uint8Array(end - start);
  }

  var normalLabelVisibilityQuery = ['label', 'show'];
  var emphasisLabelVisibilityQuery = ['emphasis', 'label', 'show'];

  for (var idx = start; idx < end; idx++) {
    var itemModel = data.getItemModel(idx);
    var normalVisibility = itemModel.get(normalLabelVisibilityQuery);
    var emphasisVisibility = itemModel.get(emphasisLabelVisibilityQuery);

    if (emphasisVisibility == null) {
      emphasisVisibility = normalVisibility;
    }

    var bit = (normalVisibility ? LABEL_NORMAL_SHOW_BIT : 0) | (emphasisVisibility ? LABEL_EMPHASIS_SHOW_BIT : 0);
    this._labelsVisibilitiesBits[idx - start] = bit;
  }

  this._start = start;
  this._end = end;
  this._data = data;
};

LabelsBuilder.prototype.updateLabels = function (highlightDataIndices) {
  if (!this._data) {
    return;
  }

  highlightDataIndices = highlightDataIndices || [];
  var hasHighlightData = highlightDataIndices.length > 0;
  var highlightDataIndicesMap = {};

  for (var i = 0; i < highlightDataIndices.length; i++) {
    highlightDataIndicesMap[highlightDataIndices[i]] = true;
  }

  this._labelsMesh.geometry.convertToDynamicArray(true);

  this._labelTextureSurface.clear();

  var normalLabelQuery = ['label'];
  var emphasisLabelQuery = ['emphasis', 'label'];
  var seriesModel = this._data.hostModel;
  var data = this._data;
  var seriesLabelModel = seriesModel.getModel(normalLabelQuery);
  var seriesLabelEmphasisModel = seriesModel.getModel(emphasisLabelQuery, seriesLabelModel);
  var textAlignMap = {
    left: 'right',
    right: 'left',
    top: 'center',
    bottom: 'center'
  };
  var textVerticalAlignMap = {
    left: 'middle',
    right: 'middle',
    top: 'bottom',
    bottom: 'top'
  };

  for (var dataIndex = this._start; dataIndex < this._end; dataIndex++) {
    var isEmphasis = false;

    if (hasHighlightData && highlightDataIndicesMap[dataIndex]) {
      isEmphasis = true;
    }

    var ifShow = this._labelsVisibilitiesBits[dataIndex - this._start] & (isEmphasis ? LABEL_EMPHASIS_SHOW_BIT : LABEL_NORMAL_SHOW_BIT);

    if (!ifShow) {
      continue;
    }

    var itemModel = data.getItemModel(dataIndex);
    var labelModel = itemModel.getModel(isEmphasis ? emphasisLabelQuery : normalLabelQuery, isEmphasis ? seriesLabelEmphasisModel : seriesLabelModel);
    var distance = labelModel.get('distance') || 0;
    var position = labelModel.get('position');

    var dpr = this._api.getDevicePixelRatio();

    var text = seriesModel.getFormattedLabel(dataIndex, isEmphasis ? 'emphasis' : 'normal');

    if (text == null || text === '') {
      return;
    } // TODO Background.


    var textEl = new echarts.graphic.Text({
      style: createTextStyle(labelModel, {
        text: text,
        fill: labelModel.get('color') || getItemVisualColor(data, dataIndex) || '#000',
        align: 'left',
        verticalAlign: 'top',
        opacity: retrieve.firstNotNull(labelModel.get('opacity'), getItemVisualOpacity(data, dataIndex), 1)
      })
    });
    var rect = textEl.getBoundingRect();
    var lineHeight = 1.2;
    rect.height *= lineHeight;

    var coords = this._labelTextureSurface.add(textEl);

    var textAlign = textAlignMap[position] || 'center';
    var textVerticalAlign = textVerticalAlignMap[position] || 'bottom';

    this._labelsMesh.geometry.addSprite(this.getLabelPosition(dataIndex, position, distance), [rect.width * dpr, rect.height * dpr], coords, textAlign, textVerticalAlign, this.getLabelDistance(dataIndex, position, distance) * dpr);
  }

  this._labelsMesh.material.set('uvScale', this._labelTextureSurface.getCoordsScale()); // var canvas = this._labelTextureSurface.getTexture().image;
  // document.body.appendChild(canvas);
  // canvas.style.cssText = 'position:absolute;z-index: 1000';
  // Update image.


  this._labelTextureSurface.getZr().refreshImmediately();

  this._labelsMesh.geometry.convertToTypedArray();

  this._labelsMesh.geometry.dirty();
};

LabelsBuilder.prototype.dispose = function () {
  this._labelTextureSurface.dispose();
};

export default LabelsBuilder;