package de.renew.gui.pnml.converter;

import org.w3c.dom.Element;

import CH.ifa.draw.figures.TextFigure;
import de.renew.draw.storables.ontology.Figure;
import de.renew.gui.ArcConnection;
import de.renew.gui.CPNTextFigure;
import de.renew.gui.DeclarationFigure;
import de.renew.gui.PlaceFigure;
import de.renew.gui.TransitionFigure;
import de.renew.gui.pnml.creator.AnnotationCreator;
import de.renew.gui.pnml.creator.AttributeCreator;
import de.renew.gui.pnml.creator.PNMLCreator;
import de.renew.shadowcompiler.InscriptionValidator;
import de.renew.shadowcompiler.ShadowNetSystemCompiler;
import de.renew.simulatorontology.shadow.ShadowNet;
import de.renew.simulatorontology.shadow.SyntaxException;


/**
 * Used to convert between the contents of a {@link de.renew.gui.CPNDrawing}
 * (in the form of {@link Figure} objects)
 * and the contents of an {@link Element} representing the same net
 * in a PNML file.
 * <p>
 * See also {@link Converter}.
 */
public abstract class NetConverterAbstract implements NetConverter {
    private static final org.apache.log4j.Logger logger =
        org.apache.log4j.Logger.getLogger(NetConverterAbstract.class);
    private final Converter _converter;
    private final boolean _toolInsc;

    /**
     * Constructor for NetConverterAbstract
     *
     * @param converter which is being used for conversion
     * @param toolInsc  weither the tool inscription should be converted or not
     */
    public NetConverterAbstract(Converter converter, boolean toolInsc) {
        _converter = converter;
        _toolInsc = toolInsc;
    }

    Converter getConverter() {
        return _converter;
    }

    @Override
    public boolean isAttribute(Element label) {
        return isAttribute(label.getNodeName());
    }

    @Override
    public boolean isAttribute(String tagName) {
        return false;
    }

    @Override
    public boolean isAnnotation(Element label) {
        String tagName = label.getNodeName();
        return tagName.equals("initialMarking") || tagName.equals("name")
            || tagName.equals("inscription") || tagName.equals("declaration");
    }

    @Override
    public boolean isInRenewAnnotation(Element label) {
        return false;
    }

    @Override
    public TextFigure convertAnnotationToTextFigure(Element label) {
        String tagName = label.getNodeName();
        if (tagName.equals("initialMarking") || tagName.equals("inscription")) {
            return new CPNTextFigure(CPNTextFigure.INSCRIPTION);
        }
        if (tagName.equals("name")) {
            return new CPNTextFigure(CPNTextFigure.NAME);
        }
        if (tagName.equals("declaration")) {
            return new DeclarationFigure();
        }

        return new CPNTextFigure();
    }

    Element generateAnnotationElement(
        String tagName, CPNTextFigure figure, PNMLCreator pnmlCreator, boolean parentVirtual)
    {
        if (isAttribute(tagName)) {
            AttributeCreator attCreator = new AttributeCreator(pnmlCreator, tagName);
            return attCreator.createElement(figure.getText());
        } else {
            AnnotationCreator annCreator =
                new AnnotationCreator(tagName, parentVirtual, getConverter());
            return annCreator.createElement(pnmlCreator, figure);
        }
    }

    @Override
    public Element annotationToPNML(
        CPNTextFigure figure, PNMLCreator pnmlCreator, boolean parentVirtual)
    {
        ShadowNet net = getConverter().getShadowNet();
        String tagName;

        switch (figure.getType()) {
            case CPNTextFigure.NAME:
                tagName = "name";
                break;
            case CPNTextFigure.INSCRIPTION:
                Figure parent = figure.parent();
                String text = figure.getText();
                if (!_toolInsc) {
                    try {
                        InscriptionValidator validator =
                            ShadowNetSystemCompiler.getInstance().createInscriptionValidator(net);
                        if (figure instanceof DeclarationFigure) {
                            tagName = validator.checkDeclarationNode(text, false);
                        } else if (parent instanceof ArcConnection) {
                            tagName = validator.checkArcInscription(text, false);
                        } else if (parent instanceof PlaceFigure) {
                            tagName = validator.checkPlaceInscription(text, false);
                        } else if (parent instanceof TransitionFigure) {
                            tagName = validator.checkTransitionInscription(text, false);
                        } else {
                            // If parent is none of these, output an error:
                            logger.error(
                                NetConverterAbstract.class.getSimpleName()
                                    + ": inscribed net element figure's class is not recognized: "
                                    + parent.getClass().getSimpleName());
                            tagName = null;
                        }

                        // The checks might also have returned null.
                        if (tagName == null) {
                            logger.error(
                                NetConverterAbstract.class.getSimpleName()
                                    + ": could not find PNML element name for inscription: "
                                    + text);
                        } else {
                            // Return from switch statement:
                            break;
                        }
                    } catch (SyntaxException e) {
                        logger.error(
                            NetConverterAbstract.class.getSimpleName() + ": " + e.getMessage()
                                + "\nIt seems that the net " + net.getName()
                                + " contains a syntax error." + "\nPlease, fix before exporting.");
                        if (logger.isDebugEnabled()) {
                            logger.debug(NetConverterAbstract.class.getSimpleName() + ": " + e);
                        }
                    }
                }

                // Declaration node figures become "declaration" tags,
                // everything else becomes an "inscription" tag.
                tagName = figure instanceof DeclarationFigure ? "declaration" : "inscription";

                // If _toolInsc or a SyntaxException was thrown:
                // Create "inscription" tag within "toolspecific" tag
                // and directly return that.
                Element toolSpec = pnmlCreator.createToolspecific();
                toolSpec.appendChild(
                    generateAnnotationElement(tagName, figure, pnmlCreator, parentVirtual));
                return toolSpec;
            case CPNTextFigure.LABEL:
                tagName = "label";
                break;
            default:
                throw new RuntimeException("Unkown type " + figure.getType());
        }

        return generateAnnotationElement(tagName, figure, pnmlCreator, parentVirtual);
    }

    @Override
    public String convertAttributeNameToRenewName(Element attribute) {
        String parent = attribute.getParentNode().getNodeName();
        String type = attribute.getNodeName();
        if ("arc".equals(parent) && "type".equals(type)) {
            return "ArcType";
        }

        return type;
    }

    /**
     * Is parser net parser.
     *
     * @param netType [String]
     * @return false
     * @author Eva Mueller
     * @date Dec 3, 2010
     * @version 0.1
     */
    public static boolean isNetParser(String netType) {
        return false;
    }
}