/* This file is part of RouteConverter. RouteConverter is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. RouteConverter is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with RouteConverter; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Copyright (C) 2007 Christian Pesch. All Rights Reserved. */ package slash.navigation.copilot; import slash.navigation.base.*; import slash.navigation.common.NavigationPosition; import java.io.BufferedReader; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.prefs.Preferences; import java.util.regex.Matcher; import java.util.regex.Pattern; import static slash.common.io.Transfer.*; import static slash.navigation.base.RouteCalculations.asWgs84Position; import static slash.navigation.base.RouteCharacteristics.Route; /** * The base of all CoPilot formats. * * @author Christian Pesch */ public abstract class CoPilotFormat extends SimpleFormat<Wgs84Route> { private static final Preferences preferences = Preferences.userNodeForPackage(CoPilotFormat.class); protected static final String DATA_VERSION = "Data Version"; private static final String START_TRIP = "Start Trip"; private static final String END_TRIP = "End Trip"; private static final String START_STOP = "Start Stop"; private static final String END_STOP = "End Stop"; private static final String START_STOP_OPT = "Start StopOpt"; private static final String END_STOP_OPT = "End StopOpt"; private static final String STOP = "Stop"; protected static final char NAME_VALUE_SEPARATOR = '='; protected static final Pattern NAME_VALUE_PATTERN = Pattern.compile("(.+?)" + NAME_VALUE_SEPARATOR + "(.+|)"); protected static final double INTEGER_FACTOR = 1000000.0; private static final String CREATOR = "Creator"; private static final String LONGITUDE = "Longitude"; private static final String LATITUDE = "Latitude"; private static final String STATE = "State"; private static final String ZIP = "Zip"; private static final String CITY = "City"; private static final String COUNTY = "County"; private static final String ADDRESS = "Address"; // houseNumber<space>street private static final String SHOW = "Show"; private static final String SEQUENCE = "Sequence"; public String getExtension() { return ".trp"; } public int getMaximumPositionCount() { return UNLIMITED_MAXIMUM_POSITION_COUNT; } @SuppressWarnings("unchecked") public <P extends NavigationPosition> Wgs84Route createRoute(RouteCharacteristics characteristics, String name, List<P> positions) { return new Wgs84Route(this, characteristics, (List<Wgs84Position>) positions); } public BaseNavigationPosition getDuplicateFirstPosition(BaseRoute<BaseNavigationPosition, BaseNavigationFormat> route) { List<BaseNavigationPosition> positions = route.getPositions(); NavigationPosition first = positions.get(0); return asWgs84Position(first.getLongitude(), first.getLatitude(), "Start:" + first.getDescription()); } public void read(BufferedReader reader, String encoding, ParserContext<Wgs84Route> context) throws IOException { List<Wgs84Position> positions = new ArrayList<>(); Map<String, String> map = new HashMap<>(); String routeName = null; while (true) { String line = reader.readLine(); if (line == null) break; if (trim(line) == null) continue; //noinspection StatementWithEmptyBody if (isDataVersion(line) || line.startsWith(END_TRIP) || line.startsWith(END_STOP_OPT)) { } else if (line.startsWith(START_TRIP)) { routeName = trim(parseValue(line)); map.clear(); } else if (line.startsWith(START_STOP) || line.startsWith(START_STOP_OPT)) { map.clear(); } else if (line.startsWith(END_STOP)) { Wgs84Position position = parsePosition(map); positions.add(position); map.clear(); } else if (isNameValue(line)) { String name = parseName(line); String value = parseValue(line); map.put(name, value); } else { return; } } if (positions.size() > 0) context.appendRoute(createRoute(Route, routeName, positions)); } protected abstract boolean isDataVersion(String line); boolean isNameValue(String line) { Matcher matcher = NAME_VALUE_PATTERN.matcher(line); return matcher.matches(); } private String parseName(String line) { Matcher matcher = NAME_VALUE_PATTERN.matcher(line); if (!matcher.matches()) throw new IllegalArgumentException("'" + line + "' does not match"); return matcher.group(1); } private String parseValue(String line) { Matcher matcher = NAME_VALUE_PATTERN.matcher(line); if (!matcher.matches()) throw new IllegalArgumentException("'" + line + "' does not match"); return matcher.group(2); } Wgs84Position parsePosition(Map<String, String> map) { Integer latitude = parseInteger(map.get(LATITUDE)); Integer longitude = parseInteger(map.get(LONGITUDE)); String state = trim(map.get(STATE)); String zip = trim(map.get(ZIP)); String city = trim(map.get(CITY)); String county = trim(map.get(COUNTY)); String address = trim(map.get(ADDRESS)); String description = (state != null ? state + (zip != null ? "-" : " ") : "") + (zip != null ? zip + " " : "") + (city != null ? city : "") + (county != null ? ", " + county : "") + (address != null ? ", " + address : ""); return new Wgs84Position(longitude != null ? longitude / INTEGER_FACTOR : null, latitude != null ? latitude / INTEGER_FACTOR : null, null, null, null, trim(description)); } protected void writeHeader(Wgs84Route route, PrintWriter writer) { writer.println(START_TRIP + NAME_VALUE_SEPARATOR + asRouteName(route.getName())); writer.println(CREATOR + NAME_VALUE_SEPARATOR + GENERATED_BY); writer.println("TollClosed=0"); writer.println(END_TRIP); writer.println(); } protected void writePositions(Wgs84Route route, PrintWriter writer, int startIndex, int endIndex) { List<Wgs84Position> positions = route.getPositions(); for (int i = startIndex; i < endIndex; i++) { Wgs84Position position = positions.get(i); writer.println(START_STOP + NAME_VALUE_SEPARATOR + STOP + " " + i); String longitude = formatIntAsString(position.getLongitude() != null ? (int) (position.getLongitude() * INTEGER_FACTOR) : null); writer.println(LONGITUDE + NAME_VALUE_SEPARATOR + longitude); String latitude = formatIntAsString(position.getLatitude() != null ? (int) (position.getLatitude() * INTEGER_FACTOR) : null); writer.println(LATITUDE + NAME_VALUE_SEPARATOR + latitude); // TODO write decomposed description // Name= // Address=11 Veilchenstrasse // City=Gladbeck // State=DE // County=Recklinghausen // Zip=47853 String description = position.getDescription(); int index = description.indexOf(','); String city = index != -1 ? description.substring(0, index) : description; city = trim(city); String address = index != -1 ? description.substring(index + 1) : description; address = trim(address); boolean first = i == startIndex; boolean last = i == endIndex - 1; // only store address if there was a comma in the description writer.println(ADDRESS + NAME_VALUE_SEPARATOR + (index != -1 ? address : "")); // otherwise store description als city writer.println(CITY + NAME_VALUE_SEPARATOR + city); if (first || last || preferences.getBoolean("writeTargets", false)) writer.println(SHOW + NAME_VALUE_SEPARATOR + "1"); // Target/Stop target else writer.println(SHOW + NAME_VALUE_SEPARATOR + "0"); // Waypoint writer.println(SEQUENCE + NAME_VALUE_SEPARATOR + i); writer.println(END_STOP); writer.println(); writer.println(START_STOP_OPT + NAME_VALUE_SEPARATOR + STOP + " " + i); writer.println("Loaded=1"); writer.println(END_STOP_OPT); writer.println(); } } }