package seng302.DataInput; import javafx.scene.paint.Color; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import seng302.Model.Boat; import seng302.Model.GPSCoordinate; import seng302.Model.Leg; import seng302.Model.Marker; import javax.xml.parsers.ParserConfigurationException; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * Created by fwy13 on 26/03/2017. */ public class RaceXMLReader extends XMLReader implements RaceDataSource { private static double COORDINATEPADDING = 0.0005; private int raceID; private List boats = new ArrayList<>(); private Color[] colors = {Color.BLUEVIOLET, Color.BLACK, Color.RED, Color.ORANGE, Color.DARKOLIVEGREEN, Color.LIMEGREEN};//TODO make this established in xml or come up with a better system. private List legs = new ArrayList<>(); private GPSCoordinate mark, startPt1, startPt2, finishPt1, finishPt2, leewardPt1, leewardPt2, windwardPt1, windwardPt2; private GPSCoordinate mapTopLeft, mapBottomRight; private List boundary = new ArrayList<>(); private List markers = new ArrayList<>(); /** * Constractor for Race XML * * @param filePath path of the file * @throws IOException error * @throws SAXException error * @throws ParserConfigurationException error */ public RaceXMLReader(String filePath) throws IOException, SAXException, ParserConfigurationException { this(filePath, true); } /** * COnstructor for Race XML * * @param filePath file path to read * @param read whether or not to read and store the files straight away. * @throws IOException error * @throws SAXException error * @throws ParserConfigurationException error */ public RaceXMLReader(String filePath, boolean read) throws IOException, SAXException, ParserConfigurationException { super(filePath); if (read) { read(); } } /** * Read the files */ private void read() { readCourse(); readID(); readLegs(); readMarkers(); readBoats(); } public void readID() { NodeList race = doc.getElementsByTagName("race"); raceID = Integer.parseInt(getTextValueOfNode((Element) race.item(0), "raceId")); } /** * Read all the boats in the XML file */ public void readBoats() { //get all boats NodeList nBoats = doc.getElementsByTagName("boat"); for (int i = 0; i < nBoats.getLength(); i++) { String name = getTextValueOfNode((Element) nBoats.item(i), "name"); String abbrev = getTextValueOfNode((Element) nBoats.item(i), "abbr"); double velo = Double.parseDouble(getTextValueOfNode((Element) nBoats.item(i), "speed")); int sourceID = Integer.parseInt(getTextValueOfNode((Element) nBoats.item(i), "sourceID")); Boat boat = new Boat(name, velo, abbrev, sourceID); boat.setCurrentPosition(startPt1); if (legs.size() > 0) { boat.setCurrentLeg(legs.get(0)); } boats.add(boat); } } /** * Read all the boats in the XML file */ public void readMarkers() { //get all boats NodeList nMarkers = doc.getElementsByTagName("marker"); for (int i = 0; i < nMarkers.getLength(); i++) { Marker marker = getMarker((Element) nMarkers.item(i)); if (marker.getName() != null) markers.add(marker); } } /** * Read all the legs in the XML file */ public void readLegs() { //get all legs NodeList nLegs = doc.getElementsByTagName("leg"); for (int i = 0; i < nLegs.getLength(); i++) { String label = getTextValueOfNode((Element) nLegs.item(i), "name"); NodeList start = ((Element) nLegs.item(i)).getElementsByTagName("start"); Marker startMarker = getMarker(start); NodeList finish = ((Element) nLegs.item(i)).getElementsByTagName("finish"); Marker finishMarker = getMarker(finish); legs.add(new Leg(label, startMarker, finishMarker, i)); } } /** * Read courses in XML file */ public void readCourse() { NodeList nCourse = doc.getElementsByTagName("course"); NodeList nBounds = ((Element) nCourse.item(0)).getElementsByTagName("boundaries"); nBounds = ((Element) nBounds.item(0)).getElementsByTagName("coordinate"); int maxLatitudeIndex = 0; double maxLatitude = -Double.MIN_VALUE; int maxLongitudeIndex = 0; double maxLongitude = -180; int minLatitudeIndex = 0; double minLatitude = Double.MAX_VALUE; int minLongitudeIndex = 0; double minLongitude = Double.MAX_VALUE; for (int i = 0; i < nBounds.getLength(); i++) { boundary.add(getCoordinates((Element) nBounds.item(i))); if (boundary.get(i).getLatitude() > maxLatitude) { maxLatitudeIndex = i; maxLatitude = boundary.get(i).getLatitude(); } if (boundary.get(i).getLatitude() < minLatitude) { minLatitudeIndex = i; minLatitude = boundary.get(i).getLatitude(); } if (boundary.get(i).getLongitude() > maxLongitude) { maxLongitudeIndex = i; maxLongitude = boundary.get(i).getLongitude(); } if (boundary.get(i).getLongitude() < minLongitude) { minLongitudeIndex = i; minLongitude = boundary.get(i).getLongitude(); } } double difference = 0;//this will hold the largest difference so we can make the map square. double latitudeDiff = Math.abs(Math.abs(boundary.get(maxLatitudeIndex).getLatitude()) - Math.abs(boundary.get(minLatitudeIndex).getLatitude())); double longitudeDiff = Math.abs(Math.abs(boundary.get(maxLongitudeIndex).getLongitude()) - Math.abs(boundary.get(minLongitudeIndex).getLongitude())); if (latitudeDiff >= longitudeDiff) { difference = latitudeDiff - longitudeDiff; maxLongitude += difference / 2; minLongitude -= difference / 2; } else { difference = longitudeDiff - latitudeDiff; maxLatitude += difference / 2; minLatitude -= difference / 2; } maxLatitude += COORDINATEPADDING; minLatitude -= COORDINATEPADDING; maxLongitude += COORDINATEPADDING; minLongitude -= COORDINATEPADDING; //now create map boundaries //top left canvas point is min logitude, max latitude //bottom right of canvas point is min longitude, max latitude. mapTopLeft = new GPSCoordinate(minLatitude, minLongitude); mapBottomRight = new GPSCoordinate(maxLatitude, maxLongitude); NodeList nMarks = ((Element) nCourse.item(0)).getElementsByTagName("marker"); startPt1 = getCoordinates(nMarks, 0); startPt2 = getCoordinates(nMarks, 0, 1); mark = getCoordinates(nMarks, 1); windwardPt1 = getCoordinates(nMarks, 2); windwardPt2 = getCoordinates(nMarks, 2, 1); leewardPt1 = getCoordinates(nMarks, 3); leewardPt2 = getCoordinates(nMarks, 3, 1); finishPt1 = getCoordinates(nMarks, 4); finishPt2 = getCoordinates(nMarks, 4, 1); } /** * gets a marker from the XML file * * @param start base nodelist this should be the tag that contains * @return */ private Marker getMarker(NodeList start) { return getMarker(start, 0); } /** * gets a marker from the XML file * * @param start base nodelist this should be the tag that contains * @param startIndex index in the node that has the coordinate tag * @return */ private Marker getMarker(NodeList start, int startIndex) { return getMarker(start, startIndex, 0); } /** * gets a marker from the XML file * * @param start base nodelist this should be the tag that contains * @param startIndex index in the node that has the coordinate tag * @param nodeIndex coordinate index * @return */ private Marker getMarker(NodeList start, int startIndex, int nodeIndex) { NodeList nodeList = ((Element) start.item(startIndex)).getElementsByTagName("marker"); Element marker = (Element) nodeList.item(nodeIndex); return getMarker(marker); } /** * gets a changes a marker to GPS coordinates into a marker * * @param markerNode marker to turn into coordinates * @return */ private Marker getMarker(Element markerNode) { NodeList nCoordinates = markerNode.getElementsByTagName("coordinate"); GPSCoordinate side1 = getCoordinates((Element) nCoordinates.item(0)); GPSCoordinate side2; if (nCoordinates.getLength() > 1) { side2 = getCoordinates((Element) nCoordinates.item(1)); } else { side2 = side1; } NodeList name = markerNode.getElementsByTagName("name"); return name.getLength() == 1 ? new Marker(getTextValueOfNode((Element) markerNode, "name"), side1, side2) : new Marker(side1, side2); } /** * gets a coordinates from the XML file * * @param start base nodelist this should be the tag that contains * @return */ private GPSCoordinate getCoordinates(NodeList start) { return getCoordinates(start, 0); } /** * gets a coordinates from the XML file * * @param start base nodelist this should be the tag that contains * @param startIndex the index the tag containing the coordinate should be in * @return */ private GPSCoordinate getCoordinates(NodeList start, int startIndex) { return getCoordinates(start, startIndex, 0); } /** * gets a coordinates from the XML file * * @param start base nodelist this should be the tag that contains * @param startIndex the index the tag containing the coordinate should be in * @param nodeIndex The coordinate index * @return */ private GPSCoordinate getCoordinates(NodeList start, int startIndex, int nodeIndex) { NodeList nodeList = ((Element) start.item(startIndex)).getElementsByTagName("coordinate"); Element coord = (Element) nodeList.item(nodeIndex); return getCoordinates(coord); } /** * Returns the coordinate TODO raise exception that runs when the XML is formatted wrongly. * * @param coordNode * @return */ private GPSCoordinate getCoordinates(Element coordNode) { double startLat = Double.parseDouble(getTextValueOfNode(coordNode, "latitude")); double startLong = Double.parseDouble(getTextValueOfNode(coordNode, "longitude")); return new GPSCoordinate(startLat, startLong); } public List getBoats() { return boats; } public List getLegs() { return legs; } public GPSCoordinate getMark() { return mark; } public GPSCoordinate getStartPt1() { return startPt1; } public GPSCoordinate getStartPt2() { return startPt2; } public GPSCoordinate getFinishPt1() { return finishPt1; } public GPSCoordinate getFinishPt2() { return finishPt2; } public GPSCoordinate getLeewardPt1() { return leewardPt1; } public GPSCoordinate getLeewardPt2() { return leewardPt2; } public GPSCoordinate getWindwardPt1() { return windwardPt1; } public GPSCoordinate getWindwardPt2() { return windwardPt2; } public List getBoundary() { return boundary; } public GPSCoordinate getMapTopLeft() { return mapTopLeft; } public GPSCoordinate getMapBottomRight() { return mapBottomRight; } public int getRaceId() { return raceID; } public List getMarkers() { return markers; } public String getRaceType() { return "FLEET"; } }