"use strict";

var __createBinding = void 0 && (void 0).__createBinding || (Object.create ? function (o, m, k, k2) {
  if (k2 === undefined) k2 = k;
  var desc = Object.getOwnPropertyDescriptor(m, k);
  if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
    desc = {
      enumerable: true,
      get: function () {
        return m[k];
      }
    };
  }
  Object.defineProperty(o, k2, desc);
} : function (o, m, k, k2) {
  if (k2 === undefined) k2 = k;
  o[k2] = m[k];
});
var __setModuleDefault = void 0 && (void 0).__setModuleDefault || (Object.create ? function (o, v) {
  Object.defineProperty(o, "default", {
    enumerable: true,
    value: v
  });
} : function (o, v) {
  o["default"] = v;
});
var __importStar = void 0 && (void 0).__importStar || function () {
  var ownKeys = function (o) {
    ownKeys = Object.getOwnPropertyNames || function (o) {
      var ar = [];
      for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
      return ar;
    };
    return ownKeys(o);
  };
  return function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
    __setModuleDefault(result, mod);
    return result;
  };
}();
var __importDefault = void 0 && (void 0).__importDefault || function (mod) {
  return mod && mod.__esModule ? mod : {
    "default": mod
  };
};
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.VisionPickNode = exports.VISION_PICK_NEED_UNLOAD_FLAG_SUFFIX = void 0;
const backend_1 = require("@aubo/wcaps/lib/backend");
const tree_model_1 = __importDefault(require("tree-model"));
const domain_1 = require("../../domain");
const agv_constant_1 = require("../../entity/agv.constant");
const translation_util_1 = __importStar(require("../../utils/translation.util"));
const waypoint_rpc_util_1 = require("../../utils/waypoint-rpc.util");
const scope_setting_1 = require("../../scope-setting");
const webscope_service_1 = require("../../webscope-service");
const TranslationUtil = translation_util_1.default;
exports.VISION_PICK_NEED_UNLOAD_FLAG_SUFFIX = 'Vision_Pick_Need_Unload_Flag_';
class VisionPickNode {
  setEnableCutWaypoint(v) {
    this.enableCutWaypoint = v;
    return this;
  }
  getEnableCutWaypoint() {
    return this.enableCutWaypoint;
  }
  setCutWaypoint(v) {
    this.cutWaypoint = v;
    this.pendingCutWaypointName = this.extractWaypointName(v);
    return this;
  }
  getCutWaypoint() {
    return this.cutWaypoint;
  }
  setCutPose(v) {
    this.cutPose = v;
    return this;
  }
  getCutPose() {
    return this.cutPose;
  }
  setPruneIoChannel(v) {
    this.pruneIoChannel = this.resolveDigitalOutputIo(v);
    return this;
  }
  getPruneIoChannel() {
    return this.pruneIoChannel;
  }
  setPruneIoLevel(v) {
    this.pruneIoLevel = v;
    return this;
  }
  getPruneIoLevel() {
    return this.pruneIoLevel;
  }
  setPruneIoChannel2(v) {
    this.pruneIoChannel2 = this.resolveDigitalOutputIo(v);
    return this;
  }
  getPruneIoChannel2() {
    return this.pruneIoChannel2;
  }
  setPruneIoLevel2(v) {
    this.pruneIoLevel2 = v;
    return this;
  }
  getPruneIoLevel2() {
    return this.pruneIoLevel2;
  }
  setBasketChangeIoChannel(v) {
    this.basketChangeIoChannel = this.resolveDigitalOutputIo(v);
    return this;
  }
  getBasketChangeIoChannel() {
    return this.basketChangeIoChannel;
  }
  setBasketChangeIoLevel(v) {
    this.basketChangeIoLevel = v;
    return this;
  }
  getBasketChangeIoLevel() {
    return this.basketChangeIoLevel;
  }
  setRows(v) {
    this.rows = this.normalizePositiveInt(v, 3);
    return this;
  }
  getRows() {
    return this.rows;
  }
  setCols(v) {
    this.cols = this.normalizePositiveInt(v, 4);
    return this;
  }
  getCols() {
    return this.cols;
  }
  setItemSpec(v) {
    this.itemSpec = v;
    return this;
  }
  getItemSpec() {
    return this.itemSpec;
  }
  setCornerPose1(v) {
    this.cornerPose1 = v;
    this.pendingCornerPose1Name = this.extractWaypointName(v);
    return this;
  }
  getCornerPose1() {
    return this.cornerPose1;
  }
  setCornerPose2(v) {
    this.cornerPose2 = v;
    this.pendingCornerPose2Name = this.extractWaypointName(v);
    return this;
  }
  getCornerPose2() {
    return this.cornerPose2;
  }
  setCornerPose3(v) {
    this.cornerPose3 = v;
    this.pendingCornerPose3Name = this.extractWaypointName(v);
    return this;
  }
  getCornerPose3() {
    return this.cornerPose3;
  }
  setCornerPose4(v) {
    this.cornerPose4 = v;
    this.pendingCornerPose4Name = this.extractWaypointName(v);
    return this;
  }
  getCornerPose4() {
    return this.cornerPose4;
  }
  setCenterBottomPose(v) {
    this.centerBottomPose = v;
    this.pendingCenterBottomPoseName = this.extractWaypointName(v);
    return this;
  }
  getCenterBottomPose() {
    return this.centerBottomPose;
  }
  setBasketCount(v) {
    this.basketCount = this.normalizePositiveInt(v, 6);
    return this;
  }
  getBasketCount() {
    return this.basketCount;
  }
  setNeedUnloadFlagVariable(v) {
    this.needUnloadFlagVariable = v;
    this.pendingNeedUnloadFlagVariableName = this.extractVariableName(v);
    return this;
  }
  getNeedUnloadFlagVariable() {
    return this.needUnloadFlagVariable;
  }
  createDigitalOutputIo(channel, name) {
    const ioName = name !== null && name !== void 0 ? name : `Standard Digital Output ${channel}`;
    const io = new domain_1.IoInternal(ioName, ioName, backend_1.InterfaceType.STANDARD, backend_1.IoType.DIGITAL, false, channel);
    io.setResolvable(false);
    return io;
  }
  extractChannelFromIoName(name) {
    if (typeof name !== 'string' || name.trim().length === 0) {
      return null;
    }
    const matched = name.match(/(\d+)\s*$/);
    if (!matched) {
      return null;
    }
    const parsed = Number(matched[1]);
    return Number.isFinite(parsed) ? parsed : null;
  }
  extractIoIndex(value) {
    if (value && typeof value === 'object' && typeof value.getIndex === 'function') {
      const index = Number(value.getIndex());
      return Number.isFinite(index) ? index : null;
    }
    if (value && typeof value === 'object' && Number.isFinite(Number(value.index))) {
      return Number(value.index);
    }
    return null;
  }
  isSameDigitalOutputIo(a, b) {
    const nameA = this.extractIoName(a);
    const nameB = this.extractIoName(b);
    const indexA = this.extractIoIndex(a);
    const indexB = this.extractIoIndex(b);
    return nameA === nameB && indexA === indexB;
  }
  resolveDigitalOutputIo(value, ioModel) {
    if (typeof (value === null || value === void 0 ? void 0 : value.getDisplayName) === 'function') {
      return value;
    }
    if (value && typeof value === 'object') {
      const objectValue = value;
      const objectName = typeof objectValue.name === 'string' && objectValue.name || typeof objectValue.defaultName === 'string' && objectValue.defaultName || '';
      if (objectName) {
        const ioByName = ioModel === null || ioModel === void 0 ? void 0 : ioModel.getIo(objectName);
        if (ioByName) {
          return ioByName;
        }
        const parsedFromName = this.extractChannelFromIoName(objectName);
        if (parsedFromName !== null) {
          return this.createDigitalOutputIo(parsedFromName, objectName);
        }
      }
      const objectIndex = Number(objectValue.index);
      if (Number.isFinite(objectIndex)) {
        return this.createDigitalOutputIo(objectIndex, objectName || undefined);
      }
      if (objectName) {
        return this.createDigitalOutputIo(0, objectName);
      }
    }
    if (typeof value === 'string') {
      const ioByName = ioModel === null || ioModel === void 0 ? void 0 : ioModel.getIo(value);
      if (ioByName) {
        return ioByName;
      }
      const parsedFromName = this.extractChannelFromIoName(value);
      if (parsedFromName !== null) {
        return this.createDigitalOutputIo(parsedFromName, value);
      }
      const channel = Number(value);
      if (Number.isFinite(channel)) {
        return this.createDigitalOutputIo(channel, value);
      }
      return this.createDigitalOutputIo(0, value);
    }
    if (typeof value === 'number' && Number.isFinite(value)) {
      return this.createDigitalOutputIo(value);
    }
    return this.createDigitalOutputIo(0);
  }
  setDataModel(dataModel) {
    this.dataModel = dataModel;
    const enableCutWaypoint = dataModel.get(this.VisionPickEnableCutWaypointKey, null);
    if (this.isBoolean(enableCutWaypoint)) {
      this.enableCutWaypoint = enableCutWaypoint;
    }
    const cutWaypoint = dataModel.get(this.VisionPickCutWaypointKey, null);
    if (this.isWaypoint(cutWaypoint)) {
      this.cutWaypoint = cutWaypoint;
      this.pendingCutWaypointName = this.extractWaypointName(cutWaypoint);
    } else if (typeof cutWaypoint === 'string' && cutWaypoint) {
      this.pendingCutWaypointName = cutWaypoint;
    }
    const cutPoseRaw = dataModel.get(this.VisionPickCutPoseKey, null);
    const cutPose = this.toFiniteNumber(cutPoseRaw);
    if (cutPose !== null) {
      this.cutPose = cutPose;
    }
    const pruneIoChannel = dataModel.get(this.VisionPickPruneIoChannelKey, null);
    if (this.isIo(pruneIoChannel)) {
      this.pruneIoChannel = pruneIoChannel;
    }
    const pruneIoLevel = dataModel.get(this.VisionPickPruneIoLevelKey, null);
    if (this.isBoolean(pruneIoLevel)) {
      this.pruneIoLevel = pruneIoLevel;
    }
    const pruneIoChannel2 = dataModel.get(this.VisionPickPruneIoChannel2Key, null);
    if (this.isIo(pruneIoChannel2)) {
      this.pruneIoChannel2 = pruneIoChannel2;
    }
    const pruneIoLevel2 = dataModel.get(this.VisionPickPruneIoLevel2Key, null);
    if (this.isBoolean(pruneIoLevel2)) {
      this.pruneIoLevel2 = pruneIoLevel2;
    }
    const basketChangeIoChannel = dataModel.get(this.VisionPickBasketChangeIoChannelKey, null);
    if (this.isIo(basketChangeIoChannel)) {
      this.basketChangeIoChannel = basketChangeIoChannel;
    }
    const basketChangeIoLevel = dataModel.get(this.VisionPickBasketChangeIoLevelKey, null);
    if (this.isBoolean(basketChangeIoLevel)) {
      this.basketChangeIoLevel = basketChangeIoLevel;
    }
    const rows = dataModel.get(this.VisionPickRowsKey, null);
    if (this.isNumber(rows)) {
      this.rows = rows;
    }
    const cols = dataModel.get(this.VisionPickColsKey, null);
    if (this.isNumber(cols)) {
      this.cols = cols;
    }
    const itemSpec = dataModel.get(this.VisionPickItemSpecKey, null);
    if (this.isString(itemSpec)) {
      this.itemSpec = itemSpec;
    }
    const cornerPose1 = dataModel.get(this.VisionPickCorner1Key, null);
    if (this.isWaypoint(cornerPose1)) {
      this.cornerPose1 = cornerPose1;
      this.pendingCornerPose1Name = this.extractWaypointName(cornerPose1);
    } else if (typeof cornerPose1 === 'string' && cornerPose1) {
      this.pendingCornerPose1Name = cornerPose1;
    }
    const cornerPose2 = dataModel.get(this.VisionPickCorner2Key, null);
    if (this.isWaypoint(cornerPose2)) {
      this.cornerPose2 = cornerPose2;
      this.pendingCornerPose2Name = this.extractWaypointName(cornerPose2);
    } else if (typeof cornerPose2 === 'string' && cornerPose2) {
      this.pendingCornerPose2Name = cornerPose2;
    }
    const cornerPose3 = dataModel.get(this.VisionPickCorner3Key, null);
    if (this.isWaypoint(cornerPose3)) {
      this.cornerPose3 = cornerPose3;
      this.pendingCornerPose3Name = this.extractWaypointName(cornerPose3);
    } else if (typeof cornerPose3 === 'string' && cornerPose3) {
      this.pendingCornerPose3Name = cornerPose3;
    }
    const cornerPose4 = dataModel.get(this.VisionPickCorner4Key, null);
    if (this.isWaypoint(cornerPose4)) {
      this.cornerPose4 = cornerPose4;
      this.pendingCornerPose4Name = this.extractWaypointName(cornerPose4);
    } else if (typeof cornerPose4 === 'string' && cornerPose4) {
      this.pendingCornerPose4Name = cornerPose4;
    }
    const centerBottomPose = dataModel.get(this.VisionPickCenterBottomPoseKey, null);
    if (this.isWaypoint(centerBottomPose)) {
      this.centerBottomPose = centerBottomPose;
      this.pendingCenterBottomPoseName = this.extractWaypointName(centerBottomPose);
    } else if (typeof centerBottomPose === 'string' && centerBottomPose) {
      this.pendingCenterBottomPoseName = centerBottomPose;
    }
    const basketCount = dataModel.get(this.VisionPickBasketCountKey, null);
    if (this.isNumber(basketCount)) {
      this.basketCount = this.normalizePositiveInt(basketCount, 6);
    }
    const needUnloadFlagVariableRaw = dataModel.get(this.VisionPickNeedUnloadFlagVariableKey, null);
    const needUnloadFlagVariable = needUnloadFlagVariableRaw && typeof needUnloadFlagVariableRaw === 'object' && 'value' in needUnloadFlagVariableRaw ? needUnloadFlagVariableRaw.value : needUnloadFlagVariableRaw;
    const needUnloadIncomingHasDefined = !!(needUnloadFlagVariableRaw && typeof needUnloadFlagVariableRaw === 'object' && 'hasDefined' in needUnloadFlagVariableRaw && needUnloadFlagVariableRaw.hasDefined === true);
    if (this.isVariable(needUnloadFlagVariable)) {
      this.needUnloadFlagVariable = needUnloadFlagVariable;
      this.pendingNeedUnloadFlagVariableName = this.extractVariableName(needUnloadFlagVariable);
    } else if (typeof needUnloadFlagVariable === 'string' && needUnloadFlagVariable) {
      this.pendingNeedUnloadFlagVariableName = needUnloadFlagVariable;
    }
    if (needUnloadIncomingHasDefined || !!this.pendingNeedUnloadFlagVariableName) {
      this.needUnloadFlagForcedDefined = true;
    }
  }
  getDataModel() {
    this.dataModel.set(this.VisionPickEnableCutWaypointKey, this.enableCutWaypoint, domain_1.XmlLabelType.BOOL);
    this.dataModel.set(this.VisionPickCutWaypointKey, this.cutWaypoint, domain_1.XmlLabelType.WAYPOINT);
    this.dataModel.set(this.VisionPickCutPoseKey, this.cutPose, domain_1.XmlLabelType.FLOAT64);
    this.dataModel.set(this.VisionPickPruneIoChannelKey, this.pruneIoChannel, domain_1.XmlLabelType.DIGITAL_IO);
    this.dataModel.set(this.VisionPickPruneIoLevelKey, this.pruneIoLevel, domain_1.XmlLabelType.BOOL);
    this.dataModel.set(this.VisionPickPruneIoChannel2Key, this.pruneIoChannel2, domain_1.XmlLabelType.DIGITAL_IO);
    this.dataModel.set(this.VisionPickPruneIoLevel2Key, this.pruneIoLevel2, domain_1.XmlLabelType.BOOL);
    this.dataModel.set(this.VisionPickBasketChangeIoChannelKey, this.basketChangeIoChannel, domain_1.XmlLabelType.DIGITAL_IO);
    this.dataModel.set(this.VisionPickBasketChangeIoLevelKey, this.basketChangeIoLevel, domain_1.XmlLabelType.BOOL);
    this.dataModel.set(this.VisionPickRowsKey, this.rows, domain_1.XmlLabelType.INT32);
    this.dataModel.set(this.VisionPickColsKey, this.cols, domain_1.XmlLabelType.INT32);
    this.dataModel.set(this.VisionPickItemSpecKey, this.itemSpec, domain_1.XmlLabelType.STRING);
    this.dataModel.set(this.VisionPickCorner1Key, this.cornerPose1, domain_1.XmlLabelType.WAYPOINT);
    this.dataModel.set(this.VisionPickCorner2Key, this.cornerPose2, domain_1.XmlLabelType.WAYPOINT);
    this.dataModel.set(this.VisionPickCorner3Key, this.cornerPose3, domain_1.XmlLabelType.WAYPOINT);
    this.dataModel.set(this.VisionPickCorner4Key, this.cornerPose4, domain_1.XmlLabelType.WAYPOINT);
    this.dataModel.set(this.VisionPickCenterBottomPoseKey, this.centerBottomPose, domain_1.XmlLabelType.WAYPOINT);
    this.dataModel.set(this.VisionPickBasketCountKey, this.basketCount, domain_1.XmlLabelType.INT32);
    this.dataModel.set(this.VisionPickNeedUnloadFlagVariableKey, this.needUnloadFlagVariable, domain_1.XmlLabelType.VARIABLE);
    return this.dataModel;
  }
  setId(id) {
    this.id = id;
  }
  update(config) {
    var _a, _b;
    let updated = false;
    const ioModel = (_b = (_a = this.programModel).getIoModel) === null || _b === void 0 ? void 0 : _b.call(_a);
    for (const key in config) {
      const raw = config[key];
      const value = raw && typeof raw === 'object' && 'value' in raw ? raw.value : raw;
      if (key === this.VisionPickEnableCutWaypointKey) {
        if (typeof value === 'boolean' && value !== this.getEnableCutWaypoint()) {
          this.setEnableCutWaypoint(value);
          updated = true;
        }
      } else if (key === this.VisionPickCutWaypointKey) {
        if (value === null) {
          const hasPending = !!this.pendingCutWaypointName;
          if (this.getCutWaypoint() !== null || hasPending) {
            this.setCutWaypoint(null);
            this.pendingCutWaypointName = null;
            this.forcedDefinedWaypointKeys.delete(this.VisionPickCutWaypointKey);
            updated = true;
          }
        } else {
          const incomingWaypointName = this.extractWaypointName(value);
          const currentWaypointName = this.extractWaypointName(this.getCutWaypoint());
          const lockedWaypointName = currentWaypointName || this.pendingCutWaypointName;
          const waypointName = lockedWaypointName || incomingWaypointName;
          const hasPendingNameChanged = !lockedWaypointName && waypointName !== this.pendingCutWaypointName;
          if (hasPendingNameChanged) {
            this.pendingCutWaypointName = waypointName;
          }
          const waypoint = this.resolveWaypointByName(waypointName);
          if (!waypoint && this.getCutWaypoint() !== null && !!lockedWaypointName) {
            continue;
          }
          if (waypoint !== this.getCutWaypoint()) {
            this.setCutWaypoint(waypoint);
            updated = true;
          }
          if (hasPendingNameChanged) {
            updated = true;
          }
        }
      } else if (key === this.VisionPickCutPoseKey) {
        if (this.isNumber(Number(value)) && Number(value) !== this.getCutPose()) {
          this.setCutPose(Number(value));
          updated = true;
        }
      } else if (key === this.VisionPickPruneIoChannelKey) {
        const nextIo = this.resolveDigitalOutputIo(value, ioModel);
        if (!this.isSameDigitalOutputIo(this.getPruneIoChannel(), nextIo)) {
          this.setPruneIoChannel(nextIo);
          updated = true;
        }
      } else if (key === this.VisionPickPruneIoLevelKey) {
        if (typeof value === 'boolean' && value !== this.getPruneIoLevel()) {
          this.setPruneIoLevel(value);
          updated = true;
        }
      } else if (key === this.VisionPickPruneIoChannel2Key) {
        const nextIo = this.resolveDigitalOutputIo(value, ioModel);
        if (!this.isSameDigitalOutputIo(this.getPruneIoChannel2(), nextIo)) {
          this.setPruneIoChannel2(nextIo);
          updated = true;
        }
      } else if (key === this.VisionPickPruneIoLevel2Key) {
        if (typeof value === 'boolean' && value !== this.getPruneIoLevel2()) {
          this.setPruneIoLevel2(value);
          updated = true;
        }
      } else if (key === this.VisionPickBasketChangeIoChannelKey) {
        const nextIo = this.resolveDigitalOutputIo(value, ioModel);
        if (!this.isSameDigitalOutputIo(this.getBasketChangeIoChannel(), nextIo)) {
          this.setBasketChangeIoChannel(nextIo);
          updated = true;
        }
      } else if (key === this.VisionPickBasketChangeIoLevelKey) {
        if (typeof value === 'boolean' && value !== this.getBasketChangeIoLevel()) {
          this.setBasketChangeIoLevel(value);
          updated = true;
        }
      } else if (key === this.VisionPickRowsKey) {
        if (this.isNumber(Number(value)) && Number(value) !== this.getRows()) {
          this.setRows(Number(value));
          updated = true;
        }
      } else if (key === this.VisionPickColsKey) {
        if (this.isNumber(Number(value)) && Number(value) !== this.getCols()) {
          this.setCols(Number(value));
          updated = true;
        }
      } else if (key === this.VisionPickItemSpecKey) {
        if (value === null) {
          if (this.getItemSpec() !== '') {
            this.setItemSpec('');
            updated = true;
          }
        } else if (this.isString(value) && value !== this.getItemSpec()) {
          this.setItemSpec(value);
          updated = true;
        }
      } else if (key === this.VisionPickCorner1Key) {
        if (value === null) {
          const hasPending = !!this.pendingCornerPose1Name;
          if (this.getCornerPose1() !== null || hasPending) {
            this.setCornerPose1(null);
            this.pendingCornerPose1Name = null;
            this.forcedDefinedWaypointKeys.delete(this.VisionPickCorner1Key);
            updated = true;
          }
        } else {
          const incomingWaypointName = this.extractWaypointName(value);
          const currentWaypointName = this.extractWaypointName(this.getCornerPose1());
          const lockedWaypointName = currentWaypointName || this.pendingCornerPose1Name;
          const waypointName = lockedWaypointName || incomingWaypointName;
          const hasPendingNameChanged = !lockedWaypointName && waypointName !== this.pendingCornerPose1Name;
          if (hasPendingNameChanged) {
            this.pendingCornerPose1Name = waypointName;
          }
          const waypoint = this.resolveWaypointByName(waypointName);
          if (!waypoint && this.getCornerPose1() !== null && !!lockedWaypointName) {
            continue;
          }
          if (waypoint !== this.getCornerPose1()) {
            this.setCornerPose1(waypoint);
            updated = true;
          }
          if (hasPendingNameChanged) {
            updated = true;
          }
        }
      } else if (key === this.VisionPickCorner2Key) {
        if (value === null) {
          const hasPending = !!this.pendingCornerPose2Name;
          if (this.getCornerPose2() !== null || hasPending) {
            this.setCornerPose2(null);
            this.pendingCornerPose2Name = null;
            this.forcedDefinedWaypointKeys.delete(this.VisionPickCorner2Key);
            updated = true;
          }
        } else {
          const incomingWaypointName = this.extractWaypointName(value);
          const currentWaypointName = this.extractWaypointName(this.getCornerPose2());
          const lockedWaypointName = currentWaypointName || this.pendingCornerPose2Name;
          const waypointName = lockedWaypointName || incomingWaypointName;
          const hasPendingNameChanged = !lockedWaypointName && waypointName !== this.pendingCornerPose2Name;
          if (hasPendingNameChanged) {
            this.pendingCornerPose2Name = waypointName;
          }
          const waypoint = this.resolveWaypointByName(waypointName);
          if (!waypoint && this.getCornerPose2() !== null && !!lockedWaypointName) {
            continue;
          }
          if (waypoint !== this.getCornerPose2()) {
            this.setCornerPose2(waypoint);
            updated = true;
          }
          if (hasPendingNameChanged) {
            updated = true;
          }
        }
      } else if (key === this.VisionPickCorner3Key) {
        if (value === null) {
          const hasPending = !!this.pendingCornerPose3Name;
          if (this.getCornerPose3() !== null || hasPending) {
            this.setCornerPose3(null);
            this.pendingCornerPose3Name = null;
            this.forcedDefinedWaypointKeys.delete(this.VisionPickCorner3Key);
            updated = true;
          }
        } else {
          const incomingWaypointName = this.extractWaypointName(value);
          const currentWaypointName = this.extractWaypointName(this.getCornerPose3());
          const lockedWaypointName = currentWaypointName || this.pendingCornerPose3Name;
          const waypointName = lockedWaypointName || incomingWaypointName;
          const hasPendingNameChanged = !lockedWaypointName && waypointName !== this.pendingCornerPose3Name;
          if (hasPendingNameChanged) {
            this.pendingCornerPose3Name = waypointName;
          }
          const waypoint = this.resolveWaypointByName(waypointName);
          if (!waypoint && this.getCornerPose3() !== null && !!lockedWaypointName) {
            continue;
          }
          if (waypoint !== this.getCornerPose3()) {
            this.setCornerPose3(waypoint);
            updated = true;
          }
          if (hasPendingNameChanged) {
            updated = true;
          }
        }
      } else if (key === this.VisionPickCorner4Key) {
        if (value === null) {
          const hasPending = !!this.pendingCornerPose4Name;
          if (this.getCornerPose4() !== null || hasPending) {
            this.setCornerPose4(null);
            this.pendingCornerPose4Name = null;
            this.forcedDefinedWaypointKeys.delete(this.VisionPickCorner4Key);
            updated = true;
          }
        } else {
          const incomingWaypointName = this.extractWaypointName(value);
          const currentWaypointName = this.extractWaypointName(this.getCornerPose4());
          const lockedWaypointName = currentWaypointName || this.pendingCornerPose4Name;
          const waypointName = lockedWaypointName || incomingWaypointName;
          const hasPendingNameChanged = !lockedWaypointName && waypointName !== this.pendingCornerPose4Name;
          if (hasPendingNameChanged) {
            this.pendingCornerPose4Name = waypointName;
          }
          const waypoint = this.resolveWaypointByName(waypointName);
          if (!waypoint && this.getCornerPose4() !== null && !!lockedWaypointName) {
            continue;
          }
          if (waypoint !== this.getCornerPose4()) {
            this.setCornerPose4(waypoint);
            updated = true;
          }
          if (hasPendingNameChanged) {
            updated = true;
          }
        }
      } else if (key === this.VisionPickCenterBottomPoseKey) {
        if (value === null) {
          const hasPending = !!this.pendingCenterBottomPoseName;
          if (this.getCenterBottomPose() !== null || hasPending) {
            this.setCenterBottomPose(null);
            this.pendingCenterBottomPoseName = null;
            this.forcedDefinedWaypointKeys.delete(this.VisionPickCenterBottomPoseKey);
            updated = true;
          }
        } else {
          const incomingWaypointName = this.extractWaypointName(value);
          const currentWaypointName = this.extractWaypointName(this.getCenterBottomPose());
          const lockedWaypointName = currentWaypointName || this.pendingCenterBottomPoseName;
          const waypointName = lockedWaypointName || incomingWaypointName;
          const hasPendingNameChanged = !lockedWaypointName && waypointName !== this.pendingCenterBottomPoseName;
          if (hasPendingNameChanged) {
            this.pendingCenterBottomPoseName = waypointName;
          }
          const waypoint = this.resolveWaypointByName(waypointName);
          if (!waypoint && this.getCenterBottomPose() !== null && !!lockedWaypointName) {
            continue;
          }
          if (waypoint !== this.getCenterBottomPose()) {
            this.setCenterBottomPose(waypoint);
            updated = true;
          }
          if (hasPendingNameChanged) {
            updated = true;
          }
        }
      } else if (key === this.VisionPickBasketCountKey) {
        if (this.isNumber(Number(value)) && Number(value) !== this.getBasketCount()) {
          this.setBasketCount(Number(value));
          updated = true;
        }
      } else if (key === this.VisionPickNeedUnloadFlagVariableKey) {
        const incomingHasDefined = !!(raw && typeof raw === 'object' && 'hasDefined' in raw && raw.hasDefined === true);
        if (value === null) {
          const hasPending = !!this.pendingNeedUnloadFlagVariableName;
          if (this.getNeedUnloadFlagVariable() !== null || hasPending) {
            this.setNeedUnloadFlagVariable(null);
            this.pendingNeedUnloadFlagVariableName = null;
            this.needUnloadFlagForcedDefined = false;
            updated = true;
          }
        } else {
          const incomingVariableName = this.extractVariableName(value);
          const currentVariableName = this.extractVariableName(this.getNeedUnloadFlagVariable());
          const lockedVariableName = currentVariableName || this.pendingNeedUnloadFlagVariableName;
          const variableName = lockedVariableName || incomingVariableName;
          if (variableName === null && value !== null && value !== undefined) {
            continue;
          }
          const hasPendingNameChanged = !lockedVariableName && variableName !== this.pendingNeedUnloadFlagVariableName;
          if (hasPendingNameChanged) {
            this.pendingNeedUnloadFlagVariableName = variableName;
          }
          const variable = this.resolveVariableByName(variableName);
          if (!variable && this.getNeedUnloadFlagVariable() !== null && !!lockedVariableName) {
            continue;
          }
          if (variable !== this.getNeedUnloadFlagVariable()) {
            this.setNeedUnloadFlagVariable(variable);
            updated = true;
          }
          if ((incomingHasDefined || !!variableName) && !this.needUnloadFlagForcedDefined) {
            this.needUnloadFlagForcedDefined = true;
            updated = true;
          }
          if (hasPendingNameChanged) {
            updated = true;
          }
        }
      }
    }
    return updated;
  }
  dropNode() {}
  toJSON() {
    const result = {};
    const model = this.getDataModel();
    if (!model || typeof model.getKeys !== 'function') {
      return result;
    }
    model.getKeys().forEach(key => {
      const serializedValue = this.toSerializableValue(key, model.get(key, null));
      let hasDefined = !!serializedValue;
      if (key === this.VisionPickCutWaypointKey || key === this.VisionPickCorner1Key || key === this.VisionPickCorner2Key || key === this.VisionPickCorner3Key || key === this.VisionPickCorner4Key || key === this.VisionPickCenterBottomPoseKey) {
        const waypointName = this.extractWaypointName(serializedValue);
        const hasUpdatedByRpc = (0, waypoint_rpc_util_1.hasWaypointBeenUpdated)(waypointName);
        if (hasUpdatedByRpc) {
          this.forcedDefinedWaypointKeys.add(key);
        }
        const latestWaypoint = this.resolveWaypointByName(waypointName);
        hasDefined = this.forcedDefinedWaypointKeys.has(key) || hasUpdatedByRpc || this.hasWaypointPoseDefined(latestWaypoint || model.get(key, null));
      }
      if (key === this.VisionPickNeedUnloadFlagVariableKey) {
        hasDefined = this.needUnloadFlagForcedDefined || !!serializedValue;
      }
      result[key] = {
        value: serializedValue,
        hasDefined
      };
    });
    return result;
  }
  cloneNode(node) {
    const treeModelInstance = new tree_model_1.default();
    const parseTree = treeModelInstance.parse({});
    const {
      children,
      programNode,
      ...restData
    } = node;
    const nodeData = programNode.getDataModel();
    this.setDataModel(nodeData);
    const currentNode = this.programModel.getProgramTree().addChild(parseTree, node.nodeId, this, 0);
    currentNode.model.disabled = node.disabled;
    currentNode.model.isBreakpoint = node.isBreakpoint;
    currentNode.model.suppressedComment = node.suppressedComment;
    return currentNode;
  }
  isString(value) {
    return typeof value === 'string';
  }
  isBoolean(value) {
    return typeof value === 'boolean';
  }
  isNumber(value) {
    return Number.isFinite(value);
  }
  normalizePositiveInt(value, fallback) {
    const normalized = Math.floor(Number(value));
    if (!Number.isFinite(normalized) || normalized < 1) {
      return fallback;
    }
    return normalized;
  }
  toFiniteNumber(value) {
    if (typeof value === 'number' && Number.isFinite(value)) {
      return value;
    }
    if (typeof value === 'string' && value.trim().length > 0) {
      const parsed = Number(value);
      return Number.isFinite(parsed) ? parsed : null;
    }
    if (value && typeof value === 'object' && 'value' in value) {
      const nested = value.value;
      if (typeof nested === 'number' && Number.isFinite(nested)) {
        return nested;
      }
      if (typeof nested === 'string' && nested.trim().length > 0) {
        const parsed = Number(nested);
        return Number.isFinite(parsed) ? parsed : null;
      }
    }
    return null;
  }
  hasWaypointPoseDefined(value) {
    var _a, _b, _c;
    if (!this.isWaypoint(value)) {
      return false;
    }
    const waypoint = value;
    const pose = Array.isArray((_a = waypoint.getPose) === null || _a === void 0 ? void 0 : _a.call(waypoint)) ? waypoint.getPose() : [];
    const joint = Array.isArray((_b = waypoint.getJointPositions) === null || _b === void 0 ? void 0 : _b.call(waypoint)) ? waypoint.getJointPositions() : [];
    const offset = Array.isArray((_c = waypoint.getTcpOffset) === null || _c === void 0 ? void 0 : _c.call(waypoint)) ? waypoint.getTcpOffset() : [];
    const hasNonZero = arr => arr.some(item => Math.abs(Number(item !== null && item !== void 0 ? item : 0)) > 1e-9);
    return hasNonZero(pose) || hasNonZero(joint) || hasNonZero(offset);
  }
  isWaypoint(value) {
    return typeof value === 'object' && value !== null && typeof value.getPose === 'function';
  }
  isVariable(value) {
    return typeof value === 'object' && value !== null && typeof value.getDisplayName === 'function' && typeof value.getType === 'function';
  }
  extractVariableName(value) {
    if (typeof value === 'string' && value) {
      return value;
    }
    if (!value || typeof value !== 'object') {
      return null;
    }
    const variable = value;
    if (typeof variable.name === 'string' && variable.name) {
      return variable.name;
    }
    if (typeof variable.getDisplayName === 'function') {
      const displayName = variable.getDisplayName();
      if (typeof displayName === 'string' && displayName) {
        return displayName;
      }
    }
    if (typeof variable.getName === 'function') {
      const name = variable.getName();
      if (typeof name === 'string' && name) {
        return name;
      }
    }
    return null;
  }
  extractWaypointName(value) {
    if (typeof value === 'string' && value) {
      return value;
    }
    if (!value || typeof value !== 'object') {
      return null;
    }
    const waypoint = value;
    if (typeof waypoint.name === 'string' && waypoint.name) {
      return waypoint.name;
    }
    if (typeof waypoint.getName === 'function') {
      const name = waypoint.getName();
      if (typeof name === 'string' && name) {
        return name;
      }
    }
    if (typeof waypoint.value === 'string' && waypoint.value) {
      return waypoint.value;
    }
    if (typeof waypoint.getDisplayName === 'function') {
      const displayName = waypoint.getDisplayName();
      if (typeof displayName === 'string' && displayName) {
        return displayName;
      }
    }
    return null;
  }
  resolveWaypoint(value) {
    const waypointName = this.extractWaypointName(value);
    return this.resolveWaypointByName(waypointName);
  }
  resolveWaypointByName(waypointName) {
    const webscopeService = (0, webscope_service_1.getWebscopeService)();
    if (!waypointName || !webscopeService) {
      return null;
    }
    try {
      const waypoint = webscopeService.getWaypointModel().getByName(waypointName);
      return this.isWaypoint(waypoint) ? waypoint : null;
    } catch (error) {
      return null;
    }
  }
  resolveVariable(value) {
    const variableName = this.extractVariableName(value);
    return this.resolveVariableByName(variableName);
  }
  resolveVariableByName(variableName) {
    const webscopeService = (0, webscope_service_1.getWebscopeService)();
    if (!variableName || !webscopeService) {
      return null;
    }
    const variableModel = webscopeService.getVariableModel();
    try {
      const byName = typeof (variableModel === null || variableModel === void 0 ? void 0 : variableModel.getByName) === 'function' ? variableModel.getByName(variableName) : null;
      if (this.isVariable(byName)) {
        return byName;
      }
    } catch (error) {}
    try {
      const byGet = typeof (variableModel === null || variableModel === void 0 ? void 0 : variableModel.get) === 'function' ? variableModel.get(variableName) : null;
      if (this.isVariable(byGet)) {
        return byGet;
      }
    } catch (error) {}
    return null;
  }
  toSerializableValue(key, value) {
    if (key === this.VisionPickPruneIoChannelKey) {
      return this.toSerializableIoValue(value);
    }
    if (key === this.VisionPickPruneIoChannel2Key) {
      return this.toSerializableIoValue(value);
    }
    if (key === this.VisionPickBasketChangeIoChannelKey) {
      return this.toSerializableIoValue(value);
    }
    if (key === this.VisionPickCutWaypointKey) {
      return this.extractWaypointName(value) || this.pendingCutWaypointName;
    }
    if (key === this.VisionPickCorner1Key) {
      return this.extractWaypointName(value) || this.pendingCornerPose1Name;
    }
    if (key === this.VisionPickCorner2Key) {
      return this.extractWaypointName(value) || this.pendingCornerPose2Name;
    }
    if (key === this.VisionPickCorner3Key) {
      return this.extractWaypointName(value) || this.pendingCornerPose3Name;
    }
    if (key === this.VisionPickCorner4Key) {
      return this.extractWaypointName(value) || this.pendingCornerPose4Name;
    }
    if (key === this.VisionPickCenterBottomPoseKey) {
      return this.extractWaypointName(value) || this.pendingCenterBottomPoseName;
    }
    if (key === this.VisionPickNeedUnloadFlagVariableKey) {
      return this.extractVariableName(value) || this.pendingNeedUnloadFlagVariableName;
    }
    return value;
  }
  toSerializableIoValue(value) {
    const name = this.extractIoName(value).trim();
    if (!name) {
      return {};
    }
    return {
      name
    };
  }
  extractIoName(value) {
    if (typeof value === 'string') {
      return value;
    }
    if (!value || typeof value !== 'object') {
      return '';
    }
    const io = value;
    if (typeof io.name === 'string') {
      return io.name;
    }
    if (typeof io.getDisplayName === 'function') {
      const displayName = io.getDisplayName();
      if (typeof displayName === 'string') {
        return displayName;
      }
    }
    if (typeof io.getDefaultName === 'function') {
      const defaultName = io.getDefaultName();
      if (typeof defaultName === 'string') {
        return defaultName;
      }
    }
    return '';
  }
  isIo(value) {
    return typeof value === 'object' && value !== null && typeof value.getDisplayName === 'function' && typeof value.getType === 'function' && typeof value.getInterfaceType === 'function';
  }
  constructor(programModel) {
    this.VisionPickEnableCutWaypointKey = 'enable_cut_waypoint';
    this.VisionPickCutWaypointKey = 'cut_waypoint';
    this.VisionPickCutPoseKey = 'cut_pose';
    this.VisionPickPruneIoChannelKey = 'prune_io_channel';
    this.VisionPickPruneIoLevelKey = 'prune_io_level';
    this.VisionPickPruneIoChannel2Key = 'prune_io_channel_2';
    this.VisionPickPruneIoLevel2Key = 'prune_io_level_2';
    this.VisionPickBasketChangeIoChannelKey = 'basket_change_io_channel';
    this.VisionPickBasketChangeIoLevelKey = 'basket_change_io_level';
    this.VisionPickRowsKey = 'rows';
    this.VisionPickColsKey = 'cols';
    this.VisionPickItemSpecKey = 'item_spec';
    this.VisionPickCorner1Key = 'corner_pose_1';
    this.VisionPickCorner2Key = 'corner_pose_2';
    this.VisionPickCorner3Key = 'corner_pose_3';
    this.VisionPickCorner4Key = 'corner_pose_4';
    this.VisionPickCenterBottomPoseKey = 'center_bottom_pose';
    this.VisionPickBasketCountKey = 'basket_count';
    this.VisionPickNeedUnloadFlagVariableKey = 'need_unload_flag_variable';
    this.enableCutWaypoint = false;
    this.cutWaypoint = null;
    this.cutPose = 0;
    this.pruneIoChannel = this.createDigitalOutputIo(0);
    this.pruneIoLevel = true;
    this.pruneIoChannel2 = this.createDigitalOutputIo(1);
    this.pruneIoLevel2 = false;
    this.basketChangeIoChannel = this.createDigitalOutputIo(1);
    this.basketChangeIoLevel = true;
    this.rows = 3;
    this.cols = 4;
    this.itemSpec = '';
    this.cornerPose1 = null;
    this.cornerPose2 = null;
    this.cornerPose3 = null;
    this.cornerPose4 = null;
    this.centerBottomPose = null;
    this.basketCount = 6;
    this.needUnloadFlagVariable = null;
    this.pendingCutWaypointName = null;
    this.pendingCornerPose1Name = null;
    this.pendingCornerPose2Name = null;
    this.pendingCornerPose3Name = null;
    this.pendingCornerPose4Name = null;
    this.pendingCenterBottomPoseName = null;
    this.pendingNeedUnloadFlagVariableName = null;
    this.needUnloadFlagForcedDefined = false;
    this.id = '';
    this.DEFAULT_VISION_TARGET_TYPE = 10010100;
    this.forcedDefinedWaypointKeys = new Set();
    this.setEnableCutWaypoint(false);
    this.setCutWaypoint(null);
    this.setCutPose(0);
    this.setPruneIoChannel(0);
    this.setPruneIoLevel(true);
    this.setPruneIoChannel2(1);
    this.setPruneIoLevel2(false);
    this.setBasketChangeIoChannel(1);
    this.setBasketChangeIoLevel(true);
    this.setRows(3);
    this.setCols(4);
    this.setItemSpec('');
    this.setCornerPose1(null);
    this.setCornerPose2(null);
    this.setCornerPose3(null);
    this.setCornerPose4(null);
    this.setCenterBottomPose(null);
    this.setBasketCount(6);
    this.setNeedUnloadFlagVariable(null);
    this.programModel = programModel;
    this.node = this;
  }
  toLuaPose(waypoint) {
    var _a, _b, _c, _d, _e, _f;
    if (!waypoint || typeof waypoint.getPose !== 'function') {
      return `{x=0, y=0, z=0, rx=0, ry=0, rz=0}`;
    }
    const pose = waypoint.getPose() || [];
    const x = Number((_a = pose[0]) !== null && _a !== void 0 ? _a : 0);
    const y = Number((_b = pose[1]) !== null && _b !== void 0 ? _b : 0);
    const z = Number((_c = pose[2]) !== null && _c !== void 0 ? _c : 0);
    const rx = Number((_d = pose[3]) !== null && _d !== void 0 ? _d : 0);
    const ry = Number((_e = pose[4]) !== null && _e !== void 0 ? _e : 0);
    const rz = Number((_f = pose[5]) !== null && _f !== void 0 ? _f : 0);
    return `{x=${x}, y=${y}, z=${z}, rx=${rx}, ry=${ry}, rz=${rz}}`;
  }
  generateScript(scriptWriter) {
    var _a, _b;
    const tree_node = (_b = (_a = this.programModel) === null || _a === void 0 ? void 0 : _a.getProgramTree().getTreeNodeById(this.id)) === null || _b === void 0 ? void 0 : _b.model;
    if (!tree_node) {
      return;
    }
    const row = tree_node.lineNumber;
    const enableCutWaypoint = Boolean(this.getEnableCutWaypoint());
    const cutWaypoint = this.toLuaPose(this.getCutWaypoint());
    const pruneIo = this.getPruneIoChannel();
    const pruneIo2 = this.getPruneIoChannel2();
    const pruneIoCloseLevel = this.getPruneIoLevel() ? 'true' : 'false';
    const pruneIo2CloseLevel = this.getPruneIoLevel2() ? 'true' : 'false';
    const basketChangeIo = this.getBasketChangeIoChannel();
    const basketPulseHighLevel = `true`;
    const basketPulseLowLevel = `false`;
    const rows = Math.max(1, Number(this.getRows() || 1));
    const cols = Math.max(1, Number(this.getCols() || 1));
    const basketCount = this.normalizePositiveInt(this.getBasketCount(), 6);
    const defaultTargetType = this.DEFAULT_VISION_TARGET_TYPE;
    const itemSpec = this.getItemSpec() || '';
    const needUnloadFlagVarName = this.extractVariableName(this.getNeedUnloadFlagVariable());
    const c1 = this.toLuaPose(this.getCornerPose1());
    const c2 = this.toLuaPose(this.getCornerPose2());
    const c3 = this.toLuaPose(this.getCornerPose3());
    const c4 = this.toLuaPose(this.getCornerPose4());
    const hasCenterBottomPose = Boolean(this.getCenterBottomPose());
    const centerBottomPose = this.toLuaPose(this.getCenterBottomPose());
    const pruneIoIndex = pruneIo && pruneIo.getInterfaceType() === backend_1.InterfaceType.TOOL ? pruneIo.getIndex() === 1 ? 1 : 0 : 0;
    const pruneIo2Index = pruneIo2 && pruneIo2.getInterfaceType() === backend_1.InterfaceType.TOOL ? pruneIo2.getIndex() === 1 ? 1 : 0 : 1;
    const scissorPulseHighLevel = `true`;
    const scissorPulseLowLevel = `false`;
    scriptWriter.appendLine(`function _aubo_lerp_${row}(a, b, t)`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`return a + (b - a) * t`);
    scriptWriter.end();
    scriptWriter.lineFeed();
    scriptWriter.appendLine(`function _aubo_pose_to_vec6_${row}(p)`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`if p == nil then return {0, 0, 0, 0, 0, 0} end`);
    scriptWriter.appendLine(`if p.x ~= nil then return {p.x, p.y, p.z, p.rx, p.ry, p.rz} end`);
    scriptWriter.appendLine(`return p`);
    scriptWriter.end();
    scriptWriter.lineFeed();
    scriptWriter.appendLine(`function _aubo_move_line_until_reached_${row}(pose, a, v, blend, duration)`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`moveLine(_aubo_pose_to_vec6_${row}(pose), a, v, blend, duration)`);
    scriptWriter.end();
    scriptWriter.lineFeed();
    scriptWriter.appendLine(`function _aubo_move_joint_until_reached_${row}(pose, a, v, blend, duration)`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`local ok, err = pcall(function()`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`moveJoint(inverseKinematics(getJointPositions(), _aubo_pose_to_vec6_${row}(pose)), a, v, blend, duration)`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end)`);
    scriptWriter.appendLine(`if not ok then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`textmsg("vision pick warn: moveJoint failed, fallback to moveLine, err=" .. tostring(err))`);
    scriptWriter.appendLine(`moveLine(_aubo_pose_to_vec6_${row}(pose), 0.2, 0.1, blend, duration)`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.end();
    scriptWriter.lineFeed();
    scriptWriter.appendLine(`function _aubo_calc_place_segment_poses_${row}(r, c, rows, cols)`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`local c1 = ${c1}`);
    scriptWriter.appendLine(`local c2 = ${c2}`);
    scriptWriter.appendLine(`local c3 = ${c3}`);
    scriptWriter.appendLine(`local c4 = ${c4}`);
    scriptWriter.appendLine(`local center_bottom = ${centerBottomPose}`);
    scriptWriter.appendLine(`local rt0 = rows > 0 and (r / rows) or 0`);
    scriptWriter.appendLine(`local rt1 = rows > 0 and ((r + 1) / rows) or 1`);
    scriptWriter.appendLine(`local ct0 = cols > 0 and (c / cols) or 0`);
    scriptWriter.appendLine(`local ct1 = cols > 0 and ((c + 1) / cols) or 1`);
    scriptWriter.appendLine(`local ctm = (ct0 + ct1) * 0.5`);
    scriptWriter.appendLine(`local min_depth = 0.010`);
    scriptWriter.appendLine(`local max_depth = 0.080`);
    scriptWriter.appendLine(`local hard_max_depth = 0.120`);
    scriptWriter.appendLine(`local tomato_stem_len = 0.150`);
    scriptWriter.appendLine(`local function _bilerp(rt, ct)`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`local top_x = _aubo_lerp_${row}(c1.x, c2.x, ct)`);
    scriptWriter.appendLine(`local top_y = _aubo_lerp_${row}(c1.y, c2.y, ct)`);
    scriptWriter.appendLine(`local top_z = _aubo_lerp_${row}(c1.z, c2.z, ct)`);
    scriptWriter.appendLine(`local bottom_x = _aubo_lerp_${row}(c3.x, c4.x, ct)`);
    scriptWriter.appendLine(`local bottom_y = _aubo_lerp_${row}(c3.y, c4.y, ct)`);
    scriptWriter.appendLine(`local bottom_z = _aubo_lerp_${row}(c3.z, c4.z, ct)`);
    scriptWriter.appendLine(`local x = _aubo_lerp_${row}(top_x, bottom_x, rt)`);
    scriptWriter.appendLine(`local y = _aubo_lerp_${row}(top_y, bottom_y, rt)`);
    scriptWriter.appendLine(`local z = _aubo_lerp_${row}(top_z, bottom_z, rt)`);
    scriptWriter.appendLine(`return x, y, z`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.appendLine(`local function _safe_place_z(top_z, target_z, label)`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`local depth = top_z - target_z`);
    scriptWriter.appendLine(`if depth > hard_max_depth then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`textmsg("vision pick warn: " .. label .. " depth too large (unsafe), clamp to max depth, depth=" .. tostring(depth))`);
    scriptWriter.appendLine(`depth = max_depth`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.appendLine(`if depth < min_depth then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`textmsg("vision pick warn: " .. label .. " depth too small, clamp to min depth")`);
    scriptWriter.appendLine(`depth = min_depth`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`elseif depth > max_depth then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`textmsg("vision pick warn: " .. label .. " depth too large, clamp to max depth")`);
    scriptWriter.appendLine(`depth = max_depth`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.appendLine(`return top_z - depth`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.appendLine(`local up_x, up_y, up_top_z = _bilerp(rt0, ctm)`);
    scriptWriter.appendLine(`local down_x, down_y, down_top_z = _bilerp(rt1, ctm)`);
    scriptWriter.appendLine(`local down_z = _safe_place_z(down_top_z, center_bottom.z, "down")`);
    scriptWriter.appendLine(`local up_z = _safe_place_z(up_top_z, center_bottom.z, "up")`);
    scriptWriter.appendLine(`local down_pose = { x = down_x, y = down_y, z = down_z, rx = c1.rx, ry = c1.ry, rz = c1.rz }`);
    scriptWriter.appendLine(`local up_pose = { x = up_x, y = up_y, z = up_z, rx = c1.rx, ry = c1.ry, rz = c1.rz }`);
    scriptWriter.appendLine(`local down_approach_pose = { x = down_x, y = down_y, z = down_z + tomato_stem_len, rx = c1.rx, ry = c1.ry, rz = c1.rz }`);
    scriptWriter.appendLine(`local up_approach_pose = { x = up_x, y = up_y, z = up_z + tomato_stem_len, rx = c1.rx, ry = c1.ry, rz = c1.rz }`);
    scriptWriter.appendLine(`return down_pose, up_pose, down_approach_pose, up_approach_pose`);
    scriptWriter.end();
    scriptWriter.lineFeed();
    scriptWriter.appendLine(`function _aubo_vision_status_msg_${row}(status)`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`if status == -1 then return "目标类型错误，无法找到对应type识别目标" end`);
    scriptWriter.appendLine(`if status == -2 then return "rgb图像为空" end`);
    scriptWriter.appendLine(`if status == -3 then return "点云为空" end`);
    scriptWriter.appendLine(`if status == -4 then return "机械臂位姿数据错误（不是6位）" end`);
    scriptWriter.appendLine(`if status == -5 then return "http通信请求失败" end`);
    scriptWriter.appendLine(`if status == -6 then return "通信结果解析失败" end`);
    scriptWriter.appendLine(`if status == -7 then return "识别结果中的位姿数据错误" end`);
    scriptWriter.appendLine(`return "未知错误 status=" .. tostring(status)`);
    scriptWriter.end();
    scriptWriter.lineFeed();
    scriptWriter.appendLine(`function _aubo_popup_error_${row}(msg)`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`sched.sync_program_point()`);
    scriptWriter.appendLine(`clearNamedVariable("_popup_continue_or_stop")`);
    scriptWriter.appendLine(`do`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`local _popup_t = getControlSystemTime()`);
    scriptWriter.appendLine(`popup(TraceLevel.ERROR, "Error", msg, 1)`);
    scriptWriter.appendLine(`halt()`);
    scriptWriter.appendLine(`while not variableUpdated("_popup_continue_or_stop", _popup_t) do sync() end`);
    scriptWriter.appendLine(`if not getBool("_popup_continue_or_stop", true) then halt() end`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.end();
    scriptWriter.lineFeed();
    scriptWriter.appendLine(`function _aubo_to_pick_pose_${row}(pose)`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`if not pose then return {x = 0, y = 0, z = 0, rx = 0, ry = 0, rz = 0} end`);
    scriptWriter.appendLine(`if pose.x ~= nil then return {x = pose.x, y = pose.y, z = pose.z, rx = pose.rx, ry = pose.ry, rz = pose.rz} end`);
    scriptWriter.appendLine(`if pose[1] ~= nil or pose[6] ~= nil then return {x = pose[1] or 0, y = pose[2] or 0, z = pose[3] or 0, rx = pose[4] or 0, ry = pose[5] or 0, rz = pose[6] or 0} end`);
    scriptWriter.appendLine(`if pose[0] ~= nil or pose[5] ~= nil then return {x = pose[0] or 0, y = pose[1] or 0, z = pose[2] or 0, rx = pose[3] or 0, ry = pose[4] or 0, rz = pose[5] or 0} end`);
    scriptWriter.appendLine(`return {x = 0, y = 0, z = 0, rx = 0, ry = 0, rz = 0}`);
    scriptWriter.end();
    scriptWriter.lineFeed();
    scriptWriter.appendLine(`function _aubo_has_pose_data_${row}(pose)`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`if not pose then return false end`);
    scriptWriter.appendLine(`if pose.x ~= nil then return true end`);
    scriptWriter.appendLine(`if pose[1] ~= nil or pose[6] ~= nil then return true end`);
    scriptWriter.appendLine(`if pose[0] ~= nil or pose[5] ~= nil then return true end`);
    scriptWriter.appendLine(`return false`);
    scriptWriter.end();
    scriptWriter.lineFeed();
    scriptWriter.appendLine(`function _aubo_vision_rpc_try_with_timeout_${row}(rpc_call, label, timeout_s)`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`local function _aubo_flatten_pose_result(raw)`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`if raw == nil then return nil end`);
    scriptWriter.appendLine(`local out = { status = tonumber(raw.status) or -6 }`);
    scriptWriter.appendLine(`local p = raw.pose`);
    scriptWriter.appendLine(`if p ~= nil then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`if p.x ~= nil then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`out.pose = {`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`tonumber(p.x) or 0, tonumber(p.y) or 0, tonumber(p.z) or 0,`);
    scriptWriter.appendLine(`tonumber(p.rx) or 0, tonumber(p.ry) or 0, tonumber(p.rz) or 0`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`}`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`elseif p[1] ~= nil or p[6] ~= nil then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`out.pose = {`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`tonumber(p[1]) or 0, tonumber(p[2]) or 0, tonumber(p[3]) or 0,`);
    scriptWriter.appendLine(`tonumber(p[4]) or 0, tonumber(p[5]) or 0, tonumber(p[6]) or 0`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`}`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`elseif p[0] ~= nil or p[5] ~= nil then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`out.pose = {`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`tonumber(p[0]) or 0, tonumber(p[1]) or 0, tonumber(p[2]) or 0,`);
    scriptWriter.appendLine(`tonumber(p[3]) or 0, tonumber(p[4]) or 0, tonumber(p[5]) or 0`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`}`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.appendLine(`return out`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.appendLine(`local done = false`);
    scriptWriter.appendLine(`local ok = false`);
    scriptWriter.appendLine(`local rsp = nil`);
    scriptWriter.appendLine(`local err = nil`);
    scriptWriter.appendLine(`local h = thread(function()`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`ok, rsp = pcall(rpc_call)`);
    scriptWriter.appendLine(`if not ok then err = rsp end`);
    scriptWriter.appendLine(`if ok then rsp = _aubo_flatten_pose_result(rsp) end`);
    scriptWriter.appendLine(`done = true`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end, "thread_vision_rpc_${row}")`);
    scriptWriter.appendLine(`run(h)`);
    scriptWriter.appendLine(`local t0 = getControlSystemTime()`);
    scriptWriter.appendLine(`local timeout_ns = math.floor((timeout_s or 3.0) * 1000000000)`);
    scriptWriter.appendLine(`while not done do`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`if (getControlSystemTime() - t0) > timeout_ns then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`kill(h)`);
    scriptWriter.appendLine(`return false, nil, "timeout"`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.appendLine(`sync()`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.appendLine(`if not ok then return false, nil, tostring(err) end`);
    scriptWriter.appendLine(`if rsp == nil then return false, nil, "nil response" end`);
    scriptWriter.appendLine(`return true, rsp, nil`);
    scriptWriter.end();
    scriptWriter.lineFeed();
    scriptWriter.appendLine(`function _aubo_get_vision_target_pose_${row}(target_type, robot_pose)`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`textmsg("vision pick call getVisionTargetPose, type=" .. tostring(target_type) .. ", host=127.0.0.1, port=30210")`);
    scriptWriter.appendLine(`local visionc = sched.jsonrpc.proxy('http://127.0.0.1:30210/jsonrpc')`);
    scriptWriter.appendLine(`local function _aubo_log_vision_rsp_summary(rsp)`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`local st = tonumber(rsp and rsp.status)`);
    scriptWriter.appendLine(`local p = rsp and rsp.pose`);
    scriptWriter.appendLine(`if p and p.x ~= nil then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`textmsg("vision pick rpc rsp summary: status=" .. tostring(st) .. ", pose=(" .. tostring(p.x) .. "," .. tostring(p.y) .. "," .. tostring(p.z) .. ")")`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`elseif p and p[1] ~= nil then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`textmsg("vision pick rpc rsp summary: status=" .. tostring(st) .. ", pose=(" .. tostring(p[1]) .. "," .. tostring(p[2]) .. "," .. tostring(p[3]) .. ")")`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`elseif p and p[0] ~= nil then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`textmsg("vision pick rpc rsp summary: status=" .. tostring(st) .. ", pose=(" .. tostring(p[0]) .. "," .. tostring(p[1]) .. "," .. tostring(p[2]) .. ")")`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`else`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`textmsg("vision pick rpc rsp summary: status=" .. tostring(st) .. ", pose=nil")`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.appendLine(`local ok = false`);
    scriptWriter.appendLine(`local rsp = nil`);
    scriptWriter.appendLine(`local err = nil`);
    scriptWriter.appendLine(`if type(getVisionTargetPose) == "function" then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`textmsg("vision pick rpc trying: getVisionTargetPose")`);
    scriptWriter.appendLine(`ok, rsp, err = _aubo_vision_rpc_try_with_timeout_${row}(function() return getVisionTargetPose(target_type, robot_pose) end, "getVisionTargetPose", 3.0)`);
    scriptWriter.appendLine(`if ok then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`_aubo_log_vision_rsp_summary(rsp)`);
    scriptWriter.appendLine(`return rsp`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.appendLine(`textmsg("vision pick rpc failed: getVisionTargetPose, err=" .. tostring(err))`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`else`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`textmsg("vision pick rpc skip: getVisionTargetPose not found")`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.appendLine(`textmsg("vision pick rpc trying: visionc.getVisionTargetPose")`);
    scriptWriter.appendLine(`ok, rsp, err = _aubo_vision_rpc_try_with_timeout_${row}(function() return visionc.getVisionTargetPose(target_type, robot_pose) end, "visionc.getVisionTargetPose", 3.0)`);
    scriptWriter.appendLine(`if ok then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`_aubo_log_vision_rsp_summary(rsp)`);
    scriptWriter.appendLine(`return rsp`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.appendLine(`textmsg("vision pick rpc failed: visionc.getVisionTargetPose, err=" .. tostring(err))`);
    scriptWriter.appendLine(`textmsg("vision pick rpc trying: visionc.VisionInterface.getVisionTargetPose")`);
    scriptWriter.appendLine(`ok, rsp, err = _aubo_vision_rpc_try_with_timeout_${row}(function() return visionc.VisionInterface.getVisionTargetPose(target_type, robot_pose) end, "visionc.VisionInterface.getVisionTargetPose", 3.0)`);
    scriptWriter.appendLine(`if ok then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`_aubo_log_vision_rsp_summary(rsp)`);
    scriptWriter.appendLine(`return rsp`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.appendLine(`textmsg("vision pick rpc failed: visionc.VisionInterface.getVisionTargetPose, err=" .. tostring(err))`);
    scriptWriter.appendLine(`return { status = -5 }`);
    scriptWriter.end();
    scriptWriter.lineFeed();
    scriptWriter.appendLine(`function _aubo_call_pick_sdk_${row}()`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`local vision_target_type = ${defaultTargetType}`);
    scriptWriter.appendLine(`textmsg("vision pick start sdk call, target_type=" .. tostring(vision_target_type))`);
    scriptWriter.appendLine(`local retry = 0`);
    scriptWriter.appendLine(`local rsp = nil`);
    scriptWriter.appendLine(`while retry < 3 do`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`rsp = _aubo_get_vision_target_pose_${row}(vision_target_type, getToolPose())`);
    scriptWriter.appendLine(`local status = tonumber(rsp and rsp.status) or -6`);
    scriptWriter.appendLine(`textmsg("vision pick attempt=" .. tostring(retry + 1) .. ", status=" .. tostring(status))`);
    scriptWriter.appendLine(`if status == 0 then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`break`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`elseif status == 1 then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`retry = retry + 1`);
    scriptWriter.appendLine(`if retry < 3 then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`textmsg("vision pick status=1, retry detect")`);
    scriptWriter.appendLine(`sleep(0.1)`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`else`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`retry = retry + 1`);
    scriptWriter.appendLine(`if retry < 3 then sleep(0.1) end`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.appendLine(`local status = tonumber(rsp and rsp.status) or -6`);
    scriptWriter.appendLine(`if status < 0 then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`local err_msg = "视觉采摘失败: " .. _aubo_vision_status_msg_${row}(status)`);
    scriptWriter.appendLine(`textmsg("vision pick fatal error after retries, status=" .. tostring(status))`);
    scriptWriter.appendLine(`_aubo_popup_error_${row}(err_msg)`);
    scriptWriter.appendLine(`return false, { status = status }`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.appendLine(`if status == 1 then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`textmsg("vision pick no fruit detected")`);
    scriptWriter.appendLine(`return false, { status = 1 }`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.appendLine(`if not _aubo_has_pose_data_${row}(rsp and rsp.pose) then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`textmsg("vision pick skip: status=0 but pose is empty")`);
    scriptWriter.appendLine(`return false, { status = 2 }`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.appendLine(`local total = ${rows} * ${cols} * ${basketCount}`);
    scriptWriter.appendLine(`if _aubo_visual_pick_count == nil then _aubo_visual_pick_count = 0 end`);
    scriptWriter.appendLine(`local idx = (_aubo_visual_pick_count % total)`);
    scriptWriter.appendLine(`local one_basket = ${rows} * ${cols}`);
    scriptWriter.appendLine(`local basket_index = math.floor(idx / one_basket)`);
    scriptWriter.appendLine(`local local_idx = idx % one_basket`);
    scriptWriter.appendLine(`local rr = math.floor(local_idx / ${cols})`);
    scriptWriter.appendLine(`local cc = local_idx % ${cols}`);
    scriptWriter.appendLine(`local pick_pose = _aubo_to_pick_pose_${row}(rsp and rsp.pose)`);
    scriptWriter.appendLine(`textmsg("vision pick target detected, basket_index=" .. tostring(basket_index) .. ", row=" .. tostring(rr) .. ", col=" .. tostring(cc))`);
    scriptWriter.appendLine(`return true, { basket_index = basket_index, row = rr, col = cc, pick_pose = pick_pose, total = total, quality_score = 1, stem_len = 0.15, grasp_width = 0, status = 0, code = 0 }`);
    scriptWriter.end();
    scriptWriter.lineFeed();
    scriptWriter.appendLine(`function _aubo_fire_basket_change_io_${row}()`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`textmsg("vision pick basket change trigger: high->low")`);
    scriptWriter.appendLine(basketChangeIo ? basketChangeIo.generateWriteScript(basketPulseHighLevel) : `setStandardDigitalOutput(0, ${basketPulseHighLevel})`);
    scriptWriter.appendLine(`sleep(0.15)`);
    scriptWriter.appendLine(basketChangeIo ? basketChangeIo.generateWriteScript(basketPulseLowLevel) : `setStandardDigitalOutput(0, ${basketPulseLowLevel})`);
    scriptWriter.appendLine(`textmsg("vision pick wait 5s for basket change finished")`);
    scriptWriter.appendLine(`sleep(5)`);
    scriptWriter.end();
    scriptWriter.lineFeed();
    scriptWriter.appendLine(`function _aubo_set_tool_io_${row}(idx, val, label)`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`local done = false`);
    scriptWriter.appendLine(`local ok = false`);
    scriptWriter.appendLine(`local err = nil`);
    scriptWriter.appendLine(`local h = thread(function()`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`ok, err = pcall(function() setToolDigitalOutput(idx, val) end)`);
    scriptWriter.appendLine(`done = true`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end, "thread_tool_io_${row}")`);
    scriptWriter.appendLine(`run(h)`);
    scriptWriter.appendLine(`local t0 = getControlSystemTime()`);
    scriptWriter.appendLine(`local timeout_ns = 500000000`);
    scriptWriter.appendLine(`while not done do`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`if (getControlSystemTime() - t0) > timeout_ns then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`kill(h)`);
    scriptWriter.appendLine(`error("vision pick aborted: tool io timeout, label=" .. tostring(label))`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.appendLine(`sync()`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.appendLine(`kill(h)`);
    scriptWriter.appendLine(`if not ok then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`error("vision pick aborted: tool io failed, label=" .. tostring(label) .. ", err=" .. tostring(err))`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.end();
    scriptWriter.lineFeed();
    scriptWriter.appendLine(`function _aubo_scissor_open_${row}()`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`textmsg("vision pick scissor open trigger: tool0 high->low while tool1 low")`);
    scriptWriter.appendLine(`_aubo_set_tool_io_${row}(${pruneIo2Index}, ${scissorPulseLowLevel}, "scissor_open_tool1_low")`);
    scriptWriter.appendLine(`_aubo_set_tool_io_${row}(${pruneIoIndex}, ${scissorPulseHighLevel}, "scissor_open_tool0_high")`);
    scriptWriter.appendLine(`sleep(0.05)`);
    scriptWriter.appendLine(`_aubo_set_tool_io_${row}(${pruneIoIndex}, ${scissorPulseLowLevel}, "scissor_open_tool0_low")`);
    scriptWriter.end();
    scriptWriter.lineFeed();
    scriptWriter.appendLine(`function _aubo_scissor_close_${row}()`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`textmsg("vision pick scissor close trigger: tool1 high->low while tool0 low")`);
    scriptWriter.appendLine(`_aubo_set_tool_io_${row}(${pruneIoIndex}, ${scissorPulseLowLevel}, "scissor_close_tool0_low")`);
    scriptWriter.appendLine(`_aubo_set_tool_io_${row}(${pruneIo2Index}, ${scissorPulseHighLevel}, "scissor_close_tool1_high")`);
    scriptWriter.appendLine(`sleep(0.05)`);
    scriptWriter.appendLine(`_aubo_set_tool_io_${row}(${pruneIo2Index}, ${scissorPulseLowLevel}, "scissor_close_tool1_low")`);
    scriptWriter.end();
    scriptWriter.lineFeed();
    scriptWriter.appendLine(`function _aubo_visual_pick_once()`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`local one_basket = ${rows} * ${cols}`);
    scriptWriter.appendLine(`local total = one_basket * ${basketCount}`);
    scriptWriter.appendLine(`if _aubo_visual_pick_count == nil then _aubo_visual_pick_count = 0 end`);
    scriptWriter.appendLine(`if _aubo_visual_pick_count >= total then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`textmsg("vision pick: all baskets already full, skip picking")`);
    if (needUnloadFlagVarName) {
      scriptWriter.appendLine(`${needUnloadFlagVarName} = true`);
    }
    scriptWriter.appendLine(`_aubo_visual_basket_full = true`);
    scriptWriter.appendLine(`return { basket_full = true }`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    if (enableCutWaypoint) {
      scriptWriter.appendLine(`local cut_pose = ${cutWaypoint}`);
      scriptWriter.appendLine(`textmsg("vision pick move to cut waypoint")`);
      scriptWriter.appendLine(`_aubo_move_joint_until_reached_${row}(cut_pose, 1.3962634015954636, 1.0471975511965976, 0, 0)`);
    }
    scriptWriter.appendLine(`local ok, result = _aubo_call_pick_sdk_${row}()`);
    scriptWriter.appendLine(`if (not ok) and result and result.status == 1 then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`textmsg("vision pick: no fruit detected")`);
    scriptWriter.appendLine(`return { basket_full = false }`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.appendLine(`if (not ok) and result and result.status == 2 then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`textmsg("vision pick: status=0 but pose empty, skip current cycle")`);
    scriptWriter.appendLine(`return { basket_full = false }`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.appendLine(`if not ok or not result then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`return { basket_full = false }`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    scriptWriter.appendLine(`textmsg("vision pick item_spec=${itemSpec}, status=" .. tostring(result.status) .. ", score=" .. tostring(result.quality_score))`);
    scriptWriter.appendLine(`textmsg("vision pick scissor open before pick")`);
    scriptWriter.appendLine(`_aubo_scissor_open_${row}()`);
    scriptWriter.appendLine(`textmsg("vision pick scissor open command done")`);
    scriptWriter.appendLine(`textmsg("vision pick after scissor open delay")`);
    scriptWriter.appendLine(`local pre_pick_pose = poseTrans(_aubo_pose_to_vec6_${row}(result.pick_pose), {0.0, 0.0, -0.05, 0.0, 0.0, 0.0})`);
    scriptWriter.appendLine(`textmsg("vision pick move to pre-pick pose (z-5cm)")`);
    scriptWriter.appendLine(`_aubo_move_joint_until_reached_${row}(pre_pick_pose, 1.3962634015954636, 1.0471975511965976, 0, 0)`);
    scriptWriter.appendLine(`textmsg("vision pick move to pick pose")`);
    scriptWriter.appendLine(`_aubo_move_line_until_reached_${row}(result.pick_pose, 0.2, 0.1, 0, 0)`);
    scriptWriter.appendLine(`textmsg("vision pick scissor close at pick point")`);
    scriptWriter.appendLine(`_aubo_scissor_close_${row}()`);
    scriptWriter.appendLine(`textmsg("vision pick scissor close command done")`);
    scriptWriter.appendLine(`sleep(1)`);
    scriptWriter.appendLine(`local retreat_pose = poseTrans(_aubo_pose_to_vec6_${row}(result.pick_pose), {0.0, 0.0, -0.10, 0.0, 0.0, 0.0})`);
    scriptWriter.appendLine(`textmsg("vision pick retreat 10cm after cut")`);
    scriptWriter.appendLine(`_aubo_move_line_until_reached_${row}(retreat_pose, 0.2, 0.1, 0, 0)`);
    scriptWriter.appendLine(`local transition_pose = {-0.12778, -0.38157, 0.5384, 1.57, 0, 0}`);
    scriptWriter.appendLine(`textmsg("vision pick move to transition pose before basket place")`);
    scriptWriter.appendLine(`_aubo_move_joint_until_reached_${row}(transition_pose, 1.3962634015954636, 1.0471975511965976, 0, 0)`);
    scriptWriter.appendLine(`local down_pose, up_pose, down_approach_pose, up_approach_pose = _aubo_calc_place_segment_poses_${row}(result.row, result.col, ${rows}, ${cols})`);
    scriptWriter.appendLine(`textmsg("vision pick move to basket approach pose")`);
    scriptWriter.appendLine(`_aubo_move_joint_until_reached_${row}(down_approach_pose, 1.3962634015954636, 1.0471975511965976, 0, 0)`);
    scriptWriter.appendLine(`textmsg("vision pick skip bottom center move, continue to top center flow")`);
    scriptWriter.appendLine(`textmsg("vision pick skip top approach move, go directly to top center")`);
    scriptWriter.appendLine(`_aubo_move_line_until_reached_${row}(up_pose, 0.2, 0.08, 0, 0)`);
    scriptWriter.appendLine(`textmsg("vision pick scissor open at stem place point")`);
    scriptWriter.appendLine(`_aubo_scissor_open_${row}()`);
    scriptWriter.appendLine(`textmsg("vision pick scissor release command done")`);
    scriptWriter.appendLine(`sleep(0.1)`);
    scriptWriter.appendLine(`_aubo_move_line_until_reached_${row}(up_approach_pose, 0.2, 0.08, 0, 0)`);
    scriptWriter.appendLine(`textmsg("vision pick move to transition pose after place")`);
    scriptWriter.appendLine(`_aubo_move_joint_until_reached_${row}(transition_pose, 1.3962634015954636, 1.0471975511965976, 0, 0)`);
    scriptWriter.appendLine(`_aubo_visual_pick_count = (_aubo_visual_pick_count or 0) + 1`);
    scriptWriter.appendLine(`local current_basket_is_full = (_aubo_visual_pick_count % one_basket) == 0`);
    scriptWriter.appendLine(`local all_basket_is_full = _aubo_visual_pick_count >= total`);
    scriptWriter.appendLine(`textmsg("vision pick basket status: current_full=" .. tostring(current_basket_is_full) .. ", all_full=" .. tostring(all_basket_is_full))`);
    scriptWriter.appendLine(`if current_basket_is_full and not all_basket_is_full then _aubo_fire_basket_change_io_${row}() end`);
    scriptWriter.appendLine(`if all_basket_is_full then _aubo_visual_basket_full = true end`);
    if (needUnloadFlagVarName) {
      scriptWriter.appendLine(`if all_basket_is_full then ${needUnloadFlagVarName} = true end`);
    }
    scriptWriter.appendLine(`textmsg("vision pick placed count=" .. tostring(_aubo_visual_pick_count) .. ", basket_full=" .. tostring(all_basket_is_full))`);
    scriptWriter.appendLine(`return { basket_full = all_basket_is_full }`);
    scriptWriter.end();
    scriptWriter.lineFeed();
    scriptWriter.appendLine(`if _aubo_visual_pick_count == nil then _aubo_visual_pick_count = 0 end`);
    scriptWriter.appendLine(`if _aubo_visual_basket_full == nil then _aubo_visual_basket_full = false end`);
    scriptWriter.appendLine(`if not ${hasCenterBottomPose ? 'true' : 'false'} then`);
    scriptWriter.increaseIndent();
    scriptWriter.appendLine(`textmsg("vision pick error: center bottom waypoint is not taught")`);
    scriptWriter.appendLine(`error("vision pick aborted: center_bottom_pose is required")`);
    scriptWriter.decreaseIndent();
    scriptWriter.appendLine(`end`);
    if (needUnloadFlagVarName) {
      scriptWriter.appendLine(`${needUnloadFlagVarName} = false`);
    }
    scriptWriter.appendLine(`_aubo_visual_pick_once()`);
  }
  hasDefined() {
    return true;
  }
  getTitle() {
    const language = (0, scope_setting_1.getCurrentLanguage)();
    return translation_util_1.default.toAimLanguage(language, 'Picking', translation_util_1.TranslationNamespace.AGV);
  }
  getIcon(hasDefined) {
    return hasDefined ? `icon${agv_constant_1.PluginsProgramNodeId.AUBO_VISION_PICK}Complete` : `icon${agv_constant_1.PluginsProgramNodeId.AUBO_VISION_PICK}`;
  }
}
exports.VisionPickNode = VisionPickNode;
//# sourceMappingURL=visionpick-node.js.map