import { useState } from 'react';
import { Plus, Minus, Trash2, ChevronDown, ChevronUp } from 'lucide-react';
import type { BurstSegment, IntraProcessPolicy, Thread, ThreadModel } from '@core/types';
import { generateId } from '../shared/processUtils';
import { deriveThreadColor } from '../shared/threadUtils';
import IconButton from '../shared/IconButton';
interface ThreadEditorProps {
threads: Thread[];
threadModel: ThreadModel;
threadSchedulingPolicy: IntraProcessPolicy;
threadQuantum: number;
kernelThreadCount: number;
processColor: string;
onChange: (threads: Thread[]) => void;
onModelChange: (model: ThreadModel) => void;
onPolicyChange: (policy: IntraProcessPolicy) => void;
onQuantumChange: (q: number) => void;
onKernelCountChange: (k: number) => void;
}
const MODEL_OPTIONS: { value: ThreadModel; label: string; desc: string }[] = [
{
value: 'MANY_TO_ONE',
label: 'Many-to-One',
desc: 'N threads → 1 kernel. I/O bloqueia todo o processo (green threads).',
},
{
value: 'ONE_TO_ONE',
label: 'One-to-One',
desc: 'N threads → N kernel threads. Bloqueios são independentes (pthreads).',
},
{
value: 'MANY_TO_MANY',
label: 'Many-to-Many',
desc: 'N threads → M kernel threads (M ≤ N). Slots liberados em I/O.',
},
];
const POLICY_OPTIONS: { value: IntraProcessPolicy; label: string }[] = [
{ value: 'FCFS', label: 'FCFS' },
{ value: 'RR', label: 'Round Robin' },
{ value: 'PRIORITY', label: 'Priority' },
];
const inputCls = 'w-full rounded-md bg-slate-700 border border-slate-600 text-slate-200 text-xs px-2 py-1.5 focus:outline-none focus:ring-1 focus:ring-blue-500';
const labelCls = 'block text-[10px] text-slate-400 mb-0.5';
// ── Burst editor interna de cada thread ───────────────────────────────────
const ThreadBurstEditor = ({
bursts,
onChange,
}: {
bursts: BurstSegment[];
onChange: (b: BurstSegment[]) => void;
}) => {
const addBurst = () => {
const lastType = bursts[bursts.length - 1]?.type ?? 'io';
const nextType: BurstSegment['type'] = lastType === 'cpu' ? 'io' : 'cpu';
onChange([...bursts, { type: nextType, duration: 2 }]);
};
const removeBurst = (idx: number) => {
if (bursts.length <= 1) return;
onChange(bursts.filter((_, i) => i !== idx));
};
const updateDuration = (idx: number, val: number) => {
onChange(bursts.map((b, i) => (i === idx ? { ...b, duration: Math.max(1, val) } : b)));
};
return (
{bursts.map((b, idx) => (
{b.type}
updateDuration(idx, Number(e.target.value))}
className="w-14 rounded bg-slate-700/60 border border-slate-600/50 text-slate-200 text-[10px] px-1.5 py-0.5 focus:outline-none focus:ring-1 focus:ring-blue-500"
/>
ticks
removeBurst(idx)}
disabled={bursts.length <= 1}
className="ml-auto hover:text-red-400"
>
))}
);
};
// ── Card de thread individual ─────────────────────────────────────────────
const ThreadCard = ({
thread,
index,
processColor,
onUpdate,
onRemove,
canRemove,
}: {
thread: Thread;
index: number;
processColor: string;
onUpdate: (t: Thread) => void;
onRemove: () => void;
canRemove: boolean;
}) => {
const [expanded, setExpanded] = useState(false);
const color = deriveThreadColor(processColor, index);
return (
);
};
// ── ThreadEditor principal ────────────────────────────────────────────────
const ThreadEditor = ({
threads,
threadModel,
threadSchedulingPolicy,
threadQuantum,
kernelThreadCount,
processColor,
onChange,
onModelChange,
onPolicyChange,
onQuantumChange,
onKernelCountChange,
}: ThreadEditorProps) => {
const addThread = () => {
const newThread: Thread = {
tid: `t_${generateId()}`,
name: `T${threads.length + 1}`,
priority: 5,
bursts: [{ type: 'cpu', duration: 3 }],
};
onChange([...threads, newThread]);
};
const updateThread = (idx: number, updated: Thread) => {
onChange(threads.map((t, i) => (i === idx ? updated : t)));
};
const removeThread = (idx: number) => {
onChange(threads.filter((_, i) => i !== idx));
};
const selectedModel = MODEL_OPTIONS.find(m => m.value === threadModel);
return (
{/* Modelo de threads */}
{selectedModel && (
{selectedModel.desc}
)}
{/* Kernel thread count — apenas MANY_TO_MANY */}
{threadModel === 'MANY_TO_MANY' && (
onKernelCountChange(Math.min(threads.length || 1, Math.max(1, Number(e.target.value))))
}
className={inputCls}
aria-label="Kernel thread count"
/>
)}
{/* Política intra-processo */}
{threadSchedulingPolicy === 'RR' && (
onQuantumChange(Math.max(1, Number(e.target.value)))}
className={inputCls}
aria-label="Thread quantum"
/>
)}
{/* Lista de threads */}
{threads.map((thread, idx) => (
updateThread(idx, updated)}
onRemove={() => removeThread(idx)}
canRemove={threads.length > 1}
/>
))}
{threads.length === 0 && (
Nenhuma thread. Clique em "+ Thread" para adicionar.
)}
);
};
export default ThreadEditor;