package sim.engine;

public class EnginePeer {

	protected NodeList inputPins;
	protected NodeList outputPins;
	protected EngineModule parent;
	protected double wakeUpTime;

	public EnginePeer(int input, int output, EngineModule em) {
		this.inputPins = new NodeList(input);
		this.outputPins = new NodeList(output);

		this.parent = em;
		this.wakeUpTime = Double.POSITIVE_INFINITY;
	}

	public EnginePeer(int input, EngineModule em) {
		this.inputPins = new NodeList(input);
		this.outputPins = null;

		this.parent = em;
		this.wakeUpTime = Double.POSITIVE_INFINITY;
	}

	public EnginePeer(EngineModule em) {
		this.inputPins = null;
		this.outputPins = null;

		this.parent = em;
		this.wakeUpTime = Double.POSITIVE_INFINITY;
	}

	public EngineModule getParent() {
		return this.parent;
	}

	public NodeList getInputPins() {
		return this.inputPins;
	}

	public NodeList getOutputPins() {
		return this.outputPins;
	}

	public void setInputPin(int index, Node node) {
		this.inputPins.changeItem(index, node);
		node.addComponent(this);
	}

	public void setOutputPin(int index, Node node) {
		this.outputPins.changeItem(index, node);
	}

	public void resetInputPin(int index) {
		this.inputPins.resetItem(index);
	}

	public void resetOutputPin(int index) {
		this.outputPins.resetItem(index);
	}

	public void simulateComponent(double currentTime) throws EngineException {
		Data[] currentInputs = new Data[this.inputPins.getSize()];

		for (int loopNumber = 0; loopNumber < this.inputPins.getSize(); loopNumber++) {
			currentInputs[loopNumber] = this.inputPins.getItemAt(loopNumber).getHistory();
		}

		this.parent.evaluateOutput(currentTime, currentInputs, this);
	}

	public double getWakeUp() {
		return this.wakeUpTime;
	}

	public void setWakeUp(double time) {
		this.wakeUpTime = time;
	}

	public void sleep() {
		this.wakeUpTime = Double.POSITIVE_INFINITY;
	}

	/* ====================================
	 Normal Transaction
	 ====================================*/
	public void normalTransaction(int index, Signal newData) {
		this.outputPins.getItemAt(index).getFuture().sortedInsert(newData);
	}

	/* ====================================
	 Clear-Uncomplited Transaction
	 ====================================*/
	public void clearUncomplitedTransaction(int index, Signal newData) {
		this.outputPins.getItemAt(index).getFuture().clearAfterInsert(newData);
	}

	/* ====================================
	 Clear-All Transaction
	 ====================================*/
	public void setOutputPinValue(int index, boolean newValue, double time) {
		this.outputPins.getItemAt(index).getFuture().destructiveInsert(new Signal(newValue, time, false, this, index));
	}

	public void setOutputPinUndefined(int index, double time) {
		this.outputPins.getItemAt(index).getFuture().destructiveInsert(new Signal(false, time, true, this, index));
	}

	public void floatOutputPin(int index, double time) {
		this.outputPins.getItemAt(index).getFuture().destructiveInsert(new Signal(time, this, index));
	}
}
