package de.renew.fa.figures;

import java.awt.Graphics;
import java.io.Serializable;
import java.util.Hashtable;

import CH.ifa.draw.figures.ArrowTip;
import CH.ifa.draw.figures.AttributeFigure;
import CH.ifa.draw.figures.LineConnection;
import CH.ifa.draw.figures.LineDecoration;
import de.renew.draw.storables.ontology.Figure;
import de.renew.draw.storables.ontology.FigureEnumeration;
import de.renew.faformalism.shadow.ShadowFAArc;
import de.renew.faformalism.shadow.ShadowFAState;
import de.renew.gui.CPNTextFigure;
import de.renew.gui.FigureWithHighlight;
import de.renew.gui.InscribableFigure;
import de.renew.gui.InstanceDrawing;
import de.renew.gui.InstanceFigure;
import de.renew.gui.ShadowHolder;
import de.renew.gui.SimulableFigure;
import de.renew.remote.ObjectAccessor;
import de.renew.simulatorontology.shadow.ShadowNet;
import de.renew.simulatorontology.shadow.ShadowNetElement;


/**
 * An arc, aka transition, connecting two states.
 *
 * @author cabac
 * @author moeller
 */
public class FAArcConnection extends LineConnection
    implements InscribableFigure, FigureWithHighlight, SimulableFigure
{
    static final long serialVersionUID = 1968826680828590162L;
    public static final org.apache.log4j.Logger LOGGER =
        org.apache.log4j.Logger.getLogger(FAArcConnection.class);

    /**
     * The shadow of this FAArcConnection
     */
    private transient ShadowFAArc _shadow = null;

    /**
     * This figure will be highlighted in a instance
     * drawing in the same manner as the transition
     * will be highlighted. May be <code>null</code>.
     * @serial
     **/
    private Figure _hilightFig = null;

    /**
     * Creates a new FAArcConnection.
     */
    public FAArcConnection() {
        super(null, new ArrowTip(), AttributeFigure.LINE_STYLE_NORMAL);
    }

    /**
     * Creates a new FAArcConnection with
     * specific decorations at start and end;
     * @param start                 the start LineDecoration
     * @param end                 the end LineDecoration
     * @param lineStyle  the style of the line
     */
    public FAArcConnection(LineDecoration start, LineDecoration end, String lineStyle) {
        super(start, end, lineStyle);
    }

    @Override
    public ShadowNetElement buildShadow(ShadowNet net) {
        LOGGER.debug("buildShadow(ShadowNet) called by " + this);
        if (_shadow != null) {
            _shadow.discard();
        }
        _shadow = new ShadowFAArc(startShadow(), endShadow());
        _shadow.setContext(this);
        _shadow.setID(this.getID());
        _shadow.setTrace(getTraceMode());
        LOGGER.debug("built " + _shadow);
        return _shadow;
    }

    private ShadowFAState startShadow() {
        return (ShadowFAState) ((ShadowHolder) startFigure()).getShadow();
    }

    private ShadowFAState endShadow() {
        return (ShadowFAState) ((ShadowHolder) endFigure()).getShadow();
    }

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

    @Override
    public InstanceFigure createInstanceFigure(
        InstanceDrawing drawing, Hashtable<Serializable, ObjectAccessor> netElements)
    {
        return new FAArcInstanceConnection(drawing, this, netElements);
    }

    @Override
    public boolean canConnect(Figure start, Figure end) {
        if (start instanceof FAStateFigure && end instanceof FAStateFigure) {
            return true;
        }
        return false;
    }

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

    @Override
    public void setHighlightFigure(Figure fig) {
        _hilightFig = fig;
    }

    @Override
    public Figure getHighlightFigure() {
        return _hilightFig;
    }

    /**
     * Retrieves the arcs name
     * @return name of arc
     */
    public String getName() {
        String cln = getClass().getName();
        int ind = cln.lastIndexOf('.') + 1;
        if (ind > 0) {
            cln = cln.substring(ind);
        }

        FigureEnumeration children = children();
        while (children.hasMoreElements()) {
            Figure child = children.nextElement();
            if (child instanceof FATextFigure) {
                FATextFigure textFig = (FATextFigure) child;
                if (textFig.getType() == CPNTextFigure.NAME) {
                    return cln + "(" + textFig.getText() + ")";
                }
            }
        }

        return cln + " (" + getID() + ")";
    }

    @Override
    public String toString() {
        return getName();
    }

    /**
     * Draws the frame of the figure.
     * We do not allow our arrow tips to be altered.
     * @param g UNUSED
     */
    @Override
    public void drawFrame(Graphics g) {
        super.setEndDecoration();
        super.setStartDecoration(null);
        super.drawFrame(g);
    }
}