import { createHashMap, each, extend } from "../../../../../../zrender@5.4.4/node_modules/zrender/lib/core/util.mjs";
import RoamController from "./RoamController.mjs";
import { updateViewOnPan, updateViewOnZoom } from "./roamHelper.mjs";
import { onIrrelevantElement } from "./cursorHelper.mjs";
import { setTooltipConfig } from "../../util/graphic.mjs";
import { setDefaultStateProxy, toggleHoverEmphasis, enableComponentHighDownFeatures } from "../../util/states.mjs";
import geoSourceManager from "../../coord/geo/geoSourceManager.mjs";
import { getUID } from "../../util/component.mjs";
import { setLabelStyle, getLabelStatesModels } from "../../label/labelStyle.mjs";
import { getECData } from "../../util/innerStore.mjs";
import { createOrUpdatePatternFromDecal } from "../../util/decal.mjs";
import Displayable from "../../../../../../zrender@5.4.4/node_modules/zrender/lib/graphic/Displayable.mjs";
import { makeInner } from "../../util/model.mjs";
import Group from "../../../../../../zrender@5.4.4/node_modules/zrender/lib/graphic/Group.mjs";
import { updateProps } from "../../animation/basicTransition.mjs";
import Polygon from "../../../../../../zrender@5.4.4/node_modules/zrender/lib/graphic/shape/Polygon.mjs";
import Polyline from "../../../../../../zrender@5.4.4/node_modules/zrender/lib/graphic/shape/Polyline.mjs";
import CompoundPath from "../../../../../../zrender@5.4.4/node_modules/zrender/lib/graphic/CompoundPath.mjs";
var OPTION_STYLE_ENABLED_TAGS = ["rect", "circle", "line", "ellipse", "polygon", "polyline", "path"];
var OPTION_STYLE_ENABLED_TAG_MAP = createHashMap(OPTION_STYLE_ENABLED_TAGS);
var STATE_TRIGGER_TAG_MAP = createHashMap(OPTION_STYLE_ENABLED_TAGS.concat(["g"]));
var LABEL_HOST_MAP = createHashMap(OPTION_STYLE_ENABLED_TAGS.concat(["g"]));
var mapLabelRaw = makeInner();
function getFixedItemStyle(model) {
  var itemStyle = model.getItemStyle();
  var areaColor = model.get("areaColor");
  if (areaColor != null) {
    itemStyle.fill = areaColor;
  }
  return itemStyle;
}
function fixLineStyle(styleHost) {
  var style = styleHost.style;
  if (style) {
    style.stroke = style.stroke || style.fill;
    style.fill = null;
  }
}
var MapDraw = (
  /** @class */
  function() {
    function MapDraw2(api) {
      var group = new Group();
      this.uid = getUID("ec_map_draw");
      this._controller = new RoamController(api.getZr());
      this._controllerHost = {
        target: group
      };
      this.group = group;
      group.add(this._regionsGroup = new Group());
      group.add(this._svgGroup = new Group());
    }
    MapDraw2.prototype.draw = function(mapOrGeoModel, ecModel, api, fromView, payload) {
      var isGeo = mapOrGeoModel.mainType === "geo";
      var data = mapOrGeoModel.getData && mapOrGeoModel.getData();
      isGeo && ecModel.eachComponent({
        mainType: "series",
        subType: "map"
      }, function(mapSeries) {
        if (!data && mapSeries.getHostGeoModel() === mapOrGeoModel) {
          data = mapSeries.getData();
        }
      });
      var geo = mapOrGeoModel.coordinateSystem;
      var regionsGroup = this._regionsGroup;
      var group = this.group;
      var transformInfo = geo.getTransformInfo();
      var transformInfoRaw = transformInfo.raw;
      var transformInfoRoam = transformInfo.roam;
      var isFirstDraw = !regionsGroup.childAt(0) || payload;
      if (isFirstDraw) {
        group.x = transformInfoRoam.x;
        group.y = transformInfoRoam.y;
        group.scaleX = transformInfoRoam.scaleX;
        group.scaleY = transformInfoRoam.scaleY;
        group.dirty();
      } else {
        updateProps(group, transformInfoRoam, mapOrGeoModel);
      }
      var isVisualEncodedByVisualMap = data && data.getVisual("visualMeta") && data.getVisual("visualMeta").length > 0;
      var viewBuildCtx = {
        api,
        geo,
        mapOrGeoModel,
        data,
        isVisualEncodedByVisualMap,
        isGeo,
        transformInfoRaw
      };
      if (geo.resourceType === "geoJSON") {
        this._buildGeoJSON(viewBuildCtx);
      } else if (geo.resourceType === "geoSVG") {
        this._buildSVG(viewBuildCtx);
      }
      this._updateController(mapOrGeoModel, ecModel, api);
      this._updateMapSelectHandler(mapOrGeoModel, regionsGroup, api, fromView);
    };
    MapDraw2.prototype._buildGeoJSON = function(viewBuildCtx) {
      var regionsGroupByName = this._regionsGroupByName = createHashMap();
      var regionsInfoByName = createHashMap();
      var regionsGroup = this._regionsGroup;
      var transformInfoRaw = viewBuildCtx.transformInfoRaw;
      var mapOrGeoModel = viewBuildCtx.mapOrGeoModel;
      var data = viewBuildCtx.data;
      var projection = viewBuildCtx.geo.projection;
      var projectionStream = projection && projection.stream;
      function transformPoint(point, project) {
        if (project) {
          point = project(point);
        }
        return point && [point[0] * transformInfoRaw.scaleX + transformInfoRaw.x, point[1] * transformInfoRaw.scaleY + transformInfoRaw.y];
      }
      function transformPolygonPoints(inPoints) {
        var outPoints = [];
        var project = !projectionStream && projection && projection.project;
        for (var i = 0; i < inPoints.length; ++i) {
          var newPt = transformPoint(inPoints[i], project);
          newPt && outPoints.push(newPt);
        }
        return outPoints;
      }
      function getPolyShape(points) {
        return {
          shape: {
            points: transformPolygonPoints(points)
          }
        };
      }
      regionsGroup.removeAll();
      each(viewBuildCtx.geo.regions, function(region) {
        var regionName = region.name;
        var regionGroup = regionsGroupByName.get(regionName);
        var _a = regionsInfoByName.get(regionName) || {}, dataIdx = _a.dataIdx, regionModel = _a.regionModel;
        if (!regionGroup) {
          regionGroup = regionsGroupByName.set(regionName, new Group());
          regionsGroup.add(regionGroup);
          dataIdx = data ? data.indexOfName(regionName) : null;
          regionModel = viewBuildCtx.isGeo ? mapOrGeoModel.getRegionModel(regionName) : data ? data.getItemModel(dataIdx) : null;
          regionsInfoByName.set(regionName, {
            dataIdx,
            regionModel
          });
        }
        var polygonSubpaths = [];
        var polylineSubpaths = [];
        each(region.geometries, function(geometry) {
          if (geometry.type === "polygon") {
            var polys = [geometry.exterior].concat(geometry.interiors || []);
            if (projectionStream) {
              polys = projectPolys(polys, projectionStream);
            }
            each(polys, function(poly) {
              polygonSubpaths.push(new Polygon(getPolyShape(poly)));
            });
          } else {
            var points = geometry.points;
            if (projectionStream) {
              points = projectPolys(points, projectionStream, true);
            }
            each(points, function(points2) {
              polylineSubpaths.push(new Polyline(getPolyShape(points2)));
            });
          }
        });
        var centerPt = transformPoint(region.getCenter(), projection && projection.project);
        function createCompoundPath(subpaths, isLine) {
          if (!subpaths.length) {
            return;
          }
          var compoundPath = new CompoundPath({
            culling: true,
            segmentIgnoreThreshold: 1,
            shape: {
              paths: subpaths
            }
          });
          regionGroup.add(compoundPath);
          applyOptionStyleForRegion(viewBuildCtx, compoundPath, dataIdx, regionModel);
          resetLabelForRegion(viewBuildCtx, compoundPath, regionName, regionModel, mapOrGeoModel, dataIdx, centerPt);
          if (isLine) {
            fixLineStyle(compoundPath);
            each(compoundPath.states, fixLineStyle);
          }
        }
        createCompoundPath(polygonSubpaths);
        createCompoundPath(polylineSubpaths, true);
      });
      regionsGroupByName.each(function(regionGroup, regionName) {
        var _a = regionsInfoByName.get(regionName), dataIdx = _a.dataIdx, regionModel = _a.regionModel;
        resetEventTriggerForRegion(viewBuildCtx, regionGroup, regionName, regionModel, mapOrGeoModel, dataIdx);
        resetTooltipForRegion(viewBuildCtx, regionGroup, regionName, regionModel, mapOrGeoModel);
        resetStateTriggerForRegion(viewBuildCtx, regionGroup, regionName, regionModel, mapOrGeoModel);
      }, this);
    };
    MapDraw2.prototype._buildSVG = function(viewBuildCtx) {
      var mapName = viewBuildCtx.geo.map;
      var transformInfoRaw = viewBuildCtx.transformInfoRaw;
      this._svgGroup.x = transformInfoRaw.x;
      this._svgGroup.y = transformInfoRaw.y;
      this._svgGroup.scaleX = transformInfoRaw.scaleX;
      this._svgGroup.scaleY = transformInfoRaw.scaleY;
      if (this._svgResourceChanged(mapName)) {
        this._freeSVG();
        this._useSVG(mapName);
      }
      var svgDispatcherMap = this._svgDispatcherMap = createHashMap();
      var focusSelf = false;
      each(this._svgGraphicRecord.named, function(namedItem) {
        var regionName = namedItem.name;
        var mapOrGeoModel = viewBuildCtx.mapOrGeoModel;
        var data = viewBuildCtx.data;
        var svgNodeTagLower = namedItem.svgNodeTagLower;
        var el = namedItem.el;
        var dataIdx = data ? data.indexOfName(regionName) : null;
        var regionModel = mapOrGeoModel.getRegionModel(regionName);
        if (OPTION_STYLE_ENABLED_TAG_MAP.get(svgNodeTagLower) != null && el instanceof Displayable) {
          applyOptionStyleForRegion(viewBuildCtx, el, dataIdx, regionModel);
        }
        if (el instanceof Displayable) {
          el.culling = true;
        }
        el.z2EmphasisLift = 0;
        if (!namedItem.namedFrom) {
          if (LABEL_HOST_MAP.get(svgNodeTagLower) != null) {
            resetLabelForRegion(viewBuildCtx, el, regionName, regionModel, mapOrGeoModel, dataIdx, null);
          }
          resetEventTriggerForRegion(viewBuildCtx, el, regionName, regionModel, mapOrGeoModel, dataIdx);
          resetTooltipForRegion(viewBuildCtx, el, regionName, regionModel, mapOrGeoModel);
          if (STATE_TRIGGER_TAG_MAP.get(svgNodeTagLower) != null) {
            var focus_1 = resetStateTriggerForRegion(viewBuildCtx, el, regionName, regionModel, mapOrGeoModel);
            if (focus_1 === "self") {
              focusSelf = true;
            }
            var els = svgDispatcherMap.get(regionName) || svgDispatcherMap.set(regionName, []);
            els.push(el);
          }
        }
      }, this);
      this._enableBlurEntireSVG(focusSelf, viewBuildCtx);
    };
    MapDraw2.prototype._enableBlurEntireSVG = function(focusSelf, viewBuildCtx) {
      if (focusSelf && viewBuildCtx.isGeo) {
        var blurStyle = viewBuildCtx.mapOrGeoModel.getModel(["blur", "itemStyle"]).getItemStyle();
        var opacity_1 = blurStyle.opacity;
        this._svgGraphicRecord.root.traverse(function(el) {
          if (!el.isGroup) {
            setDefaultStateProxy(el);
            var style = el.ensureState("blur").style || {};
            if (style.opacity == null && opacity_1 != null) {
              style.opacity = opacity_1;
            }
            el.ensureState("emphasis");
          }
        });
      }
    };
    MapDraw2.prototype.remove = function() {
      this._regionsGroup.removeAll();
      this._regionsGroupByName = null;
      this._svgGroup.removeAll();
      this._freeSVG();
      this._controller.dispose();
      this._controllerHost = null;
    };
    MapDraw2.prototype.findHighDownDispatchers = function(name, geoModel) {
      if (name == null) {
        return [];
      }
      var geo = geoModel.coordinateSystem;
      if (geo.resourceType === "geoJSON") {
        var regionsGroupByName = this._regionsGroupByName;
        if (regionsGroupByName) {
          var regionGroup = regionsGroupByName.get(name);
          return regionGroup ? [regionGroup] : [];
        }
      } else if (geo.resourceType === "geoSVG") {
        return this._svgDispatcherMap && this._svgDispatcherMap.get(name) || [];
      }
    };
    MapDraw2.prototype._svgResourceChanged = function(mapName) {
      return this._svgMapName !== mapName;
    };
    MapDraw2.prototype._useSVG = function(mapName) {
      var resource = geoSourceManager.getGeoResource(mapName);
      if (resource && resource.type === "geoSVG") {
        var svgGraphic = resource.useGraphic(this.uid);
        this._svgGroup.add(svgGraphic.root);
        this._svgGraphicRecord = svgGraphic;
        this._svgMapName = mapName;
      }
    };
    MapDraw2.prototype._freeSVG = function() {
      var mapName = this._svgMapName;
      if (mapName == null) {
        return;
      }
      var resource = geoSourceManager.getGeoResource(mapName);
      if (resource && resource.type === "geoSVG") {
        resource.freeGraphic(this.uid);
      }
      this._svgGraphicRecord = null;
      this._svgDispatcherMap = null;
      this._svgGroup.removeAll();
      this._svgMapName = null;
    };
    MapDraw2.prototype._updateController = function(mapOrGeoModel, ecModel, api) {
      var geo = mapOrGeoModel.coordinateSystem;
      var controller = this._controller;
      var controllerHost = this._controllerHost;
      controllerHost.zoomLimit = mapOrGeoModel.get("scaleLimit");
      controllerHost.zoom = geo.getZoom();
      controller.enable(mapOrGeoModel.get("roam") || false);
      var mainType = mapOrGeoModel.mainType;
      function makeActionBase() {
        var action = {
          type: "geoRoam",
          componentType: mainType
        };
        action[mainType + "Id"] = mapOrGeoModel.id;
        return action;
      }
      controller.off("pan").on("pan", function(e) {
        this._mouseDownFlag = false;
        updateViewOnPan(controllerHost, e.dx, e.dy);
        api.dispatchAction(extend(makeActionBase(), {
          dx: e.dx,
          dy: e.dy,
          animation: {
            duration: 0
          }
        }));
      }, this);
      controller.off("zoom").on("zoom", function(e) {
        this._mouseDownFlag = false;
        updateViewOnZoom(controllerHost, e.scale, e.originX, e.originY);
        api.dispatchAction(extend(makeActionBase(), {
          zoom: e.scale,
          originX: e.originX,
          originY: e.originY,
          animation: {
            duration: 0
          }
        }));
      }, this);
      controller.setPointerChecker(function(e, x, y) {
        return geo.containPoint([x, y]) && !onIrrelevantElement(e, api, mapOrGeoModel);
      });
    };
    MapDraw2.prototype.resetForLabelLayout = function() {
      this.group.traverse(function(el) {
        var label = el.getTextContent();
        if (label) {
          label.ignore = mapLabelRaw(label).ignore;
        }
      });
    };
    MapDraw2.prototype._updateMapSelectHandler = function(mapOrGeoModel, regionsGroup, api, fromView) {
      var mapDraw = this;
      regionsGroup.off("mousedown");
      regionsGroup.off("click");
      if (mapOrGeoModel.get("selectedMode")) {
        regionsGroup.on("mousedown", function() {
          mapDraw._mouseDownFlag = true;
        });
        regionsGroup.on("click", function(e) {
          if (!mapDraw._mouseDownFlag) {
            return;
          }
          mapDraw._mouseDownFlag = false;
        });
      }
    };
    return MapDraw2;
  }()
);
function applyOptionStyleForRegion(viewBuildCtx, el, dataIndex, regionModel) {
  var normalStyleModel = regionModel.getModel("itemStyle");
  var emphasisStyleModel = regionModel.getModel(["emphasis", "itemStyle"]);
  var blurStyleModel = regionModel.getModel(["blur", "itemStyle"]);
  var selectStyleModel = regionModel.getModel(["select", "itemStyle"]);
  var normalStyle = getFixedItemStyle(normalStyleModel);
  var emphasisStyle = getFixedItemStyle(emphasisStyleModel);
  var selectStyle = getFixedItemStyle(selectStyleModel);
  var blurStyle = getFixedItemStyle(blurStyleModel);
  var data = viewBuildCtx.data;
  if (data) {
    var style = data.getItemVisual(dataIndex, "style");
    var decal = data.getItemVisual(dataIndex, "decal");
    if (viewBuildCtx.isVisualEncodedByVisualMap && style.fill) {
      normalStyle.fill = style.fill;
    }
    if (decal) {
      normalStyle.decal = createOrUpdatePatternFromDecal(decal, viewBuildCtx.api);
    }
  }
  el.setStyle(normalStyle);
  el.style.strokeNoScale = true;
  el.ensureState("emphasis").style = emphasisStyle;
  el.ensureState("select").style = selectStyle;
  el.ensureState("blur").style = blurStyle;
  setDefaultStateProxy(el);
}
function resetLabelForRegion(viewBuildCtx, el, regionName, regionModel, mapOrGeoModel, dataIdx, labelXY) {
  var data = viewBuildCtx.data;
  var isGeo = viewBuildCtx.isGeo;
  var isDataNaN = data && isNaN(data.get(data.mapDimension("value"), dataIdx));
  var itemLayout = data && data.getItemLayout(dataIdx);
  if (isGeo || isDataNaN || itemLayout && itemLayout.showLabel) {
    var query = !isGeo ? dataIdx : regionName;
    var labelFetcher = void 0;
    if (!data || dataIdx >= 0) {
      labelFetcher = mapOrGeoModel;
    }
    var specifiedTextOpt = labelXY ? {
      normal: {
        align: "center",
        verticalAlign: "middle"
      }
    } : null;
    setLabelStyle(el, getLabelStatesModels(regionModel), {
      labelFetcher,
      labelDataIndex: query,
      defaultText: regionName
    }, specifiedTextOpt);
    var textEl = el.getTextContent();
    if (textEl) {
      mapLabelRaw(textEl).ignore = textEl.ignore;
      if (el.textConfig && labelXY) {
        var rect = el.getBoundingRect().clone();
        el.textConfig.layoutRect = rect;
        el.textConfig.position = [(labelXY[0] - rect.x) / rect.width * 100 + "%", (labelXY[1] - rect.y) / rect.height * 100 + "%"];
      }
    }
    el.disableLabelAnimation = true;
  } else {
    el.removeTextContent();
    el.removeTextConfig();
    el.disableLabelAnimation = null;
  }
}
function resetEventTriggerForRegion(viewBuildCtx, eventTrigger, regionName, regionModel, mapOrGeoModel, dataIdx) {
  if (viewBuildCtx.data) {
    viewBuildCtx.data.setItemGraphicEl(dataIdx, eventTrigger);
  } else {
    getECData(eventTrigger).eventData = {
      componentType: "geo",
      componentIndex: mapOrGeoModel.componentIndex,
      geoIndex: mapOrGeoModel.componentIndex,
      name: regionName,
      region: regionModel && regionModel.option || {}
    };
  }
}
function resetTooltipForRegion(viewBuildCtx, el, regionName, regionModel, mapOrGeoModel) {
  if (!viewBuildCtx.data) {
    setTooltipConfig({
      el,
      componentModel: mapOrGeoModel,
      itemName: regionName,
      // @ts-ignore FIXME:TS fix the "compatible with each other"?
      itemTooltipOption: regionModel.get("tooltip")
    });
  }
}
function resetStateTriggerForRegion(viewBuildCtx, el, regionName, regionModel, mapOrGeoModel) {
  el.highDownSilentOnTouch = !!mapOrGeoModel.get("selectedMode");
  var emphasisModel = regionModel.getModel("emphasis");
  var focus = emphasisModel.get("focus");
  toggleHoverEmphasis(el, focus, emphasisModel.get("blurScope"), emphasisModel.get("disabled"));
  if (viewBuildCtx.isGeo) {
    enableComponentHighDownFeatures(el, mapOrGeoModel, regionName);
  }
  return focus;
}
function projectPolys(rings, createStream, isLine) {
  var polygons = [];
  var curPoly;
  function startPolygon() {
    curPoly = [];
  }
  function endPolygon() {
    if (curPoly.length) {
      polygons.push(curPoly);
      curPoly = [];
    }
  }
  var stream = createStream({
    polygonStart: startPolygon,
    polygonEnd: endPolygon,
    lineStart: startPolygon,
    lineEnd: endPolygon,
    point: function(x, y) {
      if (isFinite(x) && isFinite(y)) {
        curPoly.push([x, y]);
      }
    },
    sphere: function() {
    }
  });
  !isLine && stream.polygonStart();
  each(rings, function(ring) {
    stream.lineStart();
    for (var i = 0; i < ring.length; i++) {
      stream.point(ring[i][0], ring[i][1]);
    }
    stream.lineEnd();
  });
  !isLine && stream.polygonEnd();
  return polygons;
}
const MapDraw$1 = MapDraw;
export {
  MapDraw$1 as default
};
