import { useState, useEffect, useCallback, useRef } from 'react';
import { LadderEngine } from '../../engine/engine';
import type { Program, EngineState } from '../../engine/types';
import { storageService } from '../services/storage';
// Singleton engine instance for the application
const engine = new LadderEngine();
(window as any).engine = engine; // Expose for debugging
export function useEngine() {
const [state, setState] = useState<EngineState>(() => engine.getState());
const [program, setProgram] = useState<Program | null>(() => engine.getProgram() || null);
const [currentProgramId, setCurrentProgramId] = useState<string | null>(null);
const stopFnRef = useRef<(() => void) | null>(null);
useEffect(() => {
const unsubscribe = engine.subscribe(() => {
setState({ ...engine.getState() });
const currentProgram = engine.getProgram();
if (currentProgram) {
setProgram(currentProgram);
}
});
return () => unsubscribe();
}, []);
const loadProgram = useCallback((newProgram: Program) => {
engine.loadProgram(newProgram);
setProgram(newProgram);
}, []);
const start = useCallback(() => {
const stopFn = engine.start();
stopFnRef.current = stopFn;
}, []);
const stop = useCallback(() => {
if (stopFnRef.current) {
stopFnRef.current();
stopFnRef.current = null;
}
}, []);
const newProgram = useCallback((name?: string) => {
const freshProgram: Program = {
name: name || 'Untitled Program',
rungs: [],
cycleTime: 100,
};
loadProgram(freshProgram);
setCurrentProgramId(null);
return freshProgram;
}, [loadProgram]);
const saveCurrentProgram = useCallback(async () => {
if (!program) return;
try {
const id = await storageService.saveProgram(program, currentProgramId || undefined);
setCurrentProgramId(id);
} catch (error) {
console.error('Failed to save program:', error);
alert('Failed to save program. Please try again.');
}
}, [program, currentProgramId]);
const loadProgramById = useCallback(async (id: string) => {
try {
const loaded = await storageService.loadProgram(id);
engine.loadProgram(loaded);
setProgram(loaded);
setCurrentProgramId(id);
} catch (error) {
console.error('Failed to load program:', error);
alert('Failed to load program.');
}
}, []);
const listPrograms = useCallback(async () => {
try {
return await storageService.listPrograms();
} catch (error) {
console.error('Failed to list programs:', error);
return [];
}
}, []);
const deleteProgramById = useCallback(async (id: string) => {
try {
await storageService.deleteProgram(id);
if (currentProgramId === id) {
const freshProgram = newProgram();
setCurrentProgramId(null);
loadProgram(freshProgram);
}
} catch (error) {
console.error('Failed to delete program:', error);
alert('Failed to delete program.');
}
}, [currentProgramId, newProgram, loadProgram]);
const deleteCurrentProgram = useCallback(async () => {
if (currentProgramId) {
await deleteProgramById(currentProgramId);
}
}, [currentProgramId, deleteProgramById]);
const renameCurrentProgram = useCallback(async (newName: string) => {
if (currentProgramId && program) {
try {
await storageService.renameProgram(currentProgramId, newName);
const updatedProgram = { ...program, name: newName };
engine.loadProgram(updatedProgram);
setProgram(updatedProgram);
} catch (error) {
console.error('Failed to rename program:', error);
alert('Failed to rename program.');
}
}
}, [currentProgramId, program, engine]);
return {
state,
engine,
program,
currentProgramId,
loadProgram,
start,
stop,
newProgram,
saveCurrentProgram,
loadProgramById,
listPrograms,
deleteProgramById,
deleteCurrentProgram,
renameCurrentProgram,
};
}