package de.renew.gui.pnml.parser;

import java.awt.Color;
import java.awt.Point;
import java.util.Iterator;
import java.util.Map;

import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import CH.ifa.draw.framework.FigureWithID;
import de.renew.draw.storables.ontology.Connector;
import de.renew.draw.storables.ontology.Drawing;
import de.renew.draw.storables.ontology.Figure;
import de.renew.draw.storables.ontology.FigureEnumeration;
import de.renew.gui.ArcConnection;
import de.renew.gui.DoubleArcConnection;
import de.renew.gui.HollowDoubleArcConnection;
import de.renew.gui.InhibitorConnection;
import de.renew.gui.pnml.converter.NetConverter;
import de.renew.simulatorontology.shadow.ShadowArc;


/**
 * parse Arcs
 */
public class ArcParser extends ObjectParser {
    private final Map<String, Integer> _keys;
    private String _sourceString;
    private String _targetString;
    private final Drawing _net;

    /**Create an XMLParser that parses PNML Arcs
     * @param arc XML element to parse
     * @param keys used to map between PNML and Renew keys
     * @param net to find connections
     */
    public ArcParser(Element arc, Map<String, Integer> keys, Drawing net, NetConverter converter) {
        super(arc, converter);
        _keys = keys;
        _net = net;
    }

    /* (non-Javadoc)
     * @see de.renew.gui.pnml.ObjectParser#createObject()
     */
    @Override
    protected FigureWithID createObject() {
        ArcConnection result = new ArcConnection(ShadowArc.ORDINARY); // default
        for (AttributeParser parser : getAttributes()) {
            if (parser.attributeName().equals("ArcType")) {
                String type = parser.attributeValue();
                if (type.equals("inhibitor")) {
                    result = new InhibitorConnection();
                } else if (type.equals("multi-ordinary")) {
                    result = new DoubleArcConnection();
                } else if (type.equals("clear")) {
                    result = new HollowDoubleArcConnection();
                } else if (type.equals("both")) {
                    result = new ArcConnection(ShadowArc.BOTH);
                } else if (type.equals("test")) {
                    result = new ArcConnection(ShadowArc.TEST);
                }
            }
        }
        result.startPoint(0, 0);
        result.endPoint(0, 0);
        return result;
    }

    /* (non-Javadoc)
     * @see de.renew.gui.pnml.ObjectParser#doParse()
     */
    @Override
    protected void parseFigure() {
        String source = getElement().getAttribute("source");
        String target = getElement().getAttribute("target");
        NodeList toolSpecs = getElement().getElementsByTagName("toolspecific");
        if (toolSpecs.getLength() > 0) {
            for (int pos = 0; pos < toolSpecs.getLength(); pos++) {
                Element toolSpec = (Element) toolSpecs.item(pos);
                if ("renew".equals(toolSpec.getAttribute("tool"))) {
                    if (toolSpec.hasAttribute("source")) {
                        source = toolSpec.getAttribute("source");
                    }
                    if (toolSpec.hasAttribute("target")) {
                        target = toolSpec.getAttribute("target");
                    }
                }
            }
        }
        _sourceString = source;
        _targetString = target;
    }

    private Connector findConnector(Drawing net, int id) {
        FigureEnumeration figures = net.figures();
        while (figures.hasMoreElements()) {
            Figure element = figures.nextElement();

            if (element instanceof FigureWithID figure && figure.getID() == id) {
                Point center = figure.center();
                return figure.connectorAt(center.x, center.y);
            }
        }

        return null;
    }

    /* (non-Javadoc)
     * @see de.renew.gui.pnml.ObjectParser#doInitFigure()
     */
    @Override
    protected void doInitFigure() {
        int target;
        int source;
        ArcConnection arc = (ArcConnection) figure();
        if (_keys.containsKey(_sourceString)) {
            source = _keys.get(_sourceString);
        } else {
            try {
                source = parseNumericId(_sourceString);
            } catch (NumberFormatException e) {
                throw new RuntimeException(
                    "Could not find PNML arc source with ID \"" + _sourceString + "\"");
            }
        }
        if (_keys.containsKey(_targetString)) {
            target = _keys.get(_targetString);
        } else {
            try {
                target = parseNumericId(_targetString);
            } catch (NumberFormatException e) {
                throw new RuntimeException(
                    "Could not find PNML arc target with ID \"" + _targetString + "\"");
            }
        }
        arc.connectStart(findConnector(_net, source));
        arc.connectEnd(findConnector(_net, target));
        arc.updateConnection();
        super.doInitFigure();
    }

    /* (non-Javadoc)
     * @see de.renew.gui.pnml.ObjectParser#initGraphic()
     */
    @Override
    protected void initGraphic() {
        ArcConnection arc = (ArcConnection) figure();
        int pos = 1;
        Iterator<Point> positionen = getGraphic().positions();
        while (positionen.hasNext()) {
            Point element = positionen.next();
            arc.insertPointAt(element, pos++);
        }

        Color lineColor = getGraphic().getLineColor();
        String lineStyle = getGraphic().getLineStyle();

        if (lineColor != null) {
            figure().setAttribute("FrameColor", lineColor);
        }
        if (lineStyle != null) {
            figure().setAttribute("LineStyle", lineStyle);
        }
    }
}
