/*
 * @(#)ArcConnection.java 5.1
 *
 */
package de.renew.gui;

import CH.ifa.draw.figures.ArrowTip;
import CH.ifa.draw.figures.LineConnection;
import de.renew.draw.storables.ontology.Figure;
import de.renew.simulatorontology.shadow.ShadowArc;
import de.renew.simulatorontology.shadow.ShadowNet;
import de.renew.simulatorontology.shadow.ShadowNetElement;
import de.renew.simulatorontology.shadow.ShadowNode;

/**
 * The figure representation for ArcConnections
 */
public class ArcConnection extends LineConnection implements InscribableFigure {
    /*
     * Serialization support.
     */
    private static final long serialVersionUID = -7959501008698525009L;
    public static final ArcConnection NormalArc = new ArcConnection(ShadowArc.ORDINARY);
    public static final ArcConnection TestArc = new ArcConnection(ShadowArc.TEST);
    public static final ArcConnection ReserveArc = new ArcConnection(ShadowArc.BOTH);
    @SuppressWarnings("unused")
    private final int arcConnectionSerializedDataVersion = 1;

    /**
     * The shadow of this arc connection.
     * Initially <code>null</code>, will be created
     * when needed.
     * <p>
     * This field is transient because its information
     * can be regenerated via <code>buildShadow(...)</code>.
     * </p>
     **/
    private transient ShadowArc shadow = null;

    public ArcConnection() {}

    /**
     * Creates a new ArcConnection of a specific type.
     *
     * @param arcType The type is defined according to
     *                the constants in
     *                {@link ShadowArc}.
     */
    public ArcConnection(int arcType) {
        ArrowTip start = null;
        ArrowTip end = null;
        if (arcType == ShadowArc.BOTH) {
            start = new ArrowTip();
        }
        if (arcType != ShadowArc.TEST) {
            end = new ArrowTip();
        }
        setStartDecoration(start);
        setEndDecoration(end);
    }

    public int getArcType() {
        int arrowMode = (Integer) getAttribute("ArrowMode");
        if (arrowMode == ARROW_TIP_NONE) {
            return ShadowArc.TEST;
        }
        if (arrowMode == ARROW_TIP_BOTH) {
            return ShadowArc.BOTH;
        }
        return ShadowArc.ORDINARY;
    }

    @Override
    public boolean canConnect(Figure start, Figure end) {
        return (start instanceof TransitionNodeFigure && end instanceof PlaceNodeFigure
            || start instanceof PlaceNodeFigure && end instanceof TransitionNodeFigure);
    }

    @Override
    public boolean canConnectStart(Figure start) {
        if (endFigure() != null) {
            return canConnect(start, endFigure());
        } else {
            return (start instanceof TransitionNodeFigure || start instanceof PlaceNodeFigure);
        }
    }

    @Override
    public boolean canConnectEnd(Figure end) {
        if (startFigure() != null) {
            return canConnect(startFigure(), end);
        } else {
            return (end instanceof TransitionNodeFigure || end instanceof PlaceNodeFigure);
        }
    }

    public boolean getTraceMode() {
        Object value = getAttribute("TraceMode");
        if (value instanceof Boolean result) {
            return result;
        }
        return true;
    }

    /**
     * Sets an attribute of the figure. ArcConnection understands
     * all attributes of its superclass and adjusts its semantics
     * in accordance to the value of "ArrowMode".
     * The attribute "ArrowTip" is ignored because it would lead
     * to a divergence of appearance and semantics.
     **/
    @Override
    public void setAttribute(String name, Object value) {
        if (name.equals("ArrowTip")) {
            // Ignore. Not yet implemented.
        } else {
            super.setAttribute(name, value);
        }
    }

    @Override
    public void release() {
        super.release();
        if (shadow != null) {
            shadow.discard();
        }
    }

    @Override
    public ShadowNetElement buildShadow(ShadowNet net) {
        shadow = new ShadowArc(startShadow(), endShadow(), getArcType());
        shadow.setContext(this);
        shadow.setID(this.getID());
        shadow.setTrace(getTraceMode());
        return shadow;


        // No longer calling the syntax check. This is done
        // after editing the text and in no other place should a
        // syntax check occur.
    }

    public boolean isReverse() {
        return (Integer) getAttribute("ArrowMode") == ARROW_TIP_START;
    }

    private ShadowNode anyShadow(boolean end) {
        ShadowHolder holder = (ShadowHolder) (end ? endFigure() : startFigure());
        return (ShadowNode) holder.getShadow();
    }

    ShadowNode startShadow() {
        return anyShadow(isReverse());
    }

    ShadowNode endShadow() {
        return anyShadow(!isReverse());
    }

    @Override
    public ShadowNetElement getShadow() {
        return shadow;
    }
}