/*
* Copyright 2003, 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.geotools.xml.impl;
import java.io.Serializable;
/** <p>Implementation of xs:duration.</p>
*
*
* @source $URL$
*/
public class Duration implements Serializable, Comparable {
private static final long serialVersionUID = 3257001055736117303L;
private final boolean isNegative;
private final int years, months, days, hours, minutes, seconds;
private final long millis;
/** Creates a new instance with the given values.
*/
public Duration(boolean pNegative, int pYears, int pMonths, int pDays, int pHours, int pMinutes, int pSeconds, long pMillis) {
isNegative = pNegative;
years = pYears;
months = pMonths;
days = pDays;
hours = pHours;
minutes = pMinutes;
seconds = pSeconds;
millis = pMillis;
}
/** <p>Returns the number of years.</p>
*/
public int getYears() {
return years;
}
/** <p>Returns the number of months.</p>
*/
public int getMonths() {
return months;
}
/** <p>Returns the number of days.</p>
*/
public int getDays() {
return days;
}
/** <p>Returns the number of hours.</p>
*/
public int getHours() {
return hours;
}
/** <p>Returns the number of minutes.</p>
*/
public int getMinutes() {
return minutes;
}
/** <p>Returns the number of seconds.</p>
*/
public int getSeconds() {
return seconds;
}
/** <p>Returns the number of milliseconds.</p>
*/
public long getMillis() {
return millis;
}
/** <p>Returns a string representation of this Duration.</p>
*/
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append('P');
sb.append(getYears());
sb.append('Y');
sb.append(getMonths());
sb.append('M');
sb.append(getDays());
sb.append("DT");
sb.append(getHours());
sb.append('H');
sb.append(getMinutes());
sb.append('M');
sb.append(getSeconds());
long m = getMillis();
if (m != 0) {
sb.append('.');
sb.append(m);
}
sb.append('S');
return sb.toString();
}
/** <p>Converts the given String representation into an instance of
* Duration.</p>
* @throws IllegalArgumentException The String could not be parsed.
*/
public static Duration valueOf(String pValue) {
if (pValue == null) {
throw new NullPointerException("The duration value must not be null.");
}
int len = pValue.length();
int offset = 0;
boolean isNegative;
if (len > 0) {
char c = pValue.charAt(0);
if (c == '-') {
isNegative = true;
++offset;
} else if (c == '+') {
isNegative = false;
++offset;
} else {
isNegative = false;
}
} else {
throw new IllegalArgumentException("Invalid duration: Empty string");
}
if (len == 0 || pValue.charAt(offset) != 'P') {
throw new IllegalArgumentException("Invalid duration: " + pValue + " (must start with P, +P, or -P)");
} else {
++offset;
}
int years = -1, months = -1, daysOfMonth = -1, hours = -1, minutes = -1, seconds = -1;
long millis = -1;
int preDecimalPoint = -1;
boolean separatorSeen = false;
StringBuffer digits = new StringBuffer();
while (offset < len) {
char c = pValue.charAt(offset);
if (Character.isDigit(c)) {
digits.append(c);
} else if (c == 'T') {
if (separatorSeen) {
throw new IllegalArgumentException("Invalid duration: " + pValue
+ " (date/time separator 'T' used twice)");
} else {
separatorSeen = true;
}
} else {
long l;
if (digits.length() == 0) {
l = 0;
} else {
try {
l = Long.parseLong(digits.toString());
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Invalid duration: " + pValue
+ " (max long value exceeded by " + digits + ")");
}
digits.setLength(0);
}
if (preDecimalPoint >= 0) {
if (c == 'S') {
if (!separatorSeen) {
throw new IllegalArgumentException("Invalid duration: " + pValue
+ "(seconds specified before date/time separator 'T' seen)");
}
if (seconds != -1) {
throw new IllegalArgumentException("Invalid duration: " + pValue
+ " (seconds specified twice)");
}
seconds = preDecimalPoint;
millis = l;
preDecimalPoint = -1;
} else {
throw new IllegalArgumentException("Invalid duration: " + pValue
+ " (decimal point not allowed here: "
+ preDecimalPoint + "." + digits + c + ")");
}
} else if (l > Integer.MAX_VALUE) {
throw new IllegalArgumentException("Invalid duration: " + pValue
+ " (max integer value exceeded by " + digits + ")");
} else {
int i = (int) l;
if (c == '.') {
preDecimalPoint = i;
} else if (separatorSeen) {
if (c == 'Y' || c == 'D') {
throw new IllegalArgumentException("Invalid duration: " + pValue
+ " (years or days of month specified after date/time separator 'T' seen)");
} else if (c == 'S') {
if (seconds != -1) {
throw new IllegalArgumentException("Invalid duration: " + pValue
+ " (seconds specified twice)");
}
seconds = i;
millis = 0;
} else if (c == 'M') {
if (minutes != -1) {
throw new IllegalArgumentException("Invalid duration: " + pValue
+ " (minutes specified twice)");
} else if (seconds != -1) {
throw new IllegalArgumentException("Invalid duration: " + pValue
+ " (minutes specified after seconds)");
}
minutes = i;
} else if (c == 'H') {
if (hours != -1) {
throw new IllegalArgumentException("Invalid duration: " + pValue
+ " (hours specified twice)");
} else if (minutes != -1) {
throw new IllegalArgumentException("Invalid duration: " + pValue
+ " (hours specified after minutes)");
} else if (seconds != -1) {
throw new IllegalArgumentException("Invalid duration: " + pValue
+ " (seconds specified after minutes)");
}
hours = i;
}
} else {
if (c == 'H' || c == 'S') {
throw new IllegalArgumentException("Invalid duration: " + pValue
+ " (hours or seconds specified before date/time separator 'T' seen)");
} else if (c == 'Y') {
if (years != -1) {
throw new IllegalArgumentException("Invalid duration: " + pValue
+ " (years specified twice)");
} else if (months != -1) {
throw new IllegalArgumentException("Invalid duration: " + pValue
+ " (years specified after months)");
} else if (daysOfMonth != -1) {
throw new IllegalArgumentException("Invalid duration: " + pValue
+ " (years specified after days of month)");
}
years = i;
} else if (c == 'M') {
if (months != -1) {
throw new IllegalArgumentException("Invalid duration: " + pValue
+ " (months specified twice)");
} else if (daysOfMonth != -1) {
throw new IllegalArgumentException("Invalid duration: " + pValue
+ " (days of month specified after months)");
}
months = i;
} else if (c == 'D') {
if (daysOfMonth != -1) {
throw new IllegalArgumentException("Invalid duration: " + pValue
+ " (days of month specified twice)");
}
daysOfMonth = i;
}
}
}
}
++offset;
}
return new Duration(isNegative,
years == -1 ? 0 : years,
months == -1 ? 0 : months,
daysOfMonth == -1 ? 0 :daysOfMonth,
hours == -1 ? 0 : hours,
minutes == -1 ? 0 : minutes,
seconds == -1 ? 0 : seconds,
millis == -1 ? 0 : millis);
}
public boolean equals(Object o) {
if (o == null || !(o instanceof Duration)) {
return false;
}
return compareTo((Duration) o) == 0;
}
public int compareTo(Object o) {
return compareTo((Duration) o);
}
/** Actual implementation of {@link #compareTo(Object)}.
*/
public int compareTo(Duration d) {
if (isNegative != d.isNegative) {
return isNegative ? -1 : 1;
}
if (years != d.years) { return years - d.years; }
if (months != d.months) { return months - d.months; }
if (days != d.days) { return days - d.days; }
if (hours != d.hours) { return hours - d.hours; }
if (minutes != d.minutes) { return minutes - d.minutes; }
if (seconds != d.seconds) { return seconds - d.seconds; }
if (millis > d.millis) {
return 1;
} else if (millis < d.millis) {
return -1;
} else {
return 0;
}
}
public int hashCode() {
return isNegative ? 1 : 0 + years + months + days + hours + minutes + seconds + (int) millis;
}
}