import { __extends } from '../../../../../../tslib@2.3.0/node_modules/tslib/tslib.es6.mjs';
import ComponentView from '../../view/Component.mjs';
import Model from '../../model/Model.mjs';
import BoundingRect from '../../../../../../zrender@6.0.0/node_modules/zrender/lib/core/BoundingRect.mjs';
import { set } from '../../../../../../zrender@6.0.0/node_modules/zrender/lib/core/vector.mjs';
import { subPixelOptimize } from '../../../../../../zrender@6.0.0/node_modules/zrender/lib/graphic/helper/subPixelOptimize.mjs';
import { XY, expandOrShrinkRect, setTooltipConfig } from '../../util/graphic.mjs';
import { ListIterator, clearTmpModel } from '../../util/model.mjs';
import { retrieve2, clone } from '../../../../../../zrender@6.0.0/node_modules/zrender/lib/core/util.mjs';
import { invert } from '../../../../../../zrender@6.0.0/node_modules/zrender/lib/core/matrix.mjs';
import { setLabelStyle } from '../../label/labelStyle.mjs';
import Rect from '../../../../../../zrender@6.0.0/node_modules/zrender/lib/graphic/shape/Rect.mjs';
import Line from '../../../../../../zrender@6.0.0/node_modules/zrender/lib/graphic/shape/Line.mjs';

