--- /dev/null
+package tim.prune.load.json;
+
+import java.util.ArrayList;
+
+/**
+ * Structure to hold the contents of a Json block during parsing.
+ * This will be held within the current [] or {} block
+ */
+public class JsonBlock
+{
+ private String _latitude = null;
+ private String _longitude = null;
+ private String _altitude = null;
+
+ private Expectation _nextField = Expectation.NONE;
+ private BlockType _type = BlockType.NONE;
+ private boolean _hasNonNumbers = false;
+ private ArrayList<String> _pointCoords = null;
+ private ArrayList<ArrayList<String>> _coordList = null;
+
+
+ private enum BlockType {
+ NONE, FIELDS, POINTCOORDS, ISPOINTLIST, HASPOINTLIST
+ }
+ private enum Expectation {
+ NONE, LATITUDE, LONGITUDE, ALTITUDE, COORDS
+ }
+
+ /** Internal method to remove quotes and NaNs from altitude strings */
+ private String modifyAltitudeString(String inAlt)
+ {
+ if (inAlt == null || inAlt.equals("") || inAlt.equals("\"\"")) {
+ return null;
+ }
+ String result = inAlt;
+ if (inAlt.length() > 2 && inAlt.startsWith("\"") && inAlt.endsWith("\""))
+ {
+ result = inAlt.substring(1, inAlt.length()-1);
+ }
+ if (result.equals("NaN")) {return null;}
+ return result;
+ }
+
+ /**
+ * Receive a token to this block
+ * @param inToken token from Json source
+ */
+ public void addToken(String inToken)
+ {
+ if (inToken == null || inToken.isEmpty()) {return;}
+ if (!_hasNonNumbers && !looksLikeNumber(inToken)) {
+ _hasNonNumbers = true;
+ }
+ if (inToken.equals("\"latitude\"")) {
+ _nextField = Expectation.LATITUDE;
+ }
+ else if (inToken.equals("\"longitude\"")) {
+ _nextField = Expectation.LONGITUDE;
+ }
+ else if (inToken.equals("\"altitude\"")) {
+ _nextField = Expectation.ALTITUDE;
+ }
+ else if (inToken.equals("\"coordinates\"")) {
+ _nextField = Expectation.COORDS;
+ }
+ else
+ {
+ switch (_nextField)
+ {
+ case LATITUDE:
+ _latitude = inToken;
+ _type = BlockType.FIELDS;
+ break;
+ case LONGITUDE:
+ _longitude = inToken;
+ _type = BlockType.FIELDS;
+ break;
+ case ALTITUDE:
+ _altitude = modifyAltitudeString(inToken);
+ _type = BlockType.FIELDS;
+ break;
+ default:
+ if (!_hasNonNumbers && looksLikeNumber(inToken))
+ {
+ if (_pointCoords == null) {
+ _pointCoords = new ArrayList<String>();
+ }
+ _pointCoords.add(inToken);
+ _type = BlockType.POINTCOORDS;
+ }
+ break;
+ }
+ _nextField = Expectation.NONE;
+ }
+ }
+
+ /** @return true if String can be parsed as a double */
+ private static boolean looksLikeNumber(String inToken)
+ {
+ double value = Double.NaN;
+ try {
+ value = Double.parseDouble(inToken);
+ }
+ catch (NumberFormatException nfe) {}
+ return !Double.isNaN(value);
+ }
+
+ /** @return true if named fields are valid */
+ public boolean areFieldsValid() {
+ return _type == BlockType.FIELDS && _latitude != null && _longitude != null;
+ }
+
+ /** @return true if list of 2 or 3 doubles for a single point is valid */
+ public boolean areSingleCoordsValid()
+ {
+ return !_hasNonNumbers && _pointCoords != null
+ && _pointCoords.size() >= 2 && _pointCoords.size() <= 3;
+ }
+
+ /**
+ * @param inNewSegment new segment flag
+ * @return created point
+ */
+ public JsonPoint createSinglePoint(boolean inNewSegment)
+ {
+ return new JsonPoint(_latitude, _longitude, _altitude, inNewSegment);
+ }
+
+ /**
+ * Child block has finished processing a single set of point coordinates
+ * @param inChild child block
+ */
+ public void addSingleCoordsFrom(JsonBlock inChild)
+ {
+ if (_type == BlockType.NONE && _nextField == Expectation.COORDS
+ && inChild._type == BlockType.POINTCOORDS)
+ {
+ // Named coordinates field
+ _type = BlockType.FIELDS;
+ _longitude = inChild.getSinglePointCoords(0);
+ _latitude = inChild.getSinglePointCoords(1);
+ _altitude = inChild.getSinglePointCoords(2);
+ }
+ else if ((_type == BlockType.NONE || _type == BlockType.ISPOINTLIST)
+ && !_hasNonNumbers && _nextField == Expectation.NONE
+ && inChild._type == BlockType.POINTCOORDS)
+ {
+ // add coordinates to list
+ _type = BlockType.ISPOINTLIST;
+ if (_coordList == null) {
+ _coordList = new ArrayList<ArrayList<String>>();
+ }
+ _coordList.add(inChild._pointCoords);
+ }
+ }
+
+ /** @return point coordinate for given index, or null if not present */
+ private String getSinglePointCoords(int inIndex)
+ {
+ if (_pointCoords == null || inIndex < 0 || inIndex >= _pointCoords.size()) {
+ return null;
+ }
+ return _pointCoords.get(inIndex);
+ }
+
+ /** @return true if list of point coords is valid */
+ public boolean isCoordListValid()
+ {
+ return !_hasNonNumbers && _type == BlockType.ISPOINTLIST
+ && _coordList != null;
+ }
+
+ /** @return true if this block has a valid list of point coords */
+ public boolean hasValidCoordList()
+ {
+ return _type == BlockType.HASPOINTLIST && _coordList != null;
+ }
+
+ /**
+ * Child block has finished processing a list of point coordinates
+ * @param inChild child block
+ */
+ public void addCoordListFrom(JsonBlock inChild)
+ {
+ if (_type == BlockType.NONE && _nextField == Expectation.COORDS
+ && inChild._type == BlockType.ISPOINTLIST)
+ {
+ _coordList = inChild._coordList;
+ _type = BlockType.HASPOINTLIST;
+ }
+ else if ((_type == BlockType.NONE || _type == BlockType.ISPOINTLIST)
+ && !_hasNonNumbers && inChild._type == BlockType.ISPOINTLIST)
+ {
+ if (_coordList == null) {
+ _coordList = new ArrayList<ArrayList<String>>();
+ }
+ _coordList.addAll(inChild._coordList);
+ _type = BlockType.ISPOINTLIST;
+ }
+ }
+
+ /**
+ * @return number of points in the list, if this block has a list
+ */
+ public int getNumPoints()
+ {
+ if (hasValidCoordList()) {
+ return _coordList.size();
+ }
+ return 0;
+ }
+
+ /**
+ * @param inIndex point index within list
+ * @return created point for specified index
+ */
+ public JsonPoint createPointFromList(int inIndex)
+ {
+ if (inIndex < 0 || inIndex >= getNumPoints()) {return null;}
+ ArrayList<String> pointCoords = _coordList.get(inIndex);
+ if (pointCoords.size() < 2 || pointCoords.size() > 3) {return null;}
+ final String longitude = pointCoords.get(0);
+ final String latitude = pointCoords.get(1);
+ final String altitude = ((pointCoords.size() == 3) ? pointCoords.get(3) : null);
+ return new JsonPoint(latitude, longitude, altitude, inIndex == 0);
+ }
+}