package de.renew.simulatorontology.shadow;

import java.io.Serial;

/**
 * Abstract class for shadow connections between {@link ShadowNode} instances.
 * Combines all common fields and methods like getting and setting the trace
 * or the nodes connected by this connection.
 */
public abstract class ShadowConnection extends ShadowInscribable {
    /** {@code true}, if tracing is desired, otherwise {@code false}. */
    private boolean _trace;
    /** The start of the connection. */
    private final ShadowNode _from;
    /** The end of the connection. */
    private final ShadowNode _to;

    /**
     * Constructor for a shadow connection. Checks and sets the nodes it connects.
     * Adds this connection to the elements of those nodes.
     *
     * @param from the start node of the shadow connection
     * @param to the end node of the shadow connection
     */
    protected ShadowConnection(ShadowNode from, ShadowNode to) {
        super(ensureIdentity(from, to));
        _from = from;
        _to = to;
        from.add(this);
        to.add(this);
    }

    private static ShadowNet ensureIdentity(ShadowNode from, ShadowNode to) {
        if ((from == null) | (to == null)) {
            throw new RuntimeException("Connection must be connected at both ends.");
        }

        ShadowNet net = from.getNet();
        if (net != to.getNet()) {
            throw new RuntimeException("Must connect within one net.");
        }
        return net;
    }

    /**
     * Returns whether this shadow connection is being traced.
     *
     * @return {@code true}, if trace flag is set, otherwise {@code false}
     */
    public boolean getTrace() {
        return _trace;
    }

    /**
     * Switch trace flag on or off.
     *
     * @param trace {@code true}, if tracing is desired, otherwise {@code false}
     */
    public void setTrace(boolean trace) {
        if (_trace != trace) {
            _trace = trace;
        }
    }

    @Override
    public void discard() {
        _from.remove(this);
        _to.remove(this);
        super.discard();
    }

    /**
     * Deserialization method, behaves like default readObject
     * method, additionally re-registers the connection at its nodes.
     *
     * @param in object to be read
     * @throws java.io.IOException if the object can't be read
     * @throws ClassNotFoundException if the class can't be found while reading the object
     */
    @Serial
    private void readObject(java.io.ObjectInputStream in)
        throws java.io.IOException, ClassNotFoundException
    {
        in.defaultReadObject();
        _from.add(this);
        _to.add(this);
    }
}