import { useState, useEffect } from 'react'; import { Plus, Minus, Check, X } from 'lucide-react'; import type { Process, BurstSegment } from '@core/types'; import { useProcessStore } from '../../store/processStore'; import IconButton from '../shared/IconButton'; import { generateId, nextColor } from '../shared/processUtils'; interface ProcessFormProps { /** If provided, the form edits this process; otherwise creates a new one. */ editingProcess?: Process | null; onClose: () => void; } const DEFAULT_BURSTS: BurstSegment[] = [{ type: 'cpu', duration: 4 }]; const ProcessForm = ({ editingProcess, onClose }: ProcessFormProps) => { const addProcess = useProcessStore(s => s.addProcess); const updateProcess = useProcessStore(s => s.updateProcess); const isEditing = !!editingProcess; const [name, setName] = useState(''); const [arrivalTime, setArrivalTime] = useState(0); const [priority, setPriority] = useState(5); const [color, setColor] = useState(nextColor); const [bursts, setBursts] = useState(DEFAULT_BURSTS); const [errors, setErrors] = useState([]); useEffect(() => { if (editingProcess) { setName(editingProcess.name); setArrivalTime(editingProcess.arrivalTime); setPriority(editingProcess.priority); setColor(editingProcess.color); setBursts([...editingProcess.bursts.map(b => ({ ...b }))]); } else { setName(''); setArrivalTime(0); setPriority(5); setColor(nextColor()); setBursts([{ type: 'cpu', duration: 4 }]); } setErrors([]); }, [editingProcess]); // ---- Burst helpers ---- const updateBurstDuration = (index: number, value: number) => { setBursts(prev => prev.map((b, i) => i === index ? { ...b, duration: Math.max(1, value) } : b)); }; const addBurst = () => { // enforce alternating cpu/io pattern const lastType = bursts[bursts.length - 1]?.type ?? 'io'; const nextType: BurstSegment['type'] = lastType === 'cpu' ? 'io' : 'cpu'; setBursts(prev => [...prev, { type: nextType, duration: 2 }]); }; const removeBurst = (index: number) => { if (bursts.length <= 1) return; setBursts(prev => { const next = prev.filter((_, i) => i !== index); // Safe-guard: ensure it still starts (and ends) with cpu return next; }); }; // ---- Validation ---- const validate = (): boolean => { const errs: string[] = []; if (!name.trim()) errs.push('Nome é obrigatório'); if (name.trim().length > 8) errs.push('Nome deve ter no máximo 8 caracteres'); if (arrivalTime < 0) errs.push('Arrival Time deve ser ≥ 0'); if (priority < 1 || priority > 10) errs.push('Priority deve estar entre 1 e 10'); if (bursts.length === 0) errs.push('Deve haver ao menos 1 burst CPU'); if (bursts[0]?.type !== 'cpu') errs.push('O primeiro burst deve ser CPU'); if (bursts.at(-1)?.type !== 'cpu') errs.push('O último burst deve ser CPU'); bursts.forEach((b, i) => { if (b.duration < 1) errs.push(`Burst ${i + 1}: duração deve ser ≥ 1`); if (i > 0 && bursts[i - 1].type === b.type) errs.push(`Bursts ${i} e ${i + 1} não podem ser do mesmo tipo (alternar CPU/IO)`); }); setErrors(errs); return errs.length === 0; }; const handleSubmit = () => { if (!validate()) return; if (isEditing && editingProcess) { updateProcess(editingProcess.id, { name: name.trim(), arrivalTime, priority, color, bursts }); } else { const p: Process = { id: generateId(), name: name.trim(), arrivalTime, priority, color, bursts, }; addProcess(p); } onClose(); }; const inputCls = 'w-full rounded-md bg-slate-700 border border-slate-600 text-slate-200 text-sm px-3 py-1.5 focus:outline-none focus:ring-1 focus:ring-blue-500'; const labelCls = 'block text-xs text-slate-400 mb-1'; return (

{isEditing ? 'Editar Processo' : 'Novo Processo'}

{/* Basic fields */}
{/* Name */}
setName(e.target.value)} placeholder="P1" className={inputCls} aria-label="Nome do processo" />
{/* Color */}
setColor(e.target.value)} className="h-[34px] w-12 rounded-md border border-slate-600 bg-slate-700 cursor-pointer" aria-label="Cor do processo" />
{/* Arrival */}
setArrivalTime(Number(e.target.value))} className={inputCls} aria-label="Tempo de chegada" />
{/* Priority */}
setPriority(Number(e.target.value))} className={inputCls} aria-label="Prioridade do processo" />
{/* Bursts editor */}
{bursts.map((burst, idx) => (
{burst.type} updateBurstDuration(idx, Number(e.target.value))} className="w-full rounded bg-slate-700/60 border border-slate-600/50 text-slate-200 text-xs px-2 py-0.5 focus:outline-none focus:ring-1 focus:ring-blue-500" aria-label={`Duração do burst ${idx + 1}`} /> ticks removeBurst(idx)} disabled={bursts.length <= 1} className="hover:text-red-400" >
))}
{/* Validation errors */} {errors.length > 0 && (
    {errors.map((e, i) => (
  • {e}
  • ))}
)} {/* Actions */}
); }; export default ProcessForm;