import { __extends } from '../../../../../../tslib@2.3.0/node_modules/tslib/tslib.es6.mjs';
import { traverseElements } from '../../util/graphic.mjs';
import { toggleHoverEmphasis } from '../../util/states.mjs';
import HeatmapLayer from './HeatmapLayer.mjs';
import { map, eqNaN } from '../../../../../../zrender@6.0.0/node_modules/zrender/lib/core/util.mjs';
import ChartView from '../../view/Chart.mjs';
import { isCoordinateSystemType } from '../../coord/CoordinateSystem.mjs';
import { getLabelStatesModels, setLabelStyle } from '../../label/labelStyle.mjs';
import Rect from '../../../../../../zrender@6.0.0/node_modules/zrender/lib/graphic/shape/Rect.mjs';
import ZRImage from '../../../../../../zrender@6.0.0/node_modules/zrender/lib/graphic/Image.mjs';

function getIsInPiecewiseRange(dataExtent, pieceList, selected) {
  var dataSpan = dataExtent[1] - dataExtent[0];
  pieceList = map(pieceList, function (piece) {
    return {
      interval: [(piece.interval[0] - dataExtent[0]) / dataSpan, (piece.interval[1] - dataExtent[0]) / dataSpan]
    };
  });
  var len = pieceList.length;
  var lastIndex = 0;
  return function (val) {
    var i;
    // Try to find in the location of the last found
    for (i = lastIndex; i < len; i++) {
      var interval = pieceList[i].interval;
      if (interval[0] <= val && val <= interval[1]) {
        lastIndex = i;
        break;
      }
    }
    if (i === len) {
      // Not found, back interation
      for (i = lastIndex - 1; i >= 0; i--) {
        var interval = pieceList[i].interval;
        if (interval[0] <= val && val <= interval[1]) {
          lastIndex = i;
          break;
        }
      }
    }
    return i >= 0 && i < len && selected[i];
  };
}
function getIsInContinuousRange(dataExtent, range) {
  var dataSpan = dataExtent[1] - dataExtent[0];
  range = [(range[0] - dataExtent[0]) / dataSpan, (range[1] - dataExtent[0]) / dataSpan];
  return function (val) {
    return val >= range[0] && val <= range[1];
  };
}
function isGeoCoordSys(coordSys) {
  var dimensions = coordSys.dimensions;
  // Not use coordSys.type === 'geo' because coordSys maybe extended
  return dimensions[0] === 'lng' && dimensions[1] === 'lat';
}
var HeatmapView = /** @class */function (_super) {
  __extends(HeatmapView, _super);
  function HeatmapView() {
    var _this = _super !== null && _super.apply(this, arguments) || this;
    _this.type = HeatmapView.type;
    return _this;
  }
  HeatmapView.prototype.render = function (seriesModel, ecModel, api) {
    var visualMapOfThisSeries;
    ecModel.eachComponent('visualMap', function (visualMap) {
      visualMap.eachTargetSeries(function (targetSeries) {
        if (targetSeries === seriesModel) {
          visualMapOfThisSeries = visualMap;
        }
      });
    });
    if (process.env.NODE_ENV !== 'production') {
      if (!visualMapOfThisSeries) {
        throw new Error('Heatmap must use with visualMap');
      }
    }
    // Clear previously rendered progressive elements.
    this._progressiveEls = null;
    this.group.removeAll();
    var coordSys = seriesModel.coordinateSystem;
    if (coordSys.type === 'cartesian2d' || coordSys.type === 'calendar' || coordSys.type === 'matrix') {
      this._renderOnGridLike(seriesModel, api, 0, seriesModel.getData().count());
    } else if (isGeoCoordSys(coordSys)) {
      this._renderOnGeo(coordSys, seriesModel, visualMapOfThisSeries, api);
    }
  };
  HeatmapView.prototype.incrementalPrepareRender = function (seriesModel, ecModel, api) {
    this.group.removeAll();
  };
  HeatmapView.prototype.incrementalRender = function (params, seriesModel, ecModel, api) {
    var coordSys = seriesModel.coordinateSystem;
    if (coordSys) {
      // geo does not support incremental rendering?
      if (isGeoCoordSys(coordSys)) {
        this.render(seriesModel, ecModel, api);
      } else {
        this._progressiveEls = [];
        this._renderOnGridLike(seriesModel, api, params.start, params.end, true);
      }
    }
  };
  HeatmapView.prototype.eachRendered = function (cb) {
    traverseElements(this._progressiveEls || this.group, cb);
  };
  HeatmapView.prototype._renderOnGridLike = function (seriesModel, api, start, end, incremental) {
    var coordSys = seriesModel.coordinateSystem;
    var isCartesian2d = isCoordinateSystemType(coordSys, 'cartesian2d');
    var isMatrix = isCoordinateSystemType(coordSys, 'matrix');
    var width;
    var height;
    var xAxisExtent;
    var yAxisExtent;
    if (isCartesian2d) {
      var xAxis = coordSys.getAxis('x');
      var yAxis = coordSys.getAxis('y');
      if (process.env.NODE_ENV !== 'production') {
        if (!(xAxis.type === 'category' && yAxis.type === 'category')) {
          throw new Error('Heatmap on cartesian must have two category axes');
        }
        if (!(xAxis.onBand && yAxis.onBand)) {
          throw new Error('Heatmap on cartesian must have two axes with boundaryGap true');
        }
      }
      // add 0.5px to avoid the gaps
      width = xAxis.getBandWidth() + .5;
      height = yAxis.getBandWidth() + .5;
      xAxisExtent = xAxis.scale.getExtent();
      yAxisExtent = yAxis.scale.getExtent();
    }
    var group = this.group;
    var data = seriesModel.getData();
    var emphasisStyle = seriesModel.getModel(['emphasis', 'itemStyle']).getItemStyle();
    var blurStyle = seriesModel.getModel(['blur', 'itemStyle']).getItemStyle();
    var selectStyle = seriesModel.getModel(['select', 'itemStyle']).getItemStyle();
    var borderRadius = seriesModel.get(['itemStyle', 'borderRadius']);
    var labelStatesModels = getLabelStatesModels(seriesModel);
    var emphasisModel = seriesModel.getModel('emphasis');
    var focus = emphasisModel.get('focus');
    var blurScope = emphasisModel.get('blurScope');
    var emphasisDisabled = emphasisModel.get('disabled');
    var dataDims = isCartesian2d || isMatrix ? [data.mapDimension('x'), data.mapDimension('y'), data.mapDimension('value')] : [data.mapDimension('time'), data.mapDimension('value')];
    for (var idx = start; idx < end; idx++) {
      var rect = void 0;
      var style = data.getItemVisual(idx, 'style');
      if (isCartesian2d) {
        var dataDimX = data.get(dataDims[0], idx);
        var dataDimY = data.get(dataDims[1], idx);
        // Ignore empty data and out of extent data
        if (isNaN(data.get(dataDims[2], idx)) || isNaN(dataDimX) || isNaN(dataDimY) || dataDimX < xAxisExtent[0] || dataDimX > xAxisExtent[1] || dataDimY < yAxisExtent[0] || dataDimY > yAxisExtent[1]) {
          continue;
        }
        var point = coordSys.dataToPoint([dataDimX, dataDimY]);
        rect = new Rect({
          shape: {
            x: point[0] - width / 2,
            y: point[1] - height / 2,
            width: width,
            height: height
          },
          style: style
        });
      } else if (isMatrix) {
        var shape = coordSys.dataToLayout([data.get(dataDims[0], idx), data.get(dataDims[1], idx)]).rect;
        if (eqNaN(shape.x)) {
          continue;
        }
        rect = new Rect({
          z2: 1,
          shape: shape,
          style: style
        });
      } else {
        // Calendar
        // Ignore empty data
        if (isNaN(data.get(dataDims[1], idx))) {
          continue;
        }
        var layout = coordSys.dataToLayout([data.get(dataDims[0], idx)]);
        var shape = layout.contentRect || layout.rect;
        if (eqNaN(shape.x) || eqNaN(shape.y)) {
          continue;
        }
        rect = new Rect({
          z2: 1,
          shape: shape,
          style: style
        });
      }
      // Optimization for large dataset
      if (data.hasItemOption) {
        var itemModel = data.getItemModel(idx);
        var emphasisModel_1 = itemModel.getModel('emphasis');
        emphasisStyle = emphasisModel_1.getModel('itemStyle').getItemStyle();
        blurStyle = itemModel.getModel(['blur', 'itemStyle']).getItemStyle();
        selectStyle = itemModel.getModel(['select', 'itemStyle']).getItemStyle();
        // Each item value struct in the data would be firstly
        // {
        //     itemStyle: { borderRadius: [30, 30] },
        //     value: [2022, 02, 22]
        // }
        borderRadius = itemModel.get(['itemStyle', 'borderRadius']);
        focus = emphasisModel_1.get('focus');
        blurScope = emphasisModel_1.get('blurScope');
        emphasisDisabled = emphasisModel_1.get('disabled');
        labelStatesModels = getLabelStatesModels(itemModel);
      }
      rect.shape.r = borderRadius;
      var rawValue = seriesModel.getRawValue(idx);
      var defaultText = '-';
      if (rawValue && rawValue[2] != null) {
        defaultText = rawValue[2] + '';
      }
      setLabelStyle(rect, labelStatesModels, {
        labelFetcher: seriesModel,
        labelDataIndex: idx,
        defaultOpacity: style.opacity,
        defaultText: defaultText
      });
      rect.ensureState('emphasis').style = emphasisStyle;
      rect.ensureState('blur').style = blurStyle;
      rect.ensureState('select').style = selectStyle;
      toggleHoverEmphasis(rect, focus, blurScope, emphasisDisabled);
      rect.incremental = incremental;
      // PENDING
      if (incremental) {
        // Rect must use hover layer if it's incremental.
        rect.states.emphasis.hoverLayer = true;
      }
      group.add(rect);
      data.setItemGraphicEl(idx, rect);
      if (this._progressiveEls) {
        this._progressiveEls.push(rect);
      }
    }
  };
  HeatmapView.prototype._renderOnGeo = function (geo, seriesModel, visualMapModel, api) {
    var inRangeVisuals = visualMapModel.targetVisuals.inRange;
    var outOfRangeVisuals = visualMapModel.targetVisuals.outOfRange;
    // if (!visualMapping) {
    //     throw new Error('Data range must have color visuals');
    // }
    var data = seriesModel.getData();
    var hmLayer = this._hmLayer || this._hmLayer || new HeatmapLayer();
    hmLayer.blurSize = seriesModel.get('blurSize');
    hmLayer.pointSize = seriesModel.get('pointSize');
    hmLayer.minOpacity = seriesModel.get('minOpacity');
    hmLayer.maxOpacity = seriesModel.get('maxOpacity');
    var rect = geo.getViewRect().clone();
    var roamTransform = geo.getRoamTransform();
    rect.applyTransform(roamTransform);
    // Clamp on viewport
    var x = Math.max(rect.x, 0);
    var y = Math.max(rect.y, 0);
    var x2 = Math.min(rect.width + rect.x, api.getWidth());
    var y2 = Math.min(rect.height + rect.y, api.getHeight());
    var width = x2 - x;
    var height = y2 - y;
    var dims = [data.mapDimension('lng'), data.mapDimension('lat'), data.mapDimension('value')];
    var points = data.mapArray(dims, function (lng, lat, value) {
      var pt = geo.dataToPoint([lng, lat]);
      pt[0] -= x;
      pt[1] -= y;
      pt.push(value);
      return pt;
    });
    var dataExtent = visualMapModel.getExtent();
    var isInRange = visualMapModel.type === 'visualMap.continuous' ? getIsInContinuousRange(dataExtent, visualMapModel.option.range) : getIsInPiecewiseRange(dataExtent, visualMapModel.getPieceList(), visualMapModel.option.selected);
    hmLayer.update(points, width, height, inRangeVisuals.color.getNormalizer(), {
      inRange: inRangeVisuals.color.getColorMapper(),
      outOfRange: outOfRangeVisuals.color.getColorMapper()
    }, isInRange);
    var img = new ZRImage({
      style: {
        width: width,
        height: height,
        x: x,
        y: y,
        image: hmLayer.canvas
      },
      silent: true
    });
    this.group.add(img);
  };
  HeatmapView.type = 'heatmap';
  return HeatmapView;
}(ChartView);

export { HeatmapView as default };
