namespace StoneRed.LogicSimulator.Simulation;
///
/// Represents a digital logic circuit simulator that supports combinational logic gates,
/// look-up tables (LUTs), and hierarchical macro gates.
///
public interface ICircuitSimulator
{
///
/// Gets the total number of gates in the circuit.
///
int GateCount { get; }
///
/// Adds a logic gate to the circuit.
///
/// The type of gate to add (NOT, AND, OR, etc.).
/// The unique identifier of the newly created gate.
/// Thrown when attempting to add a LUT gate using this method. Use instead.
int AddGate(GateKind kind);
///
/// Adds a Look-Up Table (LUT) gate that implements arbitrary combinational logic.
///
/// The number of inputs (0-30).
/// The truth table array. Length must be 2^inputCount. Each element is the output (0 or 1) for the corresponding input pattern.
/// The unique identifier of the newly created LUT gate.
/// Thrown when inputCount is not between 0 and 30.
/// Thrown when table is null.
/// Thrown when table length doesn't match 2^inputCount.
int AddLutGate(int inputCount, int[] table);
///
/// Connects the output of one gate to the input of another gate.
/// A single output can be connected to multiple inputs (fan-out).
///
/// The gate ID whose output will be connected.
/// The gate ID that will receive the signal.
/// The input bit position (0-31) on the destination gate.
/// Thrown when gate IDs are invalid or toInputBit is not between 0 and 31.
void ConnectGates(int fromGate, int toGate, int toInputBit);
///
/// Registers a reusable circuit definition as a macro gate that can be instantiated multiple times.
///
/// The unique name for this macro gate.
/// The circuit definition containing gates and connections.
void RegisterMacroGate(string name, CircuitDefinition definition);
///
/// Computes and caches a Look-Up Table representation of a registered macro gate for optimization.
/// This converts the macro's combinational logic into a truth table for faster simulation.
///
/// The name of the registered macro gate.
/// Maximum simulation steps allowed to compute each output pattern. Default is 4096.
/// True if the LUT was successfully computed; false if the circuit didn't stabilize within maxSteps.
/// Thrown when the macro name is not registered.
bool ComputeLut(string name, int maxSteps = 4096);
///
/// Adds an instance of a registered macro gate to the circuit.
/// If a LUT has been computed for this macro, the optimized version is used.
///
/// The name of the registered macro gate.
/// A containing the gate IDs of the instance's inputs and outputs.
/// Thrown when the macro name is not registered.
MacroInstance AddMacroGate(string name);
///
/// Returns the circuit to its initial state (all signals at 0) and
/// kickstarts the simulation logic (evaluating gates like NOT).
/// This is automatically called on the first Step if not called manually.
///
void Reset();
///
/// Sets the input signal value on a Source gate.
/// Only gates of type can have their values set.
///
/// The gate ID of the source gate.
/// The boolean value to set (true = 1, false = 0).
/// Thrown when gateId is invalid.
/// Thrown when the gate is not a Source gate.
void SetSource(int gateId, bool value);
///
/// Reads the current output signal of a gate.
///
/// The gate ID to read from.
/// True if the output is 1, false if 0.
bool GetOutput(int gateId);
///
/// Executes one simulation step. The behavior depends on the implementation:
/// - EventCircuitSimulator: Processes all pending changes in the propagation queue.
/// - CycleCircuitSimulator: Evaluates all gates once synchronously.
///
void Step();
///
/// Runs the simulation until all signals stabilize (no more changes occur).
///
/// Maximum number of steps to execute before timing out. Default is 1024.
/// The number of steps executed before stabilization.
/// Thrown when the circuit does not stabilize within maxSteps.
int RunUntilStable(int maxSteps = 1024);
///
/// Attempts to run the simulation until all signals stabilize.
///
/// Maximum number of steps to execute.
/// Output parameter containing the number of steps executed.
/// True if the circuit stabilized; false if maxSteps was exceeded.
bool TryRunUntilStable(int maxSteps, out int steps);
///
/// Subscribes to output changes on a specific gate.
/// The callback is invoked whenever the gate's output value changes.
///
/// The gate ID to watch.
/// Action to invoke on change. Parameters are (gateId, newOutputMask).
/// An that unsubscribes the watcher when disposed.
/// Thrown when callback is null.
/// Thrown when gateId is invalid.
IDisposable WatchGate(int gateId, Action callback);
}