"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.VisionInspectionNodeService = void 0;
const webscope_service_1 = require("../../webscope-service");
const waypoint_rpc_util_1 = require("../../utils/waypoint-rpc.util");
const visioninspection_node_config_1 = require("./visioninspection-node-config");
const visioninspection_node_1 = require("./visioninspection-node");
let visionInspectionResultNextIndex = 1;
let visionInspectionResultSeedInitialized = false;
let visionInspectionWaypointNextIndex = 1;
let visionInspectionWaypointSeedInitialized = false;
class VisionInspectionNodeService {
  constructor() {
    this.programNodeConfig = new visioninspection_node_config_1.VisionInspectionNodeConfig();
    this.funcMap = new Map();
    this.defaultWaypointName = 'inspection_waypoint';
    this.waypointToNodeIds = new Map();
    this.nodeIdToWaypointName = new Map();
    this.waypointIndexDirty = true;
    this.funcMap.set('visioninspection/visual/add-variable', this.addResultVariable.bind(this));
    (0, waypoint_rpc_util_1.registerWaypointRpc)(this.funcMap, 'visioninspection', {
      onWaypointUpdated: this.handleWaypointUpdated.bind(this)
    });
  }
  loadFromXml(dataModel) {
    const node = new visioninspection_node_1.VisionInspectionNode(this.programModel);
    node.setDataModel(dataModel);
    this.waypointIndexDirty = true;
    return node;
  }
  setProgramModel(programModel) {
    this.programModel = programModel;
  }
  getProgramNodeConfig() {
    return this.programNodeConfig;
  }
  getRpcMap() {
    return this.funcMap;
  }
  createNode() {
    const node = new visioninspection_node_1.VisionInspectionNode(this.programModel);
    this.initializeNodeDefaults(node);
    this.waypointIndexDirty = true;
    return {
      nodeId: this.programNodeConfig.id,
      node,
      children: []
    };
  }
  cloneNode(node) {
    this.waypointIndexDirty = true;
    return new visioninspection_node_1.VisionInspectionNode(this.programModel).cloneNode(node);
  }
  normalizeWaypointName(name) {
    return typeof name === 'string' ? name.trim().toLowerCase() : '';
  }
  clearWaypointIndexByNodeId(nodeId) {
    const oldName = this.nodeIdToWaypointName.get(nodeId);
    if (!oldName) {
      return;
    }
    this.nodeIdToWaypointName.delete(nodeId);
    const nodeIds = this.waypointToNodeIds.get(oldName);
    if (!nodeIds) {
      return;
    }
    nodeIds.delete(nodeId);
    if (nodeIds.size === 0) {
      this.waypointToNodeIds.delete(oldName);
    }
  }
  indexTreeNode(treeNode) {
    var _a, _b, _c;
    const nodeId = (_a = treeNode === null || treeNode === void 0 ? void 0 : treeNode.model) === null || _a === void 0 ? void 0 : _a.id;
    const programNode = (_b = treeNode === null || treeNode === void 0 ? void 0 : treeNode.model) === null || _b === void 0 ? void 0 : _b.programNode;
    if (typeof nodeId !== 'string' || nodeId.length === 0) {
      return;
    }
    this.clearWaypointIndexByNodeId(nodeId);
    if (!(programNode instanceof visioninspection_node_1.VisionInspectionNode)) {
      return;
    }
    const waypointName = this.normalizeWaypointName(this.extractWaypointName(programNode.getInspectionWaypoint()));
    if (!waypointName) {
      return;
    }
    this.nodeIdToWaypointName.set(nodeId, waypointName);
    if (!this.waypointToNodeIds.has(waypointName)) {
      this.waypointToNodeIds.set(waypointName, new Set());
    }
    (_c = this.waypointToNodeIds.get(waypointName)) === null || _c === void 0 ? void 0 : _c.add(nodeId);
  }
  rebuildWaypointIndexIfNeeded() {
    var _a, _b;
    if (!this.waypointIndexDirty) {
      return;
    }
    this.waypointToNodeIds.clear();
    this.nodeIdToWaypointName.clear();
    const programTree = (_b = (_a = this.programModel) === null || _a === void 0 ? void 0 : _a.getProgramTree) === null || _b === void 0 ? void 0 : _b.call(_a);
    if (!programTree) {
      return;
    }
    const updateHasDefined = programTree.updateHasDefined;
    const rootNode = programTree.getTreeNode();
    if (!rootNode || typeof rootNode.walk !== 'function') {
      return;
    }
    rootNode.walk(treeNode => {
      this.indexTreeNode(treeNode);
      return true;
    });
    this.waypointIndexDirty = false;
  }
  initResultVariableSeed(variableModel) {
    if (visionInspectionResultSeedInitialized) {
      return;
    }
    const prefix = visioninspection_node_1.VISION_INSPECTION_RESULT_SUFFIX;
    const escapedPrefix = prefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    const escapedPrefixNoUnderscore = prefix.replace(/_+$/, '').replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    const namePattern = new RegExp(`^(?:${escapedPrefix}|${escapedPrefixNoUnderscore})(\\d+)$`);
    let maxIndex = 0;
    try {
      const all = typeof (variableModel === null || variableModel === void 0 ? void 0 : variableModel.getAll) === 'function' ? variableModel.getAll() : [];
      for (const variable of all || []) {
        const rawName = variable === null || variable === void 0 ? void 0 : variable.name;
        if (typeof rawName !== 'string') {
          continue;
        }
        const matched = rawName.match(namePattern);
        if (!matched) {
          continue;
        }
        const index = Number(matched[1]);
        if (Number.isFinite(index) && index > maxIndex) {
          maxIndex = index;
        }
      }
    } catch (error) {}
    visionInspectionResultNextIndex = maxIndex + 1;
    visionInspectionResultSeedInitialized = true;
  }
  getNextResultVariableName(variableModel) {
    this.initResultVariableSeed(variableModel);
    const next = `${visioninspection_node_1.VISION_INSPECTION_RESULT_SUFFIX}${visionInspectionResultNextIndex}`;
    visionInspectionResultNextIndex += 1;
    return next;
  }
  initWaypointSeed(waypointModel) {
    if (visionInspectionWaypointSeedInitialized) {
      return;
    }
    const base = this.defaultWaypointName;
    const escapedBase = base.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    const namePattern = new RegExp(`^${escapedBase}(\\d+)$`);
    let maxIndex = 0;
    try {
      const all = typeof (waypointModel === null || waypointModel === void 0 ? void 0 : waypointModel.getWaypoints) === 'function' ? waypointModel.getWaypoints() : [];
      for (const waypoint of all || []) {
        const rawName = (waypoint === null || waypoint === void 0 ? void 0 : waypoint.name) || (typeof (waypoint === null || waypoint === void 0 ? void 0 : waypoint.getName) === 'function' ? waypoint.getName() : '') || (typeof (waypoint === null || waypoint === void 0 ? void 0 : waypoint.getDisplayName) === 'function' ? waypoint.getDisplayName() : '');
        if (typeof rawName !== 'string') {
          continue;
        }
        const matched = rawName.match(namePattern);
        if (!matched) {
          continue;
        }
        const index = Number(matched[1]);
        if (Number.isFinite(index) && index > maxIndex) {
          maxIndex = index;
        }
      }
    } catch (error) {}
    visionInspectionWaypointNextIndex = maxIndex + 1;
    visionInspectionWaypointSeedInitialized = true;
  }
  getNextWaypointName(waypointModel) {
    this.initWaypointSeed(waypointModel);
    while (true) {
      const candidate = `${this.defaultWaypointName}${visionInspectionWaypointNextIndex}`;
      visionInspectionWaypointNextIndex += 1;
      if (!this.waypointExists(waypointModel, candidate)) {
        return candidate;
      }
    }
  }
  waypointExists(waypointModel, name) {
    try {
      const all = typeof (waypointModel === null || waypointModel === void 0 ? void 0 : waypointModel.getWaypoints) === 'function' ? waypointModel.getWaypoints() : [];
      for (const waypoint of all || []) {
        const rawName = (waypoint === null || waypoint === void 0 ? void 0 : waypoint.name) || (typeof (waypoint === null || waypoint === void 0 ? void 0 : waypoint.getName) === 'function' ? waypoint.getName() : '') || (typeof (waypoint === null || waypoint === void 0 ? void 0 : waypoint.getDisplayName) === 'function' ? waypoint.getDisplayName() : '');
        if (typeof rawName === 'string' && rawName.trim() === name) {
          return true;
        }
      }
      return false;
    } catch (error) {
      return false;
    }
  }
  createResultVariable() {
    const webscopeService = (0, webscope_service_1.getWebscopeService)();
    if (!webscopeService) {
      throw new Error('Webscope service is not ready');
    }
    const variableModel = webscopeService.getVariableModel();
    const expression = webscopeService.getValueFactory().createExpression();
    expression.append('false');
    const expectedName = this.getNextResultVariableName(variableModel);
    const variable = webscopeService.getVariableModel().getVariableFactory().createGlobalVariable(expectedName, expression);
    if (variable && variable.name !== expectedName) {
      variable.name = expectedName;
    }
    variableModel.addVariable(variable);
    return variable;
  }
  extractWaypointName(value) {
    if (!value || typeof value !== 'object') {
      return '';
    }
    const waypoint = value;
    if (typeof waypoint.name === 'string' && waypoint.name.trim().length > 0) {
      return waypoint.name;
    }
    if (typeof waypoint.getName === 'function') {
      const name = waypoint.getName();
      if (typeof name === 'string' && name.trim().length > 0) {
        return name;
      }
    }
    if (typeof waypoint.getDisplayName === 'function') {
      const displayName = waypoint.getDisplayName();
      if (typeof displayName === 'string' && displayName.trim().length > 0) {
        return displayName;
      }
    }
    return '';
  }
  addWaypointWithExpectedName(waypointModel, expectedName, pose, joint, offset) {
    const created = waypointModel.addWaypoint(expectedName, pose, joint, offset);
    const createdName = this.extractWaypointName(created);
    if (createdName && createdName !== expectedName) {
      try {
        waypointModel.renameWaypoint(createdName, expectedName);
        const renamed = typeof (waypointModel === null || waypointModel === void 0 ? void 0 : waypointModel.getByName) === 'function' ? waypointModel.getByName(expectedName) : null;
        return renamed || created;
      } catch (error) {}
    }
    return created;
  }
  addResultVariable() {
    const variable = this.createResultVariable();
    return variable.name;
  }
  initializeNodeDefaults(node) {
    const webscopeService = (0, webscope_service_1.getWebscopeService)();
    if (!webscopeService) {
      return;
    }
    try {
      const variable = this.createResultVariable();
      if (variable) {
        node.setResultVariable(variable);
      }
    } catch (error) {}
    try {
      const waypointModel = webscopeService.getWaypointModel();
      const zeroPose = [0, 0, 0, 0, 0, 0];
      const waypointName = this.getNextWaypointName(waypointModel);
      const waypoint = this.addWaypointWithExpectedName(waypointModel, waypointName, zeroPose, zeroPose, zeroPose);
      if (waypoint) {
        node.setInspectionWaypoint(waypoint);
      }
    } catch (error) {}
  }
  handleWaypointUpdated(waypointNames) {
    var _a, _b;
    if (!Array.isArray(waypointNames) || waypointNames.length === 0) {
      return;
    }
    const normalizedNames = new Set(waypointNames.map(name => this.normalizeWaypointName(name)).filter(Boolean));
    if (normalizedNames.size === 0) {
      return;
    }
    this.rebuildWaypointIndexIfNeeded();
    const programTree = (_b = (_a = this.programModel) === null || _a === void 0 ? void 0 : _a.getProgramTree) === null || _b === void 0 ? void 0 : _b.call(_a);
    if (!programTree) {
      return;
    }
    for (const waypointName of normalizedNames) {
      const nodeIds = Array.from(this.waypointToNodeIds.get(waypointName) || []);
      for (const nodeId of nodeIds) {
        const treeNode = programTree.getTreeNodeById(nodeId);
        if (!treeNode) {
          this.clearWaypointIndexByNodeId(nodeId);
          continue;
        }
        this.indexTreeNode(treeNode);
        const latestName = this.nodeIdToWaypointName.get(nodeId);
        if (latestName === waypointName && typeof programTree.updateHasDefined === 'function') {
          programTree.updateHasDefined(true, treeNode);
        }
      }
    }
  }
}
exports.VisionInspectionNodeService = VisionInspectionNodeService;
//# sourceMappingURL=visioninspection-node-service.js.map