package de.renew.simulatorontology.shadow;

import java.io.Serial;
import java.io.Serializable;

/**
 * Abstract class for a shadow net element.
 * <p>
 * Combines all common fields and methods of shadow net elements, like
 * the shadow net they permanently belong to, discarding the element or
 * setting and getting the ID.
 */
public abstract class ShadowNetElement implements Serializable {
    /* Serialization support. */
    @Serial
    private static final long serialVersionUID = -5409843866403864922L;

    /**
     * Special value for the ID indicating that no ID
     * is assigned. Currently represented as 0.
     * See also: {@link #setID}
     **/
    private static final int NO_ID = 0;

    /** Not used by the shadow classes. May be used to
     * denote the origin of this shadow in an application
     * specific way. Will not be serialized, but that should
     * not be a problem in the usual application domains.
     **/
    private transient Object _context = null;

    /**
     * The shadow net this element is permanently associated to.
     **/
    private final ShadowNet _shadowNet;

    /**
     * Holds the ID assigned to this shadow net element,
     * defaults to {@code NO_ID}.
     * <p>
     * This field is serializable. Hopefully, the default
     * value created on deserialization of earlier versions
     * of shadow nets not containing the field will be {@code 0}
     * (equal to {@code NO_ID}), too.
     **/
    private int _id = NO_ID;

    /**
     * Abstract constructor for a {@code ShadowNetElement}. Adds the new
     * {@code ShadowNetElement} to the given {@code ShadowNet}.
     *
     * @param shadowNet the {@code ShadowNet} the element belongs to
     */
    protected ShadowNetElement(ShadowNet shadowNet) {
        _shadowNet = shadowNet;
        shadowNet.add(this);
    }

    /**
     * Returns the {@code ShadowNet} this shadow net element belongs to.
     *
     * @return the {@code ShadowNet} this shadow net element belongs to
     */
    public ShadowNet getNet() {
        return _shadowNet;
    }

    /**
     * Removes this shadow net element from the {@code ShadowNet} it belongs to.
     */
    public void discard() {
        _shadowNet.remove(this);
    }

    /**
     * Assigns the given ID to this shadow net element.
     * <p>
     * The ID will be persistent until changed explicitly
     * by another call to {@code setID()}. Instances
     * default to {@link ShadowNetElement#NO_ID} until setID() is called
     * the first time.
     * Be careful not to use the {@code NO_ID} value as an ID to
     * avoid confusion. Uniqueness of IDs is not guaranteed,
     * it lies in the responsibility of the assigning instance.
     * </p><p>
     * The usual way IDs are assigned is by the method
     * {@code buildShadow()} of {@code ShadowHolder}
     * instances, immediately after the shadow net element was
     * created.
     * </p><p>
     * An analogous concept is used to identify graphical net
     * elements (packages {@code de.renew.gui} and
     * {@code CH.ifa.draw.*}). If the
     * internal representation of {@code NO_ID} is the same in both
     * identification schemes, the mapping will be easier.
     * </p>
     * See also:
     * {@literal @see CH.ifa.draw.framework.FigureWithID}
     * {@literal @see de.renew.gui.ShadowHolder}
     * {@literal @see de.renew.gui.CPNDrawing}
     *
     * @param newID the new ID the element should have
     **/
    public void setID(int newID) {
        _id = newID;
    }

    /**
     * Returns the ID assigned to this shadow net element
     * or {@code NO_ID}, if no ID was assigned.
     * <p>
     * See also: {@link #setID}
     *
     * @return the id of this shadow net element or {@code NOID}, if no ID was assigned
     **/
    public int getID() {
        return _id;
    }

    /**
     * Getter for the context.
     *
     * @return the context
     */
    public Object getContext() {
        return _context;
    }

    /**
     * Setter for the context.
     *
     * @param context the context
     */
    public void setContext(Object context) {
        _context = context;
    }
}