import { MachineStatus } from "../types/machine"; /** * Machine state categories for safety logic */ export const MachineStateCategory = { IDLE: "idle", ACTIVE: "active", WAITING: "waiting", COMPLETE: "complete", INTERRUPTED: "interrupted", ERROR: "error", } as const; export type MachineStateCategoryType = (typeof MachineStateCategory)[keyof typeof MachineStateCategory]; /** * Categorize a machine status into a semantic safety category */ export function getMachineStateCategory( status: MachineStatus, ): MachineStateCategoryType { switch (status) { // IDLE states - safe to perform any action case MachineStatus.IDLE: case MachineStatus.SEWING_WAIT: case MachineStatus.Initial: case MachineStatus.LowerThread: return MachineStateCategory.IDLE; // ACTIVE states - operation in progress, dangerous to interrupt case MachineStatus.SEWING: case MachineStatus.MASK_TRACING: case MachineStatus.SEWING_DATA_RECEIVE: case MachineStatus.HOOP_AVOIDANCEING: return MachineStateCategory.ACTIVE; // WAITING states - waiting for user/machine action case MachineStatus.COLOR_CHANGE_WAIT: case MachineStatus.MASK_TRACE_LOCK_WAIT: case MachineStatus.HOOP_AVOIDANCE: return MachineStateCategory.WAITING; // COMPLETE states - operation finished case MachineStatus.SEWING_COMPLETE: case MachineStatus.MASK_TRACE_COMPLETE: case MachineStatus.RL_RECEIVED: return MachineStateCategory.COMPLETE; // INTERRUPTED states - operation paused/stopped case MachineStatus.PAUSE: case MachineStatus.STOP: case MachineStatus.SEWING_INTERRUPTION: return MachineStateCategory.INTERRUPTED; // ERROR/UNKNOWN states case MachineStatus.None: case MachineStatus.TryConnecting: case MachineStatus.RL_RECEIVING: default: return MachineStateCategory.ERROR; } } /** * Determines if the pattern can be safely deleted in the current state. * Prevents deletion during active operations (SEWING, MASK_TRACING, etc.) */ export function canDeletePattern(status: MachineStatus): boolean { const category = getMachineStateCategory(status); // Can delete in IDLE, WAITING, or COMPLETE states, never during ACTIVE operations return ( category === MachineStateCategory.IDLE || category === MachineStateCategory.WAITING || category === MachineStateCategory.COMPLETE ); } /** * Determines if a pattern can be safely uploaded in the current state. * Only allow uploads when machine is idle or in a complete state. */ export function canUploadPattern(status: MachineStatus): boolean { const category = getMachineStateCategory(status); // Can upload in IDLE or COMPLETE states (includes MASK_TRACE_COMPLETE) return ( category === MachineStateCategory.IDLE || category === MachineStateCategory.COMPLETE ); } /** * Determines if sewing can be started in the current state. * Allows starting from ready state or resuming from interrupted states. */ export function canStartSewing(status: MachineStatus): boolean { // Only in specific ready states return ( status === MachineStatus.SEWING_WAIT || status === MachineStatus.MASK_TRACE_COMPLETE || status === MachineStatus.PAUSE || status === MachineStatus.STOP || status === MachineStatus.SEWING_INTERRUPTION ); } /** * Determines if mask trace can be started in the current state. */ export function canStartMaskTrace(status: MachineStatus): boolean { // Can start mask trace when IDLE (after upload), SEWING_WAIT, or after previous trace return ( status === MachineStatus.IDLE || status === MachineStatus.SEWING_WAIT || status === MachineStatus.MASK_TRACE_COMPLETE ); } /** * Determines if sewing can be resumed in the current state. * Only for interrupted operations (PAUSE, STOP, SEWING_INTERRUPTION). */ export function canResumeSewing(status: MachineStatus): boolean { // Only in interrupted states const category = getMachineStateCategory(status); return category === MachineStateCategory.INTERRUPTED; } /** * Determines if disconnect should show a confirmation dialog. * Confirms if disconnecting during active operation or while waiting. */ export function shouldConfirmDisconnect(status: MachineStatus): boolean { const category = getMachineStateCategory(status); // Confirm if disconnecting during active operation or waiting for action return ( category === MachineStateCategory.ACTIVE || category === MachineStateCategory.WAITING ); } /** * Visual information for a machine state */ export interface StateVisualInfo { color: string; iconName: | "ready" | "active" | "waiting" | "complete" | "interrupted" | "error"; label: string; description: string; } /** * Get visual styling information for a machine state. * Returns color, icon, label, and description for UI display. */ export function getStateVisualInfo(status: MachineStatus): StateVisualInfo { const category = getMachineStateCategory(status); // Map state category to visual properties const visualMap: Record = { [MachineStateCategory.IDLE]: { color: "info", iconName: "ready", label: "Ready", description: "Machine is idle and ready for operations", }, [MachineStateCategory.ACTIVE]: { color: "warning", iconName: "active", label: "Active", description: "Operation in progress - do not interrupt", }, [MachineStateCategory.WAITING]: { color: "warning", iconName: "waiting", label: "Waiting", description: "Waiting for user or machine action", }, [MachineStateCategory.COMPLETE]: { color: "success", iconName: "complete", label: "Complete", description: "Operation completed successfully", }, [MachineStateCategory.INTERRUPTED]: { color: "danger", iconName: "interrupted", label: "Interrupted", description: "Operation paused or stopped", }, [MachineStateCategory.ERROR]: { color: "danger", iconName: "error", label: "Error", description: "Machine in error or unknown state", }, }; return visualMap[category]; } /** * Map machine state category to status indicator state. * Returns the appropriate state for the StatusIndicator component. */ export function getStatusIndicatorState( status: MachineStatus, ): "active" | "down" | "fixing" | "idle" { const category = getMachineStateCategory(status); switch (category) { case MachineStateCategory.IDLE: return "active"; // Gray, no animation case MachineStateCategory.ACTIVE: return "active"; // Green with animation case MachineStateCategory.WAITING: return "fixing"; // Yellow with animation case MachineStateCategory.COMPLETE: return "active"; // Green with animation case MachineStateCategory.INTERRUPTED: return "down"; // Red with animation case MachineStateCategory.ERROR: return "down"; // Red with animation default: return "idle"; } }