package pipe.petrinet;

import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import pipe.models.*;

import java.util.*;

/**
 * Creates an {@link Arc} based on an {@link Element}'s information
 */
public class ArcCreator implements ComponentCreator<Arc> {

    private Map<String, Connectable> connectables = new HashMap<String, Connectable>();
    private Map<String, Token> tokens = new HashMap<String, Token>();

    /**
     *
     * @param connectables Map of id to connectable
     */
    public void setConnectables(Map<String, Connectable> connectables) {
        this.connectables = connectables;
    }

    /**
     *
     * @param tokens map of token id to token
     */
    public void setTokens(Map<String, Token> tokens) {
        this.tokens = tokens;
    }


    /**
     *
     * Creates either a {@link InhibitorArc} or a {@link NormalArc}
     * based on the elements arc type
     *
     * Sets it source/target to those found in {@link this.connectables}
     *
     * @param element PNML XML Arc element
     * @return
     */
    public Arc create(Element element) {
        String id = element.getAttribute("id");
        String sourceId = element.getAttribute("source");
        String targetId = element.getAttribute("target");
        String weightInput = element.getAttribute("inscription");
        boolean tagged = CreatorUtils.falseOrValueOf(element.getAttribute("tagged"));

        Map<Token, String> tokenWeights = createTokenWeights(weightInput);

        Connectable source = connectables.get(sourceId);
        Connectable target = connectables.get(targetId);
        Arc arc;
        if (isInhibitorArc(element)) {
            arc = new InhibitorArc(source, target, tokenWeights);
        } else {
            arc = new NormalArc(source, target, tokenWeights);
        }
        arc.setId(id);

        source.addOutbound(arc);
        target.addInbound(arc);

        arc.setTagged(tagged);

        //TODO: Arc path?

        return arc;
    }

    /**
     *
     * @param element
     * @return true if element type is inhibitor
     */
    private boolean isInhibitorArc(Element element) {
        NodeList typeNode = element.getElementsByTagName("type");
        if (typeNode.getLength() > 0)
        {
            String type = ((Element) typeNode.item(0)).getAttribute("type");
            return (type.equals("inhibitor"));
        }
        return false;
    }

    /**
     * Creates the 'markings' a.k.a. weights associated with an Arc.
     * @param weightInput
     * @return
     */
    private Map<Token, String> createTokenWeights(String weightInput) {
        Map<Token, String> tokenWeights = new HashMap<Token, String>();

        String[] commaSeperatedMarkings = weightInput.split(",");
        if (commaSeperatedMarkings.length == 1)
        {
            Token token = getDefaultToken();
            String weight = commaSeperatedMarkings[0];
            tokenWeights.put(token, weight);
        } else
        {
            for (int i = 0; i < commaSeperatedMarkings.length; i += 2) {
                String weight = commaSeperatedMarkings[i+1].replace("@", ",");
                String tokenName = commaSeperatedMarkings[i];
                Token token = getTokenIfExists(tokenName);
                tokenWeights.put(token, weight);
            }
        }
        return tokenWeights;

    }

    /**
     * Turns a string of "TokenId, weight, TokenId, weight" etc. into a
     * list of markings
     * @param markingsInput
     * @return
     */
    private List<Marking> processMultipleMarkings(String[] markingsInput) {
        List<Marking> markings = new LinkedList<Marking>();
        for (int i = 0; i < markingsInput.length; i += 2) {
            String value = markingsInput[i+1].replace("@", ",");
            String tokenId = markingsInput[i];
            Token token = tokens.get(tokenId);
            Marking marking = new Marking(token, value);
            markings.add(marking);
        }
        return markings;
    }

    private Marking processIndividualMarking(String value) {
        Marking marking = new Marking(getDefaultToken(), value);
        return marking;
    }

    /**
     * @param tokenName token to find in {@link this.tokens}
     * @return token if exists
     * @throws RuntimeException if token does not exist
     */
    private Token getTokenIfExists(String tokenName) {
        if (!tokens.containsKey(tokenName)) {
            throw new RuntimeException("No " + tokenName + " token exists!");
        }
        return tokens.get(tokenName);
    }

    /**
     * @return  the default token to use if no token is specified in the
     * Arc weight XML.
     */
    private Token getDefaultToken()
    {
        return getTokenIfExists("Default");
    }

}

@@ -3359,809 +3359,8 @@
  %7D%0A%0A
-    /**%0A     * Turns a string of %22TokenId, weight, TokenId, weight%22 etc. into a%0A     * list of markings%0A     * @param markingsInput%0A     * @return%0A     */%0A    private List%3CMarking%3E processMultipleMarkings(String%5B%5D markingsInput) %7B%0A        List%3CMarking%3E markings = new LinkedList%3CMarking%3E();%0A        for (int i = 0; i %3C markingsInput.length; i += 2) %7B%0A            String value = markingsInput%5Bi+1%5D.replace(%22@%22, %22,%22);%0A            String tokenId = markingsInput%5Bi%5D;%0A            Token token = tokens.get(tokenId);%0A            Marking marking = new Marking(token, value);%0A            markings.add(marking);%0A        %7D%0A        return markings;%0A    %7D%0A%0A    private Marking processIndividualMarking(String value) %7B%0A        Marking marking = new Marking(getDefaultToken(), value);%0A        return marking;%0A    %7D%0A%0A
     

Remove unused methods