]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/load/FieldGuesser.java
Version 4, January 2008
[GpsPrune.git] / tim / prune / load / FieldGuesser.java
1 package tim.prune.load;
2
3 import tim.prune.I18nManager;
4 import tim.prune.data.Field;
5 import tim.prune.data.Latitude;
6 import tim.prune.data.Longitude;
7 import tim.prune.data.Timestamp;
8
9 /**
10  * Class to try to match data with field names,
11  * using a variety of guessing techniques
12  */
13 public abstract class FieldGuesser
14 {
15         /**
16          * Try to guess whether the given line is a header line or data
17          * @param inValues array of values from first non-blank line of file
18          * @return true if it looks like a header row, false if it looks like data
19          */
20         private static boolean isHeaderRow(String[] inValues)
21         {
22                 // Loop over values looking for a Latitude value
23                 if (inValues != null)
24                 {
25                         for (int v=0; v<inValues.length; v++)
26                         {
27                                 Latitude lat = new Latitude(inValues[v]);
28                                 if (lat.isValid()) {return false;}
29                         }
30                 }
31                 // No valid Latitude value found so presume header
32                 return true;
33         }
34
35
36         /**
37          * Try to guess the fields for the given values from the file
38          * @param inValues array of values from first non-blank line of file
39          * @return array of fields which hopefully match
40          */
41         public static Field[] guessFields(String[] inValues)
42         {
43                 // Guess whether it's a header line or not
44                 boolean isHeader = isHeaderRow(inValues);
45                 // make array of Fields
46                 int numFields = inValues.length;
47                 Field[] fields = new Field[numFields];
48                 // Loop over fields to try to guess the main ones
49                 for (int f=0; f<numFields; f++)
50                 {
51                         if (inValues[f] != null) {
52                                 String value = inValues[f].trim();
53                                 // check for latitude
54                                 if (!checkArrayHasField(fields, Field.LATITUDE) && fieldLooksLikeLatitude(value, isHeader))
55                                 {
56                                         fields[f] = Field.LATITUDE;
57                                         continue;
58                                 }
59                                 // check for longitude
60                                 if (!checkArrayHasField(fields, Field.LONGITUDE) && fieldLooksLikeLongitude(value, isHeader))
61                                 {
62                                         fields[f] = Field.LONGITUDE;
63                                         continue;
64                                 }
65                                 // check for altitude
66                                 if (!checkArrayHasField(fields, Field.ALTITUDE) && fieldLooksLikeAltitude(value, isHeader))
67                                 {
68                                         fields[f] = Field.ALTITUDE;
69                                         continue;
70                                 }
71                                 // check for waypoint name
72                                 if (!checkArrayHasField(fields, Field.WAYPT_NAME) && fieldLooksLikeName(value, isHeader))
73                                 {
74                                         fields[f] = Field.WAYPT_NAME;
75                                         continue;
76                                 }
77                                 // check for timestamp
78                                 if (!checkArrayHasField(fields, Field.TIMESTAMP) && fieldLooksLikeTimestamp(value, isHeader))
79                                 {
80                                         fields[f] = Field.TIMESTAMP;
81                                         continue;
82                                 }
83                         }
84                 }
85                 // Fill in the rest of the fields using just custom fields
86                 // Could try to guess other fields (waypoint type, segment) or unguessed altitude, name, but keep simple for now
87                 String customPrefix = I18nManager.getText("fieldname.prefix") + " ";
88                 int customFieldNum = 0;
89                 for (int f=0; f<numFields; f++) {
90                         if (fields[f] == null)
91                         {
92                                 // Make sure lat and long are filled in if not already
93                                 if (!checkArrayHasField(fields, Field.LATITUDE)) {
94                                         fields[f] = Field.LATITUDE;
95                                 }
96                                 else if (!checkArrayHasField(fields, Field.LONGITUDE)) {
97                                         fields[f] = Field.LONGITUDE;
98                                 }
99                                 else {
100                                         customFieldNum++;
101                                         fields[f] = new Field(customPrefix + (customFieldNum));
102                                 }
103                         }
104                 }
105                 // Do a final check to make sure lat and long are in there
106                 if (!checkArrayHasField(fields, Field.LATITUDE)) {
107                         fields[0] = Field.LATITUDE;
108                 }
109                 else if (!checkArrayHasField(fields, Field.LONGITUDE)) {
110                         fields[1] = Field.LONGITUDE;
111                 }
112                 return fields;
113         }
114
115
116         /**
117          * Check whether the given field array has the specified field
118          * @param inFields
119          * @param inCheckField
120          * @return true if Field is contained within the array
121          */
122         private static boolean checkArrayHasField(Field[] inFields, Field inCheckField)
123         {
124                 for (int f=0; f<inFields.length; f++)
125                 {
126                         if (inFields[f] != null && inFields[f].equals(inCheckField)) {
127                                 return true;
128                         }
129                 }
130                 // not found
131                 return false;
132         }
133
134
135         /**
136          * Check whether the given String looks like a Latitude value
137          * @param inValue value from file
138          * @param inIsHeader true if this is a header line, false for data
139          * @return true if it could be latitude
140          */
141         private static boolean fieldLooksLikeLatitude(String inValue, boolean inIsHeader)
142         {
143                 if (inValue == null || inValue.equals("")) {return false;}
144                 if (inIsHeader)
145                 {
146                         // This is a header line so look for english or local text
147                         String upperValue = inValue.toUpperCase();
148                         return (upperValue.equals("LATITUDE")
149                                 || upperValue.equals(I18nManager.getText("fieldname.latitude").toUpperCase()));
150                 }
151                 else
152                 {
153                         // Note this will also catch longitudes too
154                         Latitude lat = new Latitude(inValue);
155                         return lat.isValid();
156                 }
157         }
158
159         /**
160          * Check whether the given String looks like a Longitude value
161          * @param inValue value from file
162          * @param inIsHeader true if this is a header line, false for data
163          * @return true if it could be longitude
164          */
165         private static boolean fieldLooksLikeLongitude(String inValue, boolean inIsHeader)
166         {
167                 if (inValue == null || inValue.equals("")) {return false;}
168                 if (inIsHeader)
169                 {
170                         // This is a header line so look for english or local text
171                         String upperValue = inValue.toUpperCase();
172                         return (upperValue.equals("LONGITUDE")
173                                 || upperValue.equals(I18nManager.getText("fieldname.longitude").toUpperCase()));
174                 }
175                 else
176                 {
177                         // Note this will also catch latitudes too
178                         Longitude lon = new Longitude(inValue);
179                         return lon.isValid();
180                 }
181         }
182
183         /**
184          * Check whether the given String looks like an Altitude value
185          * @param inValue value from file
186          * @param inIsHeader true if this is a header line, false for data
187          * @return true if it could be altitude
188          */
189         private static boolean fieldLooksLikeAltitude(String inValue, boolean inIsHeader)
190         {
191                 if (inValue == null || inValue.equals("")) {return false;}
192                 if (inIsHeader)
193                 {
194                         // This is a header line so look for english or local text
195                         String upperValue = inValue.toUpperCase();
196                         return (upperValue.equals("ALTITUDE")
197                                 || upperValue.equals("ALT")
198                                 || upperValue.equals(I18nManager.getText("fieldname.altitude").toUpperCase()));
199                 }
200                 else
201                 {
202                         // Look for a number less than 100000
203                         try
204                         {
205                                 int intValue = Integer.parseInt(inValue);
206                                 return (intValue > 0 && intValue < 100000);
207                         }
208                         catch (NumberFormatException nfe) {}
209                         return false;
210                 }
211         }
212
213
214         /**
215          * Check whether the given String looks like a waypoint name
216          * @param inValue value from file
217          * @param inIsHeader true if this is a header line, false for data
218          * @return true if it could be a name
219          */
220         private static boolean fieldLooksLikeName(String inValue, boolean inIsHeader)
221         {
222                 if (inValue == null || inValue.equals("")) {return false;}
223                 if (inIsHeader)
224                 {
225                         // This is a header line so look for english or local text
226                         String upperValue = inValue.toUpperCase();
227                         return (upperValue.equals("NAME")
228                                 || upperValue.equals("LABEL")
229                                 || upperValue.equals(I18nManager.getText("fieldname.waypointname").toUpperCase()));
230                 }
231                 else
232                 {
233                         // Look for at least two letters in it
234                         int numLetters = 0;
235                         for (int i=0; i<inValue.length(); i++)
236                         {
237                                 char currChar = inValue.charAt(i);
238                                 if (Character.isLetter(currChar)) {
239                                         numLetters++;
240                                 }
241                                 // Not interested if it contains ":" or "."
242                                 if (currChar == ':' || currChar == '.') {return false;}
243                         }
244                         return numLetters >= 2;
245                 }
246         }
247
248         /**
249          * Check whether the given String looks like a timestamp
250          * @param inValue value from file
251          * @param inIsHeader true if this is a header line, false for data
252          * @return true if it could be a timestamp
253          */
254         private static boolean fieldLooksLikeTimestamp(String inValue, boolean inIsHeader)
255         {
256                 if (inValue == null || inValue.equals("")) {return false;}
257                 if (inIsHeader)
258                 {
259                         String upperValue = inValue.toUpperCase();
260                         // This is a header line so look for english or local text
261                         return (upperValue.equals("TIMESTAMP")
262                                 || upperValue.equals("TIME")
263                                 || upperValue.equals(I18nManager.getText("fieldname.timestamp").toUpperCase()));
264                 }
265                 else
266                 {
267                         // must be at least 7 characters long
268                         if (inValue.length() < 7) {return false;}
269                         Timestamp stamp = new Timestamp(inValue);
270                         return stamp.isValid();
271                 }
272         }
273 }