package atmsdriver.model; import atmsdriver.FEPLineLoader; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; import java.net.Socket; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Observable; import java.util.Observer; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; import org.w3c.dom.Element; import tmcsim.common.SimulationException; /** The Highways class aggregates all Highway instances within a geographic * region, and all of the FEPLines within an electronic detector * network, in the same geographic region. An instance of Highways.java * comprises the underlying model for the ATMSDriver application. * * Highways uses method writeToFEP() to communicate with the FEP Simulator. * It creates a socket client which sends the FEP Simulator a highways status * message over the socket. This message is in the XML format required by the * FEP Simulator, which is provided by the resident toXML() method. * * Currently, there is no driving logic within the highways class. It is only * done through an instance of the ConsoleDriver.java class. Eventually, it * will receive incident data (from exchange.xml or better yet, directly from * the TMCSimulator itself) and drive the highways using resident logic. * * @author John A. Torres */ public class Highways { final private ArrayList lines; final private String FEPHostName; final private int FEPPortNum; final public ArrayList highways; public Highways(String ldsFileName, String loopsFileName, String highwayMetaFileName, String FEPHostName, int FEPPortNum) { /* lines = loadLines(highwayMetaFileName); System.out.println("SIZE: " + toXML().toCharArray().length); */ FEPLineLoader ldr = new FEPLineLoader(new File(ldsFileName), new File(loopsFileName)); this.lines = (ArrayList) ldr.getFEPLines(); this.FEPHostName = FEPHostName; this.FEPPortNum = FEPPortNum; this.highways = loadHighways(); //writeHighwaysMeta("hard.txt"); } private ArrayList loadHighways() { System.out.println("Loading highways..."); // The list of highways to return ArrayList highways = new ArrayList(); Map> highwayMap = new HashMap<>(); for (FEPLine line : lines) { ArrayList lineStations = (ArrayList) line.stations; for(Station station : lineStations) { Integer hwyNum = station.routeNumber; if(!highwayMap.containsKey(hwyNum)) { ArrayList stnList = new ArrayList<>(); stnList.add(station); highwayMap.put(hwyNum, stnList); } else { highwayMap.get(hwyNum).add(station); } } } Set hwyKeys = highwayMap.keySet(); for(Integer hwyKey : hwyKeys) { ArrayList hwyStations = highwayMap.get(hwyKey); Collections.sort(hwyStations); System.out.println("Loaded highway " + hwyKey + "..."); highways.add(new Highway(hwyKey, hwyStations)); } System.out.println(""); return highways; } /* private ArrayList loadLines(String highwayMetaFileName) { ArrayList lines = new ArrayList<>(); try { Scanner sc = new Scanner(new File(highwayMetaFileName)); String firstLine = sc.nextLine(); Scanner linesc = new Scanner(firstLine); int numLines = linesc.nextInt(); linesc.close(); for (int i = 0; i < numLines; i++) { System.out.println("CURR: " + i); lines.add(loadLine(sc)); } sc.close(); } catch (FileNotFoundException ex) { Logger.getLogger(Highways.class.getName()).log(Level.SEVERE, null, ex); } return lines; } private FEPLine loadLine(Scanner sc) { String line = sc.nextLine(); System.out.println(line); Scanner scline = new Scanner(line); int lineNum = scline.nextInt(); int count = scline.nextInt(); int numStations = scline.nextInt(); ArrayList stations = new ArrayList<>(); for (int i = 0; i < numStations; i++) { stations.add(loadStation(sc, lineNum)); } return new FEPLine(lineNum, stations, count); } private Station loadStation(Scanner sc, int lineNum) { String line = sc.nextLine(); System.out.println(line); Scanner scline = new Scanner(line); int ldsID = scline.nextInt(); int drop = scline.nextInt(); int fwy = scline.nextInt(); DIRECTION dir = DIRECTION.getEnum(scline.next()); double postmile = scline.nextDouble(); int numLoops = scline.nextInt(); String location = getStationLoc(line); ArrayList loops = new ArrayList<>(); for (int i = 0; i < numLoops; i++) { loops.add(loadLoop(sc)); } return new Station(lineNum, ldsID, drop, location, loops, fwy, dir, postmile); } private LoopDetector loadLoop(Scanner sc) { String line = sc.nextLine(); Scanner scline = new Scanner(line); int loopID = scline.nextInt(); int laneNum = scline.nextInt(); String loopLoc = getLoopLoc(line); // NEED GET LOOPLOC scline.close(); return new LoopDetector(loopID, loopLoc, laneNum); } private String getLoopLoc(String line) { Scanner sc = new Scanner(line); sc.nextInt(); sc.nextInt(); // GRABS FROM CURRENT TO END OF LINE sc.useDelimiter("\\z"); String loc = sc.next().trim(); sc.close(); return loc; } // Returns the loction given the whole line from the lookup file private String getStationLoc(String line) { Scanner scline = new Scanner(line); scline.nextInt(); scline.nextInt(); scline.nextInt(); scline.next(); scline.nextDouble(); scline.nextInt(); // GRABS FROM CURRENT TO END OF LINE scline.useDelimiter("\\z"); String loc = scline.next().trim(); scline.close(); return loc; } */ public void writeToFEP() throws SimulationException { try { Socket sock = new Socket(FEPHostName /*"192.168.251.130"*/, 8080); PrintWriter out = new PrintWriter(sock.getOutputStream(), true); System.out.println("BYTES: " + this.toXML().toCharArray().length + 1); out.println(this.toXML()); sock.close(); } catch (IOException ex) { Logger.getLogger(Highways.class.getName()).log(Level.SEVERE, null, ex); System.out.println("Highway Model failed writing to FEPSim."); throw new SimulationException(SimulationException.BINDING); } } // CHECK: DO WE EVEN NEED TO DO THIS? private void updateSequences() { for (FEPLine line : lines) { line.updateSequences(); } } /** * Returns the network metadata in condensed form. This is just a quick * script function to make a proper highway metadata configuration file, so * that we can read the network faster. * * @return Network metadata */ public void writeHighwaysMeta(String fileName) { try { FileWriter fw = new FileWriter(new File(fileName)); StringBuilder build = new StringBuilder(); build.append(lines.size()); build.append("\n"); System.out.println(lines.size()); fw.write(build.toString()); int count = 1; for (FEPLine line : lines) { System.out.println("Writing num: " + count); count++; fw.write(line.getLineMeta()); } } catch (IOException ex) { Logger.getLogger(Highways.class.getName()).log(Level.SEVERE, null, ex); } } public String toXML() { String xml = null; try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document theDoc = builder.newDocument(); Element networkElement = theDoc.createElement(XML_TAGS.NETWORK.tag); theDoc.appendChild(networkElement); for (FEPLine line : lines) { line.toXML(networkElement); } Transformer tf = TransformerFactory.newInstance().newTransformer(); tf.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); tf.setOutputProperty(OutputKeys.INDENT, "yes"); tf.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); Writer out = new StringWriter(); tf.transform(new DOMSource(theDoc), new StreamResult(out)); xml = out.toString(); out.close(); } catch (Exception ex) { Logger.getLogger(Highways.class.getName()).log(Level.SEVERE, null, ex); } return xml; } public Highway getHighwayByRouteNumber(Integer routeNum) { Highway returnHwy = null; for(Highway hwy : highways) { if(hwy.routeNumber.equals(routeNum)) { returnHwy = hwy; break; } } return returnHwy; } private static enum XML_TAGS { NETWORK("Network"); String tag; private XML_TAGS(String n) { tag = n; } } }