import React from 'react';
import type {
RungElement,
Contact,
Coil,
Timer,
Counter,
LogicGate,
Branch,
MathElement,
OneShot,
MoveElement,
ScaleElement,
NoOp,
CompareElement,
EdgeType,
ComparisonOp
} from '../../engine/types';
interface ConfigPanelProps {
element: RungElement;
onUpdate: (updated: RungElement) => void;
onDelete: () => void;
onClose: () => void;
}
export const ConfigPanel: React.FC<ConfigPanelProps> = ({ element, onUpdate, onDelete, onClose }) => {
const handleConditionChange = (name: 'op' | 'value', value: any) => {
if (element.type === 'contact' && element.condition) {
onUpdate({
...element,
condition: { ...element.condition, [name]: value }
} as RungElement);
}
};
return (
<>
<div className="config-panel-header">
<h3>Edit {element.type.toUpperCase()}</h3>
<button className="btn-close" onClick={onClose}>×</button>
</div>
<div className="config-panel-content">
<div className="config-form">
{element.type === 'contact' && (
<ContactForm
element={element as Contact}
onChange={onUpdate}
onConditionChange={handleConditionChange}
/>
)}
{element.type === 'coil' && (
<CoilForm
element={element as Coil}
onChange={onUpdate}
/>
)}
{element.type === 'timer' && (
<TimerForm
element={element as Timer}
onChange={onUpdate}
/>
)}
{element.type === 'counter' && (
<CounterForm
element={element as Counter}
onChange={onUpdate}
/>
)}
{element.type === 'gate' && (
<GateForm
element={element as LogicGate}
onChange={onUpdate}
/>
)}
{element.type === 'branch' && (
<BranchForm
element={element as Branch}
onChange={onUpdate}
/>
)}
{element.type === 'math' && (
<MathForm
element={element as MathElement}
onChange={onUpdate}
/>
)}
{element.type === 'oneshot' && (
<OneShotForm
element={element as OneShot}
onChange={onUpdate}
/>
)}
{element.type === 'move' && (
<MoveForm
element={element as MoveElement}
onChange={onUpdate}
/>
)}
{element.type === 'scale' && (
<ScaleForm
element={element as ScaleElement}
onChange={onUpdate}
/>
)}
{element.type === 'compare' && (
<CompareForm
element={element as CompareElement}
onChange={onUpdate}
/>
)}
{element.type === 'noop' && (
<NoOpForm
element={element as NoOp}
onChange={onUpdate}
/>
)}
</div>
</div>
<div className="config-panel-footer">
<button className="btn btn-danger" onClick={onDelete}>Delete</button>
<button className="btn" onClick={onClose}>Close</button>
</div>
</>
);
};
const ContactForm: React.FC<{ element: Contact; onChange: (u: RungElement) => void; onConditionChange: (n: 'op' | 'value', v: any) => void }> = ({ element, onChange, onConditionChange }) => (
<>
<div className="config-group">
<div className="config-group-header">Basic Configuration</div>
<div className="config-group-content">
<div className="config-field">
<label htmlFor="contactType">Contact Type</label>
<select id="contactType" name="contactType" value={element.contactType} onChange={(e) => onChange({ ...element, contactType: e.target.value as any })}>
<option value="NO">NO</option>
<option value="NC">NC</option>
</select>
</div>
<div className="config-field">
<label htmlFor="address">Address</label>
<input id="address" name="address" value={element.address} onChange={(e) => onChange({ ...element, address: e.target.value })} />
</div>
<div className="config-field">
<label htmlFor="edgeType">Edge Detection</label>
<select id="edgeType" name="edgeType" value={element.edgeType ?? 'None'} onChange={(e) => onChange({ ...element, edgeType: e.target.value === 'None' ? undefined : e.target.value as EdgeType })}>
<option value="None">None</option>
<option value="RISING">Rising Edge</option>
<option value="FALLING">Falling Edge</option>
<option value="BOTH">Both Edges</option>
</select>
</div>
</div>
</div>
{element.condition && (
<div className="config-group">
<div className="config-group-header">Comparison Condition</div>
<div className="config-group-content">
<div className="config-field">
<label htmlFor="op">Operator</label>
<select id="op" value={element.condition?.op} onChange={(e) => onConditionChange('op', e.target.value as any)}>
<option value="==">==</option>
<option value="!=">!=</option>
<option value=">">{">"}</option>
<option value="<">{"<"}</option>
<option value=">=">{">="}</option>
<option value="<=">{"<="}</option>
</select>
</div>
<div className="config-field">
<label htmlFor="value">Value</label>
<input id="value" type="number" value={element.condition?.value} onChange={(e) => onConditionChange('value', Number(e.target.value))} />
</div>
</div>
</div>
)}
</>
);
const CoilForm: React.FC<{ element: Coil; onChange: (u: RungElement) => void }> = ({ element, onChange }) => (
<div className="config-group">
<div className="config-group-header">Coil Settings</div>
<div className="config-group-content">
<div className="config-field">
<label htmlFor="coilType">Coil Type</label>
<select id="coilType" name="coilType" value={element.coilType} onChange={(e) => onChange({ ...element, coilType: e.target.value as any })}>
<option value="OUTPUT">OUTPUT</option>
<option value="SET">SET</option>
<option value="RESET">RESET</option>
<option value="TOGGLE">TOGGLE</option>
<option value="LATCH">LATCH</option>
<option value="UNLATCH">UNLATCH</option>
</select>
</div>
<div className="config-field">
<label htmlFor="address">Address</label>
<input id="address" name="address" value={element.address} onChange={(e) => onChange({ ...element, address: e.target.value })} />
</div>
<div className="config-field">
<label htmlFor="value">Target Value</label>
<input id="value" type="number" name="value" value={element.value ?? 0} onChange={(e) => onChange({ ...element, value: Number(e.target.value) })} />
</div>
</div>
</div>
);
const TimerForm: React.FC<{ element: Timer; onChange: (u: RungElement) => void }> = ({ element, onChange }) => (
<div className="config-group">
<div className="config-group-header">Timer Settings</div>
<div className="config-group-content">
<div className="config-field">
<label htmlFor="timerType">Timer Type</label>
<select id="timerType" name="timerType" value={element.timerType} onChange={(e) => onChange({ ...element, timerType: e.target.value as any })}>
<option value="TON">TON</option>
<option value="TOF">TOF</option>
<option value="TP">TP</option>
<option value="RTO">RTO</option>
</select>
</div>
<div className="config-field">
<label htmlFor="instanceId">Instance ID</label>
<input id="instanceId" name="instanceId" value={element.instanceId} onChange={(e) => onChange({ ...element, instanceId: e.target.value })} />
</div>
<div className="config-field">
<label htmlFor="preset">Preset (ms)</label>
<input id="preset" type="number" name="preset" value={element.preset} onChange={(e) => onChange({ ...element, preset: Number(e.target.value) })} />
</div>
{element.timerType === 'RTO' && (
<div className="config-field">
<label htmlFor="timerResetAddr">Reset Address</label>
<input id="timerResetAddr" name="resetAddress" placeholder="Address to reset this timer" value={element.resetAddress ?? ''} onChange={(e) => onChange({ ...element, resetAddress: e.target.value })} />
</div>
)}
</div>
</div>
);
const CounterForm: React.FC<{ element: Counter; onChange: (u: RungElement) => void }> = ({ element, onChange }) => (
<div className="config-group">
<div className="config-group-header">Counter Settings</div>
<div className="config-group-content">
<div className="config-field">
<label htmlFor="counterType">Counter Type</label>
<select id="counterType" name="counterType" value={element.counterType} onChange={(e) => onChange({ ...element, counterType: e.target.value as any })}>
<option value="CTU">CTU</option>
<option value="CTD">CTD</option>
<option value="CTUD">CTUD</option>
</select>
</div>
<div className="config-field">
<label htmlFor="instanceId">Instance ID</label>
<input id="instanceId" name="instanceId" value={element.instanceId} onChange={(e) => onChange({ ...element, instanceId: e.target.value })} />
</div>
<div className="config-field">
<label htmlFor="preset">Preset</label>
<input id="preset" type="number" name="preset" value={element.preset} onChange={(e) => onChange({ ...element, preset: Number(e.target.value) })} />
</div>
<div className="config-field">
<label htmlFor="resetAddress">Reset Address</label>
<input id="resetAddress" name="resetAddress" value={element.resetAddress ?? ''} onChange={(e) => onChange({ ...element, resetAddress: e.target.value })} />
</div>
</div>
</div>
);
const GateForm: React.FC<{ element: LogicGate; onChange: (u: RungElement) => void }> = ({ element, onChange }) => (
<div className="config-group">
<div className="config-group-header">Gate Settings</div>
<div className="config-group-content">
<div className="config-field">
<label htmlFor="gateType">Gate Type</label>
<select id="gateType" name="gateType" value={element.gateType} onChange={(e) => onChange({ ...element, gateType: e.target.value as any })}>
<option value="AND">AND</option>
<option value="OR">OR</option>
<option value="XOR">XOR</option>
<option value="NOT">NOT</option>
<option value="NAND">NAND</option>
<option value="NOR">NOR</option>
</select>
</div>
<div className="config-field">
<label htmlFor="inputs">Inputs (comma separated)</label>
<input id="inputs" name="inputs" value={element.inputs.join(',')} onChange={(e) => {
const vals = e.target.value.split(',').map(s => s.trim()).filter(s => s !== '');
onChange({ ...element, inputs: vals });
}} />
</div>
<div className="config-field">
<label htmlFor="outputAddress">Output Address</label>
<input id="outputAddress" name="outputAddress" value={element.outputAddress} onChange={(e) => onChange({ ...element, outputAddress: e.target.value })} />
</div>
</div>
</div>
);
const BranchForm: React.FC<{ element: Branch; onChange: (u: RungElement) => void }> = ({ element, onChange }) => (
<div className="config-group">
<div className="config-group-header">Branch Settings</div>
<div className="config-group-content">
<div className="config-field">
<label htmlFor="branchId">Branch ID</label>
<input id="branchId" name="id" value={element.id} onChange={(e) => onChange({ ...element, id: e.target.value })} />
</div>
<div className="config-field">
<label htmlFor="logic">Logic</label>
<select id="logic" name="logic" value={element.logic} onChange={(e) => onChange({ ...element, logic: e.target.value as any })}>
<option value="AND">AND</option>
<option value="OR">OR</option>
</select>
</div>
</div>
</div>
);
const MathForm: React.FC<{ element: MathElement; onChange: (u: RungElement) => void }> = ({ element, onChange }) => (
<div className="config-group">
<div className="config-group-header">Math Settings</div>
<div className="config-group-content">
<div className="config-field">
<label htmlFor="operator">Operator</label>
<select id="operator" name="operator" value={element.operator} onChange={(e) => onChange({ ...element, operator: e.target.value as any })}>
<option value="ADD">ADD</option>
<option value="SUB">SUB</option>
<option value="MUL">MUL</option>
<option value="DIV">DIV</option>
</select>
</div>
<div className="config-field">
<label htmlFor="inputA">Input A Address</label>
<input id="inputA" name="inputA" value={element.inputA} onChange={(e) => onChange({ ...element, inputA: e.target.value })} />
</div>
<div className="config-field">
<label htmlFor="inputB">Input B Address</label>
<input id="inputB" name="inputB" value={element.inputB} onChange={(e) => onChange({ ...element, inputB: e.target.value })} />
</div>
<div className="config-field">
<label htmlFor="outputAddress">Output Address</label>
<input id="outputAddress" name="outputAddress" value={element.outputAddress} onChange={(e) => onChange({ ...element, outputAddress: e.target.value })} />
</div>
</div>
</div>
);
const OneShotForm: React.FC<{ element: OneShot; onChange: (u: RungElement) => void }> = ({ element, onChange }) => (
<div className="config-group">
<div className="config-group-header">One-Shot Settings</div>
<div className="config-group-content">
<div className="config-field">
<label htmlFor="osAddress">Address</label>
<input id="osAddress" name="address" value={element.address} onChange={(e) => onChange({ ...element, address: e.target.value })} />
</div>
<div className="config-field">
<label htmlFor="edgeType">Edge Type</label>
<select id="edgeType" name="edgeType" value={element.edgeType} onChange={(e) => onChange({ ...element, edgeType: e.target.value as 'RISING' | 'FALLING' })}>
<option value="RISING">Rising Edge</option>
<option value="FALLING">Falling Edge</option>
</select>
</div>
</div>
</div>
);
const MoveForm: React.FC<{ element: MoveElement; onChange: (u: RungElement) => void }> = ({ element, onChange }) => (
<div className="config-group">
<div className="config-group-header">Move Settings</div>
<div className="config-group-content">
<div className="config-field">
<label htmlFor="moveSource">Source Address</label>
<input id="moveSource" name="source" value={element.source} onChange={(e) => onChange({ ...element, source: e.target.value })} />
</div>
<div className="config-field">
<label htmlFor="moveDest">Destination Address</label>
<input id="moveDest" name="destination" value={element.destination} onChange={(e) => onChange({ ...element, destination: e.target.value })} />
</div>
</div>
</div>
);
const ScaleForm: React.FC<{ element: ScaleElement; onChange: (u: RungElement) => void }> = ({ element, onChange }) => (
<div className="config-group">
<div className="config-group-header">Scale Settings</div>
<div className="config-group-content">
<div className="config-field">
<label htmlFor="scaleInAddr">Input Address</label>
<input id="scaleInAddr" name="inputAddress" value={element.inputAddress} onChange={(e) => onChange({ ...element, inputAddress: e.target.value })} />
</div>
<div className="config-field">
<label htmlFor="scaleDest">Destination Address</label>
<input id="scaleDest" name="destination" value={element.destination} onChange={(e) => onChange({ ...element, destination: e.target.value })} />
</div>
<div className="config-group">
<div className="config-group-header">Input Range</div>
<div className="config-group-content">
<div className="config-field">
<label htmlFor="inMin">Min</label>
<input id="inMin" type="number" name="inMin" value={element.inMin} onChange={(e) => onChange({ ...element, inMin: Number(e.target.value) })} />
</div>
<div className="config-field">
<label htmlFor="inMax">Max</label>
<input id="inMax" type="number" name="inMax" value={element.inMax} onChange={(e) => onChange({ ...element, inMax: Number(e.target.value) })} />
</div>
</div>
</div>
<div className="config-group">
<div className="config-group-header">Output Range</div>
<div className="config-group-content">
<div className="config-field">
<label htmlFor="outMin">Min</label>
<input id="outMin" type="number" name="outMin" value={element.outMin} onChange={(e) => onChange({ ...element, outMin: Number(e.target.value) })} />
</div>
<div className="config-field">
<label htmlFor="outMax">Max</label>
<input id="outMax" type="number" name="outMax" value={element.outMax} onChange={(e) => onChange({ ...element, outMax: Number(e.target.value) })} />
</div>
</div>
</div>
</div>
</div>
);
const CompareForm: React.FC<{ element: CompareElement; onChange: (u: RungElement) => void }> = ({ element, onChange }) => (
<div className="config-group">
<div className="config-group-header">Compare Settings</div>
<div className="config-group-content">
<div className="config-field">
<label htmlFor="cmpOp">Operator</label>
<select id="cmpOp" value={element.op} onChange={(e) => onChange({ ...element, op: e.target.value as ComparisonOp })}>
<option value="==">==</option>
<option value="!=">!=</option>
<option value={">"}>{">"}</option>
<option value={"<"}>{"<"}</option>
<option value={">="}>{">="}</option>
<option value={"<="}>{"<="}</option>
</select>
</div>
<div className="config-field">
<label htmlFor="cmpInputA">Input A</label>
<input id="cmpInputA" name="inputA" value={element.inputA} onChange={(e) => onChange({ ...element, inputA: e.target.value })} />
</div>
<div className="config-field">
<label htmlFor="cmpInputB">Input B</label>
<input id="cmpInputB" name="inputB" value={element.inputB} onChange={(e) => onChange({ ...element, inputB: e.target.value })} />
</div>
<div className="config-field">
<label htmlFor="cmpOutAddr">Output Address</label>
<input id="cmpOutAddr" name="outputAddress" value={element.outputAddress} onChange={(e) => onChange({ ...element, outputAddress: e.target.value })} />
</div>
</div>
</div>
);
const NoOpForm: React.FC<{ element: NoOp; onChange: (u: RungElement) => void }> = ({ element, onChange }) => (
<div className="config-group">
<div className="config-group-header">NoOp Settings</div>
<div className="config-group-content">
<div className="config-field">
<label htmlFor="noopComment">Comment (optional)</label>
<input id="noopComment" name="comment" value={element.comment ?? ''} onChange={(e) => onChange({ ...element, comment: e.target.value || undefined })} placeholder="e.g. Section separator" />
</div>
</div>
</div>
);