115 lines
4.0 KiB
TypeScript
115 lines
4.0 KiB
TypeScript
import { extractTriggersFromPoint } from "./extractTriggersFromPoint";
|
|
|
|
export function determineExecutionOrder(products: productsSchema): PointsScheme[] {
|
|
// Create maps for all events and points
|
|
const eventMap = new Map<string, EventsSchema>();
|
|
const pointMap = new Map<string, PointsScheme>();
|
|
const allPoints: PointsScheme[] = [];
|
|
|
|
// First pass: collect all points
|
|
products.forEach(product => {
|
|
product.eventDatas.forEach(event => {
|
|
eventMap.set(event.modelUuid, event);
|
|
|
|
if (event.type === 'transfer') {
|
|
event.points.forEach(point => {
|
|
pointMap.set(point.uuid, point);
|
|
allPoints.push(point);
|
|
});
|
|
} else if (event.type === 'vehicle' ||
|
|
event.type === 'machine' ||
|
|
event.type === 'storageUnit' ||
|
|
event.type === 'roboticArm' ||
|
|
event.type === 'human' ||
|
|
event.type === 'crane'
|
|
) {
|
|
pointMap.set(event.point.uuid, event.point);
|
|
allPoints.push(event.point);
|
|
}
|
|
});
|
|
});
|
|
|
|
// Build dependency graphs
|
|
const graph = new Map<string, string[]>();
|
|
const reverseGraph = new Map<string, string[]>();
|
|
const allTriggeredPoints = new Set<string>();
|
|
|
|
allPoints.forEach(point => {
|
|
const triggers = extractTriggersFromPoint(point);
|
|
const dependencies: string[] = [];
|
|
|
|
triggers.forEach(trigger => {
|
|
const targetUuid = trigger.triggeredAsset?.triggeredPoint?.pointUuid;
|
|
if (targetUuid && pointMap.has(targetUuid)) {
|
|
dependencies.push(targetUuid);
|
|
allTriggeredPoints.add(targetUuid);
|
|
|
|
if (!reverseGraph.has(targetUuid)) {
|
|
reverseGraph.set(targetUuid, []);
|
|
}
|
|
reverseGraph.get(targetUuid)!.push(point.uuid);
|
|
}
|
|
});
|
|
|
|
graph.set(point.uuid, dependencies);
|
|
});
|
|
|
|
// Identify root points (points that trigger others but aren't triggered themselves)
|
|
const rootPoints = allPoints
|
|
.filter(point => !allTriggeredPoints.has(point.uuid))
|
|
.filter(point => {
|
|
// Only include roots that actually have triggers pointing FROM them
|
|
const triggers = extractTriggersFromPoint(point);
|
|
return triggers.some(t => t.triggeredAsset?.triggeredPoint?.pointUuid);
|
|
});
|
|
|
|
// If no root points found but we have triggered points, find the earliest triggers
|
|
if (rootPoints.length === 0 && allTriggeredPoints.size > 0) {
|
|
// This handles cases where we have circular dependencies
|
|
// but still want to include the triggered points
|
|
const minTriggerCount = Math.min(
|
|
...Array.from(allTriggeredPoints)
|
|
.map(uuid => (graph.get(uuid) || []).length)
|
|
);
|
|
const potentialRoots = Array.from(allTriggeredPoints)
|
|
.filter(uuid => (graph.get(uuid) || []).length === minTriggerCount);
|
|
|
|
rootPoints.push(...potentialRoots.map(uuid => pointMap.get(uuid)!));
|
|
}
|
|
|
|
// Topological sort only for triggered points
|
|
const visited = new Set<string>();
|
|
const temp = new Set<string>();
|
|
const order: string[] = [];
|
|
let hasCycle = false;
|
|
|
|
function visit(node: string) {
|
|
if (temp.has(node)) {
|
|
hasCycle = true;
|
|
return;
|
|
}
|
|
if (visited.has(node)) return;
|
|
|
|
temp.add(node);
|
|
|
|
const dependencies = reverseGraph.get(node) || [];
|
|
for (const dep of dependencies) {
|
|
visit(dep);
|
|
}
|
|
|
|
temp.delete(node);
|
|
visited.add(node);
|
|
order.push(node);
|
|
}
|
|
|
|
// Start processing from root points
|
|
rootPoints.forEach(root => visit(root.uuid));
|
|
|
|
// Convert UUIDs back to points and filter out untriggered points
|
|
const triggeredPoints = order
|
|
.map(uuid => pointMap.get(uuid)!)
|
|
.filter(point => allTriggeredPoints.has(point.uuid) ||
|
|
rootPoints.some(root => root.uuid === point.uuid));
|
|
|
|
return triggeredPoints;
|
|
} |