Index: trunk/src/atmsdriver/model/StationComparator.java
===================================================================
--- trunk/src/atmsdriver/model/Station.java	(revision 343)
+++ trunk/src/atmsdriver/model/StationComparator.java	(revision 353)
@@ -1,158 +1,40 @@
 package atmsdriver.model;
 
-import atmsdriver.model.LoopDetector.DOTCOLOR;
-import java.util.ArrayList;
-import java.util.List;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
+import java.util.Comparator;
 
 /**
- * A Station (VDS or Vehicle Detector Station) represents a group of lane detectors
- * across all lanes in one direction at a particular point on a highway. A station is identified
- * by its highway number and postmile. A station has an associated direction
- * used to establish which direction is Main and which is Opposite. The MLTotVol
- * and OppTotVol for a station can be dynamically updated. A station has other
- * attributes: lineNum, vdsID, drop, and location which are used by the FEP. A
- * station can be compared to other stations by its postmile.
- *
- * @author John A. Torres, jdalbey
- * @version 9/10/2017, 3/22/2019
+ * Compare two stations by route and postmile. 
+ * Used by Highways.toJson() so json is listed by route then postmile
+ * @author jdalbey
+ * @version 4/2/2019
  */
-public final class Station implements Comparable
+public final class StationComparator implements Comparator
 {
 
-    /* Static Station meta data */
-    final public int lineID;
-    final public int vdsID; // double check
-    final public int drop;
-    final public String location;
-    final public List<LoopDetector> loops;
-    final public int routeNumber;
-    final public double postmile;
-    final public DIRECTION direction;
-
-    /* Dynamic Station data */
-    private int MLTotVol;
-    private int OppTotVol;
-
-    /* Constructor */
-    public Station(int lineID, int vdsID, int drop,
-            String location, List<LoopDetector> loops, int hwy,
-            DIRECTION direction, double postmile)
-    {
-        this.lineID = lineID;
-        this.vdsID = vdsID;
-        this.drop = drop;
-        this.loops = loops;
-        this.location = location;
-        this.postmile = postmile;
-        this.direction = direction;
-        this.routeNumber = hwy;
-
-        this.MLTotVol = getMLTotVol();
-        this.OppTotVol = getOPPTotVol();
-    }
-
     /**
-     * Calculates the total ML Volume.
-     *
-     * @return total ML volume.
-     */
-    private int getMLTotVol()
-    {
-        int mlTotVol = 0;
-        for (LoopDetector loop : loops)
-        {
-            if (loop.loopLocation.startsWith("ML"))
-            {
-                mlTotVol += loop.vol;
-            }
-        }
-        return mlTotVol;
-    }
-
-    /**
-     * Calculates the total OPP Volume
-     *
-     * @return total OPP volume.
-     */
-    private int getOPPTotVol()
-    {
-        int oppTotVol = 0;
-        for (LoopDetector loop : loops)
-        {
-            if (loop.loopLocation.startsWith("OS"))
-            {
-                oppTotVol += loop.vol;
-            }
-        }
-        return oppTotVol;
-    }
-
-    /**
-     * Returns a string of highways data. If MetaDataOnly is true, you get a
-     * full dump of the highways meta data, which does not include dynamic loop
-     * values, and does include the string location names. If MetaDataOnly is
-     * false, dynamic loop values are included, and unnecessary information like
-     * string location values are included.
-     *
-     * The FEPSimulator takes in the toCondensedFormat() output, with a
-     * MetaDataOnly value of false, over the socket.
-     *
-     * The MetaDataOnly flag should be used to get a full dump of the highways
-     * information. This was used to get the highways_fullmap.txt output.
-     *
-     * @param MetaDataOnly Whether you want meta data, or a full dump for FEPSim
-     * @return String, highways data in condensed format
-     */
-    public String toCondensedFormat(boolean MetaDataOnly)
-    {
-        StringBuilder build = new StringBuilder();
-        build.append(Integer.toString(this.vdsID));
-        build.append(" ");
-        build.append(Integer.toString(this.drop));
-        build.append(" ");
-        build.append(Integer.toString(this.routeNumber));
-        build.append(" ");
-        build.append(this.direction.getLetter());
-        build.append(" ");
-        build.append(Double.toString(this.postmile));
-        build.append(" ");
-        build.append(Integer.toString(loops.size()));
-        build.append(" ");
-        if (MetaDataOnly)
-        {
-            build.append(this.location);
-        }
-        build.append("\n");
-        for (LoopDetector loop : loops)
-        {
-            build.append(loop.toCondensedFormat(MetaDataOnly));
-        }
-        return build.toString();
-    }
-
-    /**
-     * Compare this Station to another by postmile. Note: This might be better
-     * as a Comparator since it checks only one field.
+     * Compare two stations by route and postmile. 
      */
     @Override
-    public int compareTo(Object otherStation)
+    public int compare(Object a, Object b)
     {
         // check for identity
-        if (this == otherStation)
+        if (a == b)
         {
             return 0;
         }
         // check that Object is of type Station, if not throw exception
-        if (!(otherStation instanceof Station))
+        if (!(a instanceof Station && b instanceof Station))
         {
             throw new ClassCastException("A Station object expected.");
         }
-
-        // get difference of values
-        double otherStationPostmile = ((Station) otherStation).postmile;
-        double val = this.postmile - otherStationPostmile;
-
+        Station statA = (Station) a;
+        Station statB = (Station) b;
+        // compare by direction field first
+        int i = statA.direction.compareTo(statB.direction);
+        if (i != 0) return i;
+        
+        // get difference of postmile values
+        double val = statA.postmile - statB.postmile;
+        
         // set appropriate comparable return value
         int retval = 0;
@@ -169,267 +51,3 @@
     }
 
-    /**
-     * See if this station matches the specified attributes.
-     * @param dir
-     * @param postmile
-     * @return true if this station's attributes match the given ones.
-     */
-    public boolean matches(DIRECTION dir, double postmile)
-    {
-        double val = this.postmile - postmile;
-        return (Math.abs(val) < 0.01) && this.direction.equals(dir);
-    }
-    /**
-     * Determine which lane fields to update based on given direction and update
-     * all the loop detectors with the given color.
-     *
-     * @param direction desired highway direction
-     * @param dotColor desired dot color
-     */
-    public void updateByDirection(DIRECTION direction, DOTCOLOR dotColor)
-    {
-        // Is this station going in the desired direction?
-        if (direction.equals(this.direction))
-        {
-            outputUpdateMessage(dotColor, direction.toString());
-
-            for (LoopDetector loop : loops)
-            {
-                // THIS DECISION ISN'T NEEDED after JD's BuildHighwayFile pgm
-                // creates a highway map based on VDS instead of Controller (LDS).
-    //            if (loop.loopLocation.startsWith(laneDir))
-    //            {
-                    // UPDATE LOOP WITH VALUES
-                    loop.updateLoop(dotColor.volume(), dotColor.occupancy());
-    //            }
-            }
-
-            this.MLTotVol = getMLTotVol();
-            this.OppTotVol = getOPPTotVol();
-        }
-    }
-    /**
-     * Return the color for the lanes in a given direction.
-     * @return character representing color of this station's traffic flow
-     * '@' = red, '+' = yellow, '-' = green
-     */
-    public char getColor()
-    {
-        /* For now just use the color of the first lane. 
-         * TODO: Average the color in ALL the lanes for the given direction */
-
-        String laneDir = "";
-        
-            // THIS DECISION ISN'T NEEDED after JD's BuildHighwayFile pgm
-            // creates a highway map based on VDS instead of Controller (LDS).
-//        if (direction.equals(this.direction))
-//        {
-//            laneDir = "ML";
-//        }
-//        else if (direction.equals(this.direction.getOpposite()))
-//        {
-//            laneDir = "OS";
-//        }
-        // Search lanes to find specified direction
-        for (LoopDetector loop : loops)
-        {
-            // THIS DECISION ISN'T NEEDED after JD's BuildHighwayFile pgm
-            // creates a highway map based on VDS instead of Controller (LDS).
-//            if (loop.loopLocation.substring(0,2).equals(laneDir))
-//            {
-                // Return color according to loop volume of first matching lane
-                if (loop.vol == 1)
-                {
-                    return '@';
-                }
-                if (loop.vol == 3)
-                {
-                    return '+';
-                }
-                if (loop.vol == 0)
-                {
-                    return '-';
-                }
-//            }
-        }
-        // Default case for when the route is not on this direction
-        return ' ';
-    }
-    /**
-     * Return the color name for the traffic volume of this station.
-     */
-    public String getColorName()
-    {
-        String colorName = "";
-        switch (this.getColor())
-        {
-            case '@': colorName = "red";break;
-            case '+': colorName = "yellow"; break;
-            case '-': colorName = "lime";break;
-            case ' ': colorName = "lime";break;
-        }
-        return colorName;
-    }
-    /**
-     * Output for updateByDirection. Logs the update to the console.
-     *
-     * @param dotcolor
-     * @param OPP_ML
-     */
-    private void outputUpdateMessage(DOTCOLOR dotcolor, String OPP_ML)
-    {
-        System.out.printf("Updating %-3.3s %-5.5s %-3.3s lanes\t %-12.12s "
-                + "at postmile %-6.6s to %-7.7s\n",
-                Integer.toString(this.routeNumber), this.direction.name(),
-                OPP_ML, this.location, Double.toString(this.postmile),
-                dotcolor.name());
-    }
-
-    /**
-     * XML tags used for toXML() method.
-     */
-    private static enum XML_TAGS
-    {
-
-        STATION("Station"),
-        LDS_ID("LDS_ID"),
-        LINE_NUM("Line_Num"),
-        DROP("Drop"),
-        LOOPS("Loops"),
-        LOCATION("Location"),
-        POST_MILE("Post_Mile"),
-        DIRECTION("Direction"),
-        FREEWAY("Freeway"),
-        ML_TOT_VOL("ML_Tot_Vol"),
-        OPP_TOT_VOL("Opp_Tot_Vol");
-
-        String tag;
-
-        private XML_TAGS(String n)
-        {
-            tag = n;
-        }
-    }
-
-    /**
-     * Returns the Station data in XMLFormat.
-     *
-     * @param currElem The current XML <Station> element
-     */
-    public void toXML(Element currElem)
-    {
-        Document theDoc = currElem.getOwnerDocument();
-
-        Element stationElement = theDoc.createElement(XML_TAGS.STATION.tag);
-        currElem.appendChild(stationElement);
-
-        Element ldsIDElement = theDoc.createElement(XML_TAGS.LDS_ID.tag);
-        ldsIDElement.appendChild(theDoc.createTextNode(String.valueOf(this.vdsID)));
-        stationElement.appendChild(ldsIDElement);
-
-        Element lineNumElement = theDoc.createElement(XML_TAGS.LINE_NUM.tag);
-        lineNumElement.appendChild(theDoc.createTextNode(String.valueOf(this.lineID)));
-        stationElement.appendChild(lineNumElement);
-
-        Element dropElement = theDoc.createElement(XML_TAGS.DROP.tag);
-        dropElement.appendChild(theDoc.createTextNode(String.valueOf(this.drop)));
-        stationElement.appendChild(dropElement);
-
-        Element locationElement = theDoc.createElement(XML_TAGS.LOCATION.tag);
-        locationElement.appendChild(theDoc.createTextNode(this.location));
-        stationElement.appendChild(locationElement);
-
-        Element postMileElement = theDoc.createElement(XML_TAGS.POST_MILE.tag);
-        postMileElement.appendChild(theDoc.createTextNode(String.valueOf(this.postmile)));
-        stationElement.appendChild(postMileElement);
-
-        Element directionElement = theDoc.createElement(XML_TAGS.DIRECTION.tag);
-        directionElement.appendChild(theDoc.createTextNode("" + this.direction.getLetter()));
-        stationElement.appendChild(directionElement);
-
-        Element freewayElement = theDoc.createElement(XML_TAGS.FREEWAY.tag);
-        freewayElement.appendChild(theDoc.createTextNode(String.valueOf(this.routeNumber)));
-        stationElement.appendChild(freewayElement);
-
-        Element mlElement = theDoc.createElement(XML_TAGS.ML_TOT_VOL.tag);
-        mlElement.appendChild(theDoc.createTextNode(String.valueOf(this.MLTotVol)));
-        stationElement.appendChild(mlElement);
-
-        Element oppElement = theDoc.createElement(XML_TAGS.OPP_TOT_VOL.tag);
-        oppElement.appendChild(theDoc.createTextNode(String.valueOf(this.OppTotVol)));
-        stationElement.appendChild(oppElement);
-
-        Element loopsElement = theDoc.createElement(XML_TAGS.LOOPS.tag);
-        stationElement.appendChild(loopsElement);
-
-        for (LoopDetector loop : loops)
-        {
-            loop.toXML(loopsElement);
-        }
-    }
-
-    /**
-     * Enum for freeway direction.
-     *
-     * @author John A. Torres
-     * @version 9/10/2017
-     */
-    public static enum DIRECTION
-    {
-        NORTH,
-        SOUTH,
-        EAST,
-        WEST;
-
-        // All the first letters of the values, in order.
-        private static String allLetters = "NSEW";
-
-        /**
-         * Return the first letter of this enum.
-         *
-         * @return String first letter of this enum.
-         */
-        public String getLetter()
-        {
-            return this.toString().substring(0, 1);
-        }
-        
-        public DIRECTION getOpposite()
-        {
-            switch (this)
-            {
-                case NORTH:
-                    return SOUTH;
-                case SOUTH:
-                    return NORTH;
-                case EAST:
-                    return WEST;
-                case WEST:
-                    return EAST;
-            }
-            return null;
-        }
-
-        /**
-         * Returns a direction given its first character.
-         *
-         * @param letter the first character of a direction
-         * @return direction corresponding to letter
-         * @pre letter must be one of allLetters
-         */
-        public static DIRECTION toDirection(String letter)
-        {
-            if(letter.indexOf(letter.charAt(0)) == -1)
-            {
-                return null;
-            }
-            return values()[allLetters.indexOf(letter.charAt(0))];
-        }
-    }
-    
-    @Override
-    public String toString()
-    {
-        return Integer.toString(this.vdsID)+this.getColor();
-    }
 }
