1 package tim.prune.load.json;
3 import java.util.ArrayList;
6 * Structure to hold the contents of a Json block during parsing.
7 * This will be held within the current [] or {} block
11 private String _latitude = null;
12 private String _longitude = null;
13 private String _altitude = null;
15 private Expectation _nextField = Expectation.NONE;
16 private BlockType _type = BlockType.NONE;
17 private boolean _hasNonNumbers = false;
18 private ArrayList<String> _pointCoords = null;
19 private ArrayList<ArrayList<String>> _coordList = null;
22 private enum BlockType {
23 NONE, FIELDS, POINTCOORDS, ISPOINTLIST, HASPOINTLIST
25 private enum Expectation {
26 NONE, LATITUDE, LONGITUDE, ALTITUDE, COORDS
29 /** Internal method to remove quotes and NaNs from altitude strings */
30 private String modifyAltitudeString(String inAlt)
32 if (inAlt == null || inAlt.equals("") || inAlt.equals("\"\"")) {
35 String result = inAlt;
36 if (inAlt.length() > 2 && inAlt.startsWith("\"") && inAlt.endsWith("\""))
38 result = inAlt.substring(1, inAlt.length()-1);
40 if (result.equals("NaN")) {return null;}
45 * Receive a token to this block
46 * @param inToken token from Json source
48 public void addToken(String inToken)
50 if (inToken == null || inToken.isEmpty()) {return;}
51 if (!_hasNonNumbers && !looksLikeNumber(inToken)) {
52 _hasNonNumbers = true;
54 if (inToken.equals("\"latitude\"")) {
55 _nextField = Expectation.LATITUDE;
57 else if (inToken.equals("\"longitude\"")) {
58 _nextField = Expectation.LONGITUDE;
60 else if (inToken.equals("\"altitude\"")) {
61 _nextField = Expectation.ALTITUDE;
63 else if (inToken.equals("\"coordinates\"")) {
64 _nextField = Expectation.COORDS;
72 _type = BlockType.FIELDS;
76 _type = BlockType.FIELDS;
79 _altitude = modifyAltitudeString(inToken);
80 _type = BlockType.FIELDS;
83 if (!_hasNonNumbers && looksLikeNumber(inToken))
85 if (_pointCoords == null) {
86 _pointCoords = new ArrayList<String>();
88 _pointCoords.add(inToken);
89 _type = BlockType.POINTCOORDS;
93 _nextField = Expectation.NONE;
97 /** @return true if String can be parsed as a double */
98 private static boolean looksLikeNumber(String inToken)
100 double value = Double.NaN;
102 value = Double.parseDouble(inToken);
104 catch (NumberFormatException nfe) {}
105 return !Double.isNaN(value);
108 /** @return true if named fields are valid */
109 public boolean areFieldsValid() {
110 return _type == BlockType.FIELDS && _latitude != null && _longitude != null;
113 /** @return true if list of 2 or 3 doubles for a single point is valid */
114 public boolean areSingleCoordsValid()
116 return !_hasNonNumbers && _pointCoords != null
117 && _pointCoords.size() >= 2 && _pointCoords.size() <= 3;
121 * @param inNewSegment new segment flag
122 * @return created point
124 public JsonPoint createSinglePoint(boolean inNewSegment)
126 return new JsonPoint(_latitude, _longitude, _altitude, inNewSegment);
130 * Child block has finished processing a single set of point coordinates
131 * @param inChild child block
133 public void addSingleCoordsFrom(JsonBlock inChild)
135 if (_type == BlockType.NONE && _nextField == Expectation.COORDS
136 && inChild._type == BlockType.POINTCOORDS)
138 // Named coordinates field
139 _type = BlockType.FIELDS;
140 _longitude = inChild.getSinglePointCoords(0);
141 _latitude = inChild.getSinglePointCoords(1);
142 _altitude = inChild.getSinglePointCoords(2);
144 else if ((_type == BlockType.NONE || _type == BlockType.ISPOINTLIST)
145 && !_hasNonNumbers && _nextField == Expectation.NONE
146 && inChild._type == BlockType.POINTCOORDS)
148 // add coordinates to list
149 _type = BlockType.ISPOINTLIST;
150 if (_coordList == null) {
151 _coordList = new ArrayList<ArrayList<String>>();
153 _coordList.add(inChild._pointCoords);
157 /** @return point coordinate for given index, or null if not present */
158 private String getSinglePointCoords(int inIndex)
160 if (_pointCoords == null || inIndex < 0 || inIndex >= _pointCoords.size()) {
163 return _pointCoords.get(inIndex);
166 /** @return true if list of point coords is valid */
167 public boolean isCoordListValid()
169 return !_hasNonNumbers && _type == BlockType.ISPOINTLIST
170 && _coordList != null;
173 /** @return true if this block has a valid list of point coords */
174 public boolean hasValidCoordList()
176 return _type == BlockType.HASPOINTLIST && _coordList != null;
180 * Child block has finished processing a list of point coordinates
181 * @param inChild child block
183 public void addCoordListFrom(JsonBlock inChild)
185 if (_type == BlockType.NONE && _nextField == Expectation.COORDS
186 && inChild._type == BlockType.ISPOINTLIST)
188 _coordList = inChild._coordList;
189 _type = BlockType.HASPOINTLIST;
191 else if ((_type == BlockType.NONE || _type == BlockType.ISPOINTLIST)
192 && !_hasNonNumbers && inChild._type == BlockType.ISPOINTLIST)
194 if (_coordList == null) {
195 _coordList = new ArrayList<ArrayList<String>>();
197 _coordList.addAll(inChild._coordList);
198 _type = BlockType.ISPOINTLIST;
203 * @return number of points in the list, if this block has a list
205 public int getNumPoints()
207 if (hasValidCoordList()) {
208 return _coordList.size();
214 * @param inIndex point index within list
215 * @return created point for specified index
217 public JsonPoint createPointFromList(int inIndex)
219 if (inIndex < 0 || inIndex >= getNumPoints()) {return null;}
220 ArrayList<String> pointCoords = _coordList.get(inIndex);
221 if (pointCoords.size() < 2 || pointCoords.size() > 3) {return null;}
222 final String longitude = pointCoords.get(0);
223 final String latitude = pointCoords.get(1);
224 final String altitude = ((pointCoords.size() == 3) ? pointCoords.get(3) : null);
225 return new JsonPoint(latitude, longitude, altitude, inIndex == 0);