var round = Math.round;
var Z2_BACKGROUND = 0;
var Z2_OUTER_BORDER = 99;
var Z2_BODY_CORNER_CELL_DEFAULT = {
  normal: 25,
  special: 100
};
var Z2_DIMENSION_CELL_DEFAULT = {
  normal: 50,
  special: 125
};
var MatrixView = /** @class */function (_super) {
  __extends(MatrixView, _super);
  function MatrixView() {
    var _this = _super !== null && _super.apply(this, arguments) || this;
    _this.type = MatrixView.type;
    return _this;
  }
  MatrixView.prototype.render = function (matrixModel, ecModel) {
    this.group.removeAll();
    var group = this.group;
    var coordSys = matrixModel.coordinateSystem;
    var rect = coordSys.getRect();
    var xDimModel = matrixModel.getDimensionModel('x');
    var yDimModel = matrixModel.getDimensionModel('y');
    var xDim = xDimModel.dim;
    var yDim = yDimModel.dim;
    // PENDING:
    //  reuse the existing text and rect elements for performance?
    renderDimensionCells(group, matrixModel, ecModel);
    createBodyAndCorner(group, matrixModel, xDim, yDim, ecModel);
    var borderZ2Option = matrixModel.getShallow('borderZ2', true);
    var outerBorderZ2 = retrieve2(borderZ2Option, Z2_OUTER_BORDER);
    var dividerLineZ2 = outerBorderZ2 - 1;
    // Outer border and overall background. Use separate elements because of z-order:
    // The overall background should appear below any other elements.
    // But in most cases, the outer border and the divider line should be above the normal cell borders -
    // especially when cell borders have different colors. But users may highlight some specific cells by
    // overstirking their border, in which case it should be above the outer border.
    var bgStyle = matrixModel.getModel('backgroundStyle').getItemStyle(['borderWidth']);
    bgStyle.lineWidth = 0;
    var borderStyle = matrixModel.getModel('backgroundStyle').getItemStyle(['color', 'decal', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY']);
    borderStyle.fill = 'none';
    var bgRect = createMatrixRect(rect.clone(), bgStyle, Z2_BACKGROUND);
    var borderRect = createMatrixRect(rect.clone(), borderStyle, outerBorderZ2);
    bgRect.silent = true;
    borderRect.silent = true;
    group.add(bgRect);
    group.add(borderRect);
    // Header split line.
    var xDimCell0 = xDim.getUnitLayoutInfo(0, 0);
    var yDimCell0 = yDim.getUnitLayoutInfo(1, 0);
    if (xDimCell0 && yDimCell0) {
      if (xDim.shouldShow()) {
        group.add(createMatrixLine({
          x1: rect.x,
          y1: yDimCell0.xy,
          x2: rect.x + rect.width,
          y2: yDimCell0.xy
        }, xDimModel.getModel('dividerLineStyle').getLineStyle(), dividerLineZ2));
      }
      if (yDim.shouldShow()) {
        group.add(createMatrixLine({
          x1: xDimCell0.xy,
          y1: rect.y,
          x2: xDimCell0.xy,
          y2: rect.y + rect.height
        }, yDimModel.getModel('dividerLineStyle').getLineStyle(), dividerLineZ2));
      }
    }
  };
  MatrixView.type = 'matrix';
  return MatrixView;
}(ComponentView);
function renderDimensionCells(group, matrixModel, ecModel) {
  renderOnDimension(0);
  renderOnDimension(1);
  function renderOnDimension(dimIdx) {
    var thisDimModel = matrixModel.getDimensionModel(XY[dimIdx]);
    var thisDim = thisDimModel.dim;
    if (!thisDim.shouldShow()) {
      return;
    }
    var thisDimBgStyleModel = thisDimModel.getModel('itemStyle');
    var thisDimLabelModel = thisDimModel.getModel('label');
    var tooltipOption = matrixModel.getShallow('tooltip', true);
    var xyLocator = [];
    for (var it_1 = thisDim.resetCellIterator(); it_1.next();) {
      var dimCell = it_1.item;
      var shape = {};
      BoundingRect.copy(shape, dimCell.rect);
      set(xyLocator, dimCell.id.x, dimCell.id.y);
      createMatrixCell(xyLocator, matrixModel, group, ecModel, dimCell.option, thisDimBgStyleModel, thisDimLabelModel, thisDimModel, shape, dimCell.option.value, Z2_DIMENSION_CELL_DEFAULT, tooltipOption);
    }
  }
}
function createBodyAndCorner(group, matrixModel, xDim, yDim, ecModel) {
  createBodyOrCornerCells('body', matrixModel.getBody(), xDim, yDim);
  if (xDim.shouldShow() && yDim.shouldShow()) {
    createBodyOrCornerCells('corner', matrixModel.getCorner(), yDim, xDim);
  }
  function createBodyOrCornerCells(bodyCornerOptionRoot, bodyOrCorner, dimForCoordX,
  // Can be `matrix.y` (transposed) for corners.
  dimForCoordY) {
    // Prevent inheriting from ancestor.
    var parentCellModel = new Model(matrixModel.getShallow(bodyCornerOptionRoot, true));
    var parentItemStyleModel = parentCellModel.getModel('itemStyle');
    var parentLabelModel = parentCellModel.getModel('label');
    var itx = new ListIterator();
    var ity = new ListIterator();
    var xyLocator = [];
    var tooltipOption = matrixModel.getShallow('tooltip', true);
    for (dimForCoordY.resetLayoutIterator(ity, 1); ity.next();) {
      for (dimForCoordX.resetLayoutIterator(itx, 0); itx.next();) {
        var xLayout = itx.item;
        var yLayout = ity.item;
        set(xyLocator, xLayout.id.x, yLayout.id.y);
        var bodyCornerCell = bodyOrCorner.getCell(xyLocator);
        // If in span of an other body or corner cell, never render it.
        if (bodyCornerCell && bodyCornerCell.inSpanOf && bodyCornerCell.inSpanOf !== bodyCornerCell) {
          continue;
        }
        var shape = {};
        if (bodyCornerCell && bodyCornerCell.span) {
          BoundingRect.copy(shape, bodyCornerCell.spanRect);
        } else {
          xLayout.dim.getLayout(shape, 0, xyLocator[0]);
          yLayout.dim.getLayout(shape, 1, xyLocator[1]);
        }
        var bodyCornerCellOption = bodyCornerCell ? bodyCornerCell.option : null;
        createMatrixCell(xyLocator, matrixModel, group, ecModel, bodyCornerCellOption, parentItemStyleModel, parentLabelModel, parentCellModel, shape, bodyCornerCellOption ? bodyCornerCellOption.value : null, Z2_BODY_CORNER_CELL_DEFAULT, tooltipOption);
      }
    }
  } // End of createBodyOrCornerCells
}
function createMatrixCell(xyLocator, matrixModel, group, ecModel, cellOption, parentItemStyleModel, parentLabelModel, parentCellModel, shape, textValue, zrCellDefault, tooltipOption) {
  var _a;
  // Do not use getModel for handy performance optimization.
  _tmpCellItemStyleModel.option = cellOption ? cellOption.itemStyle : null;
  _tmpCellItemStyleModel.parentModel = parentItemStyleModel;
  _tmpCellModel.option = cellOption;
  _tmpCellModel.parentModel = parentCellModel;
  // Use different z2 because special border may be defined in itemStyle.
  var z2 = retrieve2(_tmpCellModel.getShallow('z2'), cellOption && cellOption.itemStyle ? zrCellDefault.special : zrCellDefault.normal);
  var tooltipOptionShow = tooltipOption && tooltipOption.show;
  var cellRect = createMatrixRect(shape, _tmpCellItemStyleModel.getItemStyle(), z2);
  group.add(cellRect);
  var cursorOption = _tmpCellModel.get('cursor');
  if (cursorOption != null) {
    cellRect.attr('cursor', cursorOption);
  }
  var cellText;
  if (textValue != null) {
    var text = textValue + '';
    _tmpCellLabelModel.option = cellOption ? cellOption.label : null;
    _tmpCellLabelModel.parentModel = parentLabelModel;
    // This is to accept `option.textStyle` as the default.
    _tmpCellLabelModel.ecModel = ecModel;
    setLabelStyle(cellRect,
    // Currently do not support other states (`emphasis`, `select`, `blur`)
    {
      normal: _tmpCellLabelModel
    }, {
      defaultText: text,
      autoOverflowArea: true,
      // By default based on boundingRect. But boundingRect contains borderWidth,
      // and borderWidth is half outside the cell. Thus specific `layoutRect` explicitly.
      layoutRect: clone(cellRect.shape)
    });
    cellText = cellRect.getTextContent();
    if (cellText) {
      cellText.z2 = z2 + 1;
      var style = cellText.style;
      if (style && style.overflow && style.overflow !== 'none' && style.lineOverflow) {
        // `overflow: 'break'/'breakAll'/'truncate'` does not guarantee prevention of overflow
        // when space is insufficient. Use a `clipPath` in such case.
        var clipShape = {};
        BoundingRect.copy(clipShape, shape);
        // `lineWidth` is half outside half inside the bounding rect.
        expandOrShrinkRect(clipShape, (((_a = cellRect.style) === null || _a === void 0 ? void 0 : _a.lineWidth) || 0) / 2, true, true);
        cellRect.updateInnerText();
        cellText.getLocalTransform(_tmpInnerTextTrans);
        invert(_tmpInnerTextTrans, _tmpInnerTextTrans);
        BoundingRect.applyTransform(clipShape, clipShape, _tmpInnerTextTrans);
        cellText.setClipPath(new Rect({
          shape: clipShape
        }));
      }
    }
    setTooltipConfig({
      el: cellRect,
      componentModel: matrixModel,
      itemName: text,
      itemTooltipOption: tooltipOption,
      formatterParamsExtra: {
        xyLocator: xyLocator.slice()
      }
    });
  }
  // Set silent
  if (cellText) {
    var labelSilent = _tmpCellLabelModel.get('silent');
    // auto, tooltip of text cells need silient: false, but non-text cells
    // do not need a special cursor in most cases.
    if (labelSilent == null) {
      labelSilent = !tooltipOptionShow;
    }
    cellText.silent = labelSilent;
    cellText.ignoreHostSilent = true;
  }
  var rectSilent = _tmpCellModel.get('silent');
  if (rectSilent == null) {
    rectSilent =
    // If no background color in cell, set `rect.silent: false` will cause that only
    // the border response to mouse hovering, which is probably weird.
    !cellRect.style || cellRect.style.fill === 'none' || !cellRect.style.fill;
  }
  cellRect.silent = rectSilent;
  clearTmpModel(_tmpCellModel);
  clearTmpModel(_tmpCellItemStyleModel);
  clearTmpModel(_tmpCellLabelModel);
}
var _tmpCellModel = new Model();
var _tmpCellItemStyleModel = new Model();
var _tmpCellLabelModel = new Model();
var _tmpInnerTextTrans = [];
// FIXME: move all of the subpixel process to Matrix.ts resize, otherwise the result of
// `dataToLayout` is not consistent with this rendering, and the caller (like heatmap) can
// not precisely align with the matrix border.
function createMatrixRect(shape, style, z2) {
  // Currently `subPixelOptimizeRect` can not be used here because it will break rect alignment.
  // Optimize line and rect with the same direction.
  var lineWidth = style.lineWidth;
  if (lineWidth) {
    var x2Original = shape.x + shape.width;
    var y2Original = shape.y + shape.height;
    shape.x = subPixelOptimize(shape.x, lineWidth, true);
    shape.y = subPixelOptimize(shape.y, lineWidth, true);
    shape.width = subPixelOptimize(x2Original, lineWidth, true) - shape.x;
    shape.height = subPixelOptimize(y2Original, lineWidth, true) - shape.y;
  }
  return new Rect({
    shape: shape,
    style: style,
    z2: z2
  });
}
function createMatrixLine(shape, style, z2) {
  var lineWidth = style.lineWidth;
  if (lineWidth) {
    if (round(shape.x1 * 2) === round(shape.x2 * 2)) {
      shape.x1 = shape.x2 = subPixelOptimize(shape.x1, lineWidth, true);
    }
    if (round(shape.y1 * 2) === round(shape.y2 * 2)) {
      shape.y1 = shape.y2 = subPixelOptimize(shape.y1, lineWidth, true);
    }
  }
  return new Line({
    shape: shape,
    style: style,
    silent: true,
    z2: z2
  });
}

export { MatrixView as default };
