import React, { useEffect, useState } from "react"; import { useSceneContext } from "../../scene/sceneContext"; import { determineExecutionMachineSequences } from "./functions/determineExecutionMachineSequences"; import { usePlayButtonStore } from "../../../store/ui/usePlayButtonStore"; import { useSimulationManager } from "../../../store/rough/useSimulationManagerStore"; import { useParams } from "react-router-dom"; import { saveSimulationDataApi } from "../../../services/simulation/comparison/saveSimulationDataApi"; interface SimulationUsageRecord { activeTime: number; isActive: boolean; idleTime: number; type: "roboticArm" | "vehicle" | "transfer" | "storageUnit" | "crane" | "human" | "machine"; assetId: string; } // Product → holds multiple usage records interface ProductSimulation { productId: string; data: SimulationUsageRecord[]; } // Version → holds multiple products interface VersionSimulation { versionId: string; products: ProductSimulation[]; } const SimulationHandler = () => { const { materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, productStore, craneStore, humanStore, versionStore } = useSceneContext(); const { armBots, getArmBotById } = armBotStore(); const { vehicles, getVehicleById } = vehicleStore(); const { getConveyorById } = conveyorStore(); const { materialHistory, materials } = materialStore(); const { getProductById, selectedProduct } = productStore(); const { machines, getMachineById } = machineStore(); const { getHumanById } = humanStore(); const { getCraneById } = craneStore(); const { getStorageUnitById } = storageUnitStore(); const { isPlaying, setIsPlaying } = usePlayButtonStore(); const { resetProductRecords, addSimulationRecord } = useSimulationManager(); const { projectId } = useParams(); const COST_RATES: Record = { roboticArm: 5, vehicle: 2, transfer: 1, storageUnit: 1, crane: 6, human: 4, machine: 3, }; const { selectedVersion } = versionStore(); // Calculate totals for one product function calculateProductMetrics(product: ProductSimulation) { let totalActiveTime = 0; let totalIdleTime = 0; let totalCost = 0; product.data.forEach((record) => { const resourceTime = record.activeTime + record.idleTime; const costRate = COST_RATES[record.type] || 0; totalActiveTime += record.activeTime; totalIdleTime += record.idleTime; totalCost += resourceTime * costRate; }); return { totalTime: totalActiveTime + totalIdleTime, totalActiveTime, totalIdleTime, totalCost, }; } // Calculate totals for a version function calculateVersionMetrics(version: VersionSimulation) { return version.products.reduce( (acc, product) => { const metrics = calculateProductMetrics(product); acc.totalTime += metrics.totalTime; acc.totalActiveTime += metrics.totalActiveTime; acc.totalIdleTime += metrics.totalIdleTime; acc.totalCost += metrics.totalCost; return acc; }, { totalTime: 0, totalActiveTime: 0, totalIdleTime: 0, totalCost: 0 } ); } // Efficiency score (compare across versions) function calculateEfficiencyScores(versions: VersionSimulation[]) { const versionMetrics = versions.map((v) => ({ versionId: v.versionId, ...calculateVersionMetrics(v), })); const minTime = Math.min(...versionMetrics.map((m) => m.totalTime)); const minCost = Math.min(...versionMetrics.map((m) => m.totalCost)); return versionMetrics.map((m) => { const timeFactor = minTime / m.totalTime; const costFactor = minCost / m.totalCost; const efficiencyScore = 0.5 * timeFactor + 0.5 * costFactor; return { ...m, efficiencyScore }; }); } useEffect(() => { let checkTimer: ReturnType; if (!projectId) return; async function checkActiveMachines() { const currentProduct = getProductById(selectedProduct.productUuid); let hasActiveEntity = false; if (currentProduct) { const executionSequences = await determineExecutionMachineSequences([currentProduct]); if (executionSequences?.length > 0) { executionSequences.forEach((sequence) => { sequence.forEach((entity) => { if (entity.type === "roboticArm") { const roboticArm = getArmBotById(entity.modelUuid); if (roboticArm?.isActive) { hasActiveEntity = true; } } if (entity.type === "vehicle") { const vehicle = getVehicleById(entity.modelUuid); if (vehicle?.isActive) { hasActiveEntity = true; } } if (entity.type === "machine") { const machine = getMachineById(entity.modelUuid); if (machine?.isActive) { hasActiveEntity = true; } } if (entity.type === "human") { const human = getHumanById(entity.modelUuid); if (human?.isActive) { hasActiveEntity = true; } } if (entity.type === "crane") { const crane = getCraneById(entity.modelUuid); if (crane?.isActive) { hasActiveEntity = true; } } if (entity.type === "storageUnit") { const storageUnit = getStorageUnitById(entity.modelUuid); if (storageUnit?.isActive) { hasActiveEntity = true; } } if (entity.type === "transfer") { const storageUnit = getConveyorById(entity.modelUuid); if (storageUnit?.isActive) { hasActiveEntity = true; } } }); }); } if (materials.length === 0 && materialHistory.length >= 0 && !hasActiveEntity) { if (!selectedVersion) return; resetProductRecords(projectId, selectedVersion?.versionId, selectedProduct?.productUuid); if (executionSequences?.length > 0) { executionSequences.forEach((sequence) => { sequence.forEach((entity) => { const typeToGetter: Record any> = { roboticArm: getArmBotById, vehicle: getVehicleById, machine: getMachineById, human: getHumanById, crane: getCraneById, storageUnit: getStorageUnitById, transfer: getConveyorById, }; const getter = typeToGetter[entity.type]; if (!getter) return; // skip unknown entity types const obj = getter(entity.modelUuid); if (!obj) return; // skip if not found addSimulationRecord(projectId, selectedVersion?.versionId || "", selectedProduct?.productUuid, { activeTime: obj.activeTime ?? 0, isActive: obj.isActive ?? false, idleTime: obj.idleTime ?? 0, type: entity.type as "roboticArm" | "vehicle" | "machine" | "human" | "crane" | "storageUnit" | "transfer", assetId: entity.modelUuid, }); }); }); } const data = { projectId: projectId, versionId: selectedVersion?.versionId, productUuid: selectedProduct.productUuid, simulateData: useSimulationManager.getState().getProductById(projectId || "", selectedVersion?.versionId || "", selectedProduct?.productUuid || "")?.simulateData, }; const simulations = await saveSimulationDataApi(data); echo.log("Simulation data saved successfully"); setIsPlaying(false); } } } if (isPlaying) { checkTimer = setTimeout(() => { checkActiveMachines(); }, 1500); } return () => { if (checkTimer) clearTimeout(checkTimer); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [materials, materialHistory, selectedVersion, selectedProduct?.productUuid, isPlaying, armBots, vehicles, machines]); return null; }; export default SimulationHandler;