package tim.prune.load; import tim.prune.I18nManager; import tim.prune.data.Field; import tim.prune.data.Latitude; import tim.prune.data.Longitude; import tim.prune.data.TimestampUtc; /** * Class to try to match data with field names, * using a variety of guessing techniques */ public abstract class FieldGuesser { /** * Try to guess whether the given line is a header line or data * @param inValues array of values from first non-blank line of file * @return true if it looks like a header row, false if it looks like data */ private static boolean isHeaderRow(String[] inValues) { // Loop over values seeing if any are mostly numeric if (inValues != null) { for (String value : inValues) { if (fieldLooksNumeric(value)) {return false;} } } // No (mostly) numeric values found so presume header return true; } /** * See if a field looks numeric or not by comparing the number of numeric vs non-numeric characters * @param inValue field value to check * @return true if there are more numeric characters than not */ private static boolean fieldLooksNumeric(String inValue) { if (inValue == null) { return false; } final int numChars = inValue.length(); if (numChars < 3) {return false;} // Don't care about one or two character values // Loop through characters seeing which ones are numeric and which not int numNums = 0; for (int i=0; i= '0' && currChar <= '9') {numNums++;} } // Return true if more than half the characters are numeric return numNums > (numChars/2); } /** * Try to guess the fields for the given values from the file * @param inValues array of values from first non-blank line of file * @return array of fields which hopefully match */ public static Field[] guessFields(String[] inValues) { // Guess whether it's a header line or not boolean isHeader = isHeaderRow(inValues); // make array of Fields int numFields = inValues.length; Field[] fields = new Field[numFields]; // Loop over fields to try to guess the main ones for (int f=0; f 0) { customField = new Field(inValues[f]); } // Find an unused field number while (customField == null || checkArrayHasField(fields, customField)) { customFieldNum++; customField = new Field(customPrefix + (customFieldNum)); } fields[f] = customField; } } } // Do a final check to make sure lat and long are in there if (!checkArrayHasField(fields, Field.LATITUDE)) { fields[0] = Field.LATITUDE; } else if (!checkArrayHasField(fields, Field.LONGITUDE)) { fields[1] = Field.LONGITUDE; } // Longitude _could_ have overwritten latitude in position 1 if (!checkArrayHasField(fields, Field.LATITUDE)) { fields[0] = Field.LATITUDE; } return fields; } /** * Check whether the given field array has the specified field * @param inFields * @param inCheckField * @return true if Field is contained within the array */ private static boolean checkArrayHasField(Field[] inFields, Field inCheckField) { for (int f=0; f 0 && intValue < 100000); } catch (NumberFormatException nfe) {} return false; } } /** * Check whether the given String looks like a waypoint name * @param inValue value from file * @param inIsHeader true if this is a header line, false for data * @return true if it could be a name */ private static boolean fieldLooksLikeName(String inValue, boolean inIsHeader) { if (inValue == null || inValue.equals("")) {return false;} if (inIsHeader) { // This is a header line so look for english or local text String upperValue = inValue.toUpperCase(); return (upperValue.equals("NAME") || upperValue.equals("LABEL") || upperValue.equals(I18nManager.getText("fieldname.waypointname").toUpperCase())); } else { // Look for at least two letters in it int numLetters = 0; for (int i=0; i= 2; } } /** * Check whether the given String looks like a timestamp * @param inValue value from file * @param inIsHeader true if this is a header line, false for data * @return true if it could be a timestamp */ private static boolean fieldLooksLikeTimestamp(String inValue, boolean inIsHeader) { if (inValue == null || inValue.equals("")) {return false;} if (inIsHeader) { String upperValue = inValue.toUpperCase(); // This is a header line so look for english or local text return (upperValue.equals("TIMESTAMP") || upperValue.equals("TIME") || upperValue.equals(I18nManager.getText("fieldname.timestamp").toUpperCase())); } else { // must be at least 7 characters long if (inValue.length() < 7) {return false;} TimestampUtc stamp = new TimestampUtc(inValue); return stamp.isValid(); } } /** * Check whether the given String looks like a track segment field * @param inValue value from file * @param inIsHeader true if this is a header line, false for data * @return true if it could be a track segment */ private static boolean fieldLooksLikeSegment(String inValue, boolean inIsHeader) { if (inValue == null || inValue.equals("")) {return false;} if (inIsHeader) { String upperValue = inValue.toUpperCase(); // This is a header line so look for english or local text return upperValue.equals("SEGMENT") || upperValue.equals(I18nManager.getText("fieldname.newsegment").toUpperCase()); } else { // can't reliably identify it just using the value return false; } } /** * Check whether the given String looks like a waypoint type * @param inValue value from file * @param inIsHeader true if this is a header line, false for data * @return true if it could be a waypoint type */ private static boolean fieldLooksLikeWaypointType(String inValue, boolean inIsHeader) { if (inValue == null || inValue.equals("")) {return false;} if (inIsHeader) { String upperValue = inValue.toUpperCase(); // This is a header line so look for english or local text return (upperValue.equals("TYPE") || upperValue.equals(I18nManager.getText("fieldname.waypointtype").toUpperCase())); } else { // can't reliably identify it just using the value return false; } } }