package de.renew.gui.fs;

import CH.ifa.draw.figures.ArrowTip;
import CH.ifa.draw.figures.LineConnection;
import de.renew.draw.storables.ontology.Figure;
import de.renew.formalism.fs.ShadowConcept;
import de.renew.gui.ShadowHolder;
import de.renew.simulatorontology.shadow.ShadowNet;
import de.renew.simulatorontology.shadow.ShadowNetElement;


/**
 * Connection between {@link ShadowConcept}s.
 */
public abstract class ConceptConnection extends LineConnection implements ShadowHolder {

    /**
     * The shadow of this concept 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 ShadowNetElement _shadow = null;

    /**
     * Constructor for the ConceptConnection.
     *
     * @param arrowTip Tip to be used for the connection
     */
    protected ConceptConnection(ArrowTip arrowTip) {
        fArrowTipClass = arrowTip.getClass();
        setStartDecoration(null);
        setEndDecoration(arrowTip);
    }

    /** Build a shadow in the given shadow net.
      *  This shadow is stored as well as returned.
      */
    @Override
    public ShadowNetElement buildShadow(ShadowNet net) {
        _shadow = createShadow(getStartConcept(), getEndConcept());
        _shadow.setContext(this);
        return _shadow;
    }

    /**
     * Creates a {@link ShadowNetElement} from two {@link ShadowConcept}s.
     *
     * @param from associated with the source of the connection
     * @param to associated with the destination of the connection
     * @return representing the connection
     */
    protected abstract ShadowNetElement createShadow(ShadowConcept from, ShadowConcept to);

    /** Get the associated shadow, if any.
     */
    @Override
    public ShadowNetElement getShadow() {
        return _shadow;
    }

    /**
     * Retrieve {@link ShadowConcept} associated with the start of the connection.
     *
     * @return concept associated with the start
     */
    protected ShadowConcept getStartConcept() {
        return getConcept(startFigure());
    }

    /**
     * Retrieve {@link ShadowConcept} associated with the end of the connection.
     *
     * @return concept associated with the end
     */
    protected ShadowConcept getEndConcept() {
        return getConcept(endFigure());
    }

    private static ShadowConcept getConcept(Figure figure) {
        if (canConnect(figure)) {
            return (ShadowConcept) ((ShadowHolder) figure).getShadow();
        } else {
            return null;
        }
    }

    private static boolean canConnect(Figure figure) {
        return figure instanceof ConceptFigure;
    }

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

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

    @Override
    public void setAttribute(String name, Object value) {
        if (!name.equals("ArrowMode")) {
            super.setAttribute(name, value);
        }
    }
}