001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2004-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.referencing.factory.wms;
017:
018: // OpenGIS dependencies
019: import org.opengis.referencing.NoSuchAuthorityCodeException;
020:
021: // Geotools dependencies
022: import org.geotools.measure.Latitude;
023: import org.geotools.measure.Longitude;
024: import org.geotools.resources.Utilities;
025: import org.geotools.resources.i18n.Errors;
026: import org.geotools.resources.i18n.ErrorKeys;
027:
028: /**
029: * A code parsed by the {@link AutoCRSFactory} methods.
030: * The expected format is {@code AUTO:code,lon0,lat0} where {@code AUTO} is optional.
031: *
032: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/factory/wms/Code.java $
033: * @version $Id: Code.java 20874 2006-08-07 10:00:01Z jgarnett $
034: * @author Jody Garnett
035: * @author Martin Desruisseaux
036: */
037: final class Code {
038: /**
039: * The authority name. Should usually be {@code AUTO}.
040: */
041: public final String authority;
042:
043: /**
044: * The code number.
045: */
046: public final int code;
047:
048: /**
049: * The central longitude.
050: */
051: public final double longitude;
052:
053: /**
054: * The central latitude.
055: */
056: public final double latitude;
057:
058: /**
059: * The type of the CRS to be constructed (e.g. {@code GeographicCRS.class}).
060: * Used only in case of failure for constructing an error message.
061: */
062: final Class type;
063:
064: /**
065: * Parse the code string to retrive the code number and central longitude / latitude.
066: * Assumed format is {@code AUTO:code,lon0,lat0} where {@code AUTO} is optional.
067: *
068: * @param text The code in the {@code AUTO:code,lon0,lat0} format.
069: * @param The type of the CRS to be constructed (e.g. {@code GeographicCRS.class}).
070: * Used only in case of failure for constructing an error message.
071: * @throws NoSuchAuthorityCodeException if the specified code can't be parsed.
072: */
073: public Code(final String text, final Class type)
074: throws NoSuchAuthorityCodeException {
075: String authority = "AUTO";
076: int code = 0;
077: double longitude = Double.NaN;
078: double latitude = Double.NaN;
079: int startField = -1;
080: parse: for (int i = 0; /*stop condition in the 'switch' statement below*/; i++) {
081: final char delimiter = (i == 0) ? ':' : ',';
082: int endField = text.indexOf(delimiter, ++startField);
083: if (endField < 0) {
084: if (i == 0) {
085: // The "AUTO" prefix is optional. Continue the search for next fields.
086: startField = -1;
087: continue;
088: }
089: endField = text.length();
090: }
091: if (endField <= startField) {
092: // A required field was not found.
093: throw noSuchAuthorityCode(type, text);
094: }
095: final String field = text.substring(startField, endField)
096: .trim();
097: try {
098: switch (i) {
099: default:
100: throw new AssertionError(i);
101: case 0:
102: authority = field;
103: break;
104: case 1:
105: code = Integer.parseInt(field);
106: break;
107: case 2:
108: longitude = Double.parseDouble(field);
109: break;
110: case 3:
111: latitude = Double.parseDouble(field);
112: break parse;
113: /*
114: * Add case statements here if the is more fields to parse.
115: * Only the last case should end with 'break parse' instead of 'break'.
116: */
117: }
118: } catch (NumberFormatException exception) {
119: // If a number can't be parsed, then this is an invalid authority code.
120: NoSuchAuthorityCodeException e = noSuchAuthorityCode(
121: type, text);
122: e.initCause(exception);
123: throw e;
124: }
125: startField = endField;
126: }
127: if (!(longitude >= Longitude.MIN_VALUE
128: && longitude <= Longitude.MAX_VALUE
129: && latitude >= Latitude.MIN_VALUE && latitude <= Latitude.MAX_VALUE)) {
130: // A longitude or latitude is out of range, or was not present
131: // (i.e. the field still has a NaN value).
132: throw noSuchAuthorityCode(type, text);
133: }
134: this .authority = authority;
135: this .code = code;
136: this .longitude = longitude;
137: this .latitude = latitude;
138: this .type = type;
139: }
140:
141: /**
142: * Creates an exception for an unknow authority code.
143: *
144: * @param type The GeoAPI interface that was to be created.
145: * @param code The unknow authority code.
146: * @return An exception initialized with an error message built from the specified informations.
147: */
148: private static NoSuchAuthorityCodeException noSuchAuthorityCode(
149: final Class type, final String code) {
150: final String authority = "AUTO";
151: return new NoSuchAuthorityCodeException(Errors.format(
152: ErrorKeys.NO_SUCH_AUTHORITY_CODE_$3, code, authority,
153: Utilities.getShortName(type)), authority, code);
154: }
155:
156: /**
157: * Returns a string representation of this code.
158: */
159: public String toString() {
160: return authority + ':' + code + ',' + longitude + ','
161: + latitude;
162: }
163: }
|