CategoryTag.java

package org.opentrafficsim.road.network.factory.xml.demand;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.djutils.exceptions.Throw;
import org.opentrafficsim.core.gtu.GTUType;
import org.opentrafficsim.core.network.Link;
import org.opentrafficsim.core.network.route.Route;
import org.opentrafficsim.road.gtu.strategical.od.Categorization;
import org.opentrafficsim.road.gtu.strategical.od.Category;
import org.opentrafficsim.road.network.factory.xml.XmlParserException;
import org.opentrafficsim.road.network.lane.CrossSectionLink;
import org.opentrafficsim.road.network.lane.Lane;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * Category.
 * <p>
 * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
 * <p>
 * @version $Revision$, $LastChangedDate$, by $Author$, initial version 25 mei 2018 <br>
 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
 * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
 */
public class CategoryTag implements Serializable
{

    /** */
    private static final long serialVersionUID = 20180525L;

    /** GTU type. */
    private GTUType gtuType;

    /** Route. */
    private Route route;

    /** Lane. */
    private Lane lane;

    /** FACTOR. */
    Double factor;

    /** Created category. */
    private Category category;

    /**
     * Parse category nodes.
     * @param nodeList NodeList; node list
     * @param parser XmlOdParser; parser
     * @throws XmlParserException if category cannot be parsed
     */
    static void parse(final NodeList nodeList, final XmlOdParser parser) throws XmlParserException
    {
        List<Class<?>> categorizationClasses = new ArrayList<>();
        for (Node node : XMLParser.getNodesSorted(nodeList, "CATEGORY", "GTUTYPE", "ROUTE", "LANE"))
        {
            NamedNodeMap attributes = node.getAttributes();
            CategoryTag tag = new CategoryTag();

            Node nameNode = attributes.getNamedItem("NAME");
            Throw.when(nameNode == null, XmlParserException.class, "Missing NAME attribute in CATEGORY tag.");
            String name = nameNode.getNodeValue().trim();

            Node gtuTypeNode = attributes.getNamedItem("GTUTYPE");
            Throw.when(categorizationClasses.contains(GTUType.class) && gtuTypeNode == null, XmlParserException.class,
                    "Missing GTUTYPE attribute in CATEGORY %s.", name);
            Throw.when(
                    !categorizationClasses.isEmpty() && !categorizationClasses.contains(GTUType.class) && gtuTypeNode != null,
                    XmlParserException.class, "Missing GTUTYPE attribute in a CATEGORY prior to %s.", name);
            if (gtuTypeNode != null)
            {
                tag.gtuType = parser.getGTUType(gtuTypeNode.getNodeValue().trim());
            }

            Node routeNode = attributes.getNamedItem("ROUTE");
            Throw.when(categorizationClasses.contains(Route.class) && routeNode == null, XmlParserException.class,
                    "Missing ROUTE attribute in CATEGORY %s.", name);
            Throw.when(!categorizationClasses.isEmpty() && !categorizationClasses.contains(Route.class) && routeNode != null,
                    XmlParserException.class, "Missing ROUTE attribute in a CATEGORY prior to %s.", name);
            if (routeNode != null)
            {
                String routeId = routeNode.getNodeValue().trim();
                tag.route = parser.network.getRoute(routeId);
                Throw.when(tag.route == null, XmlParserException.class, "Route %s is not available.", routeId);
            }

            Node laneNode = attributes.getNamedItem("LANE");
            Throw.when(categorizationClasses.contains(Lane.class) && laneNode == null, XmlParserException.class,
                    "Missing LANE attribute in CATEGORY %s.", name);
            Throw.when(!categorizationClasses.isEmpty() && !categorizationClasses.contains(Lane.class) && laneNode != null,
                    XmlParserException.class, "Missing LANE attribute in a CATEGORY prior to %s.", name);
            if (laneNode != null)
            {
                String laneId = laneNode.getNodeValue().trim();
                // find lane
                for (Link link : parser.network.getLinkMap().values())
                {
                    if (link instanceof CrossSectionLink)
                    {
                        for (Lane lane : ((CrossSectionLink) link).getLanes())
                        {
                            if (lane.getFullId().equals(laneId))
                            {
                                tag.lane = lane;
                                break;
                            }
                        }
                    }
                    if (tag.lane != null)
                    {
                        break;
                    }
                }
                Throw.when(tag.lane == null, XmlParserException.class,
                        "Lane %s is not available. Make sure to use the full id 'LinkId.LaneId'.", laneId);
            }

            Node factorNode = attributes.getNamedItem("FACTOR");
            if (factorNode != null)
            {
                tag.factor = DemandTag.parseFactor(factorNode.getNodeValue().trim());
            }

            // define categorization classes
            if (categorizationClasses.isEmpty())
            {
                if (tag.gtuType != null)
                {
                    categorizationClasses.add(GTUType.class);
                }
                if (tag.route != null)
                {
                    categorizationClasses.add(Route.class);
                }
                if (tag.lane != null)
                {
                    categorizationClasses.add(Lane.class);
                }
                Throw.when(categorizationClasses.isEmpty(), XmlParserException.class, "Category contains no objects.");
            }

            // store category tag
            parser.categories.put(name, tag);
        }

        // create categorization
        if (categorizationClasses.isEmpty())
        {
            parser.categorization = Categorization.UNCATEGORIZED;
        }
        else if (categorizationClasses.size() > 1)
        {
            parser.categorization = new Categorization("od categorization", categorizationClasses.get(0), categorizationClasses
                    .subList(1, categorizationClasses.size()).toArray(new Class<?>[categorizationClasses.size() - 1]));
        }
        else
        {
            parser.categorization = new Categorization("od categorization", categorizationClasses.get(0));
        }
    }

    /**
     * Returns the category.
     * @param categorization Categorization; categorization
     * @return Category; category
     */
    public Category getCategory(final Categorization categorization)
    {
        if (this.category == null)
        {
            int n = 0;
            if (this.gtuType != null)
            {
                n++;
            }
            if (this.route != null)
            {
                n++;
            }
            if (this.lane != null)
            {
                n++;
            }
            Object first = null;
            Object[] objects = new Object[n - 1];
            int i = 0;
            if (this.gtuType != null)
            {
                first = this.gtuType;
            }
            if (this.route != null)
            {
                if (first == null)
                {
                    first = this.gtuType;
                }
                else
                {
                    objects[i] = this.route;
                    i++;
                }
            }
            if (this.lane != null)
            {
                if (first == null)
                {
                    first = this.gtuType;
                }
                else
                {
                    objects[i] = this.lane;
                }
            }
            this.category = new Category(categorization, first, objects);
        }
        return this.category;
    }

}