blob: ffe1c96203b42782861c69061bc821fb987d7004 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2010 Andrea Bittau, University College London, and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Andrea Bittau - initial API and implementation from the PsychoPath XPath 2.0
* Mukul Gandhi - bug 273760 - wrong namespace for functions and data types
* Mukul Gandhi - bug 279377 - improvements to multiplication and division operations
* on xs:dayTimeDuration.
* David Carver - bug 282223 - implementation of xs:duration
* Mukul Gandhi - bug 280798 - PsychoPath support for JDK 1.4
*******************************************************************************/
package org.eclipse.wst.xml.xpath2.processor.internal.types;
import org.eclipse.wst.xml.xpath2.processor.DynamicError;
import org.eclipse.wst.xml.xpath2.processor.ResultSequence;
import org.eclipse.wst.xml.xpath2.processor.ResultSequenceFactory;
import org.eclipse.wst.xml.xpath2.processor.internal.function.CmpEq;
import org.eclipse.wst.xml.xpath2.processor.internal.function.CmpGt;
import org.eclipse.wst.xml.xpath2.processor.internal.function.CmpLt;
import org.eclipse.wst.xml.xpath2.processor.internal.function.MathDiv;
import org.eclipse.wst.xml.xpath2.processor.internal.function.MathMinus;
import org.eclipse.wst.xml.xpath2.processor.internal.function.MathPlus;
import org.eclipse.wst.xml.xpath2.processor.internal.function.MathTimes;
import java.math.BigDecimal;
import java.util.Calendar;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.Duration;
/**
* A representation of the DayTimeDuration datatype
*/
public class XSDayTimeDuration extends XSDuration implements CmpEq, CmpLt,
CmpGt,
MathPlus, MathMinus, MathTimes, MathDiv,
Cloneable {
private static final String XS_DAY_TIME_DURATION = "xs:dayTimeDuration";
/**
* Initialises to the supplied parameters. If more than 24 hours is
* supplied, the number of days is adjusted acordingly. The same occurs for
* minutes and seconds
*
* @param days
* Number of days in this duration of time
* @param hours
* Number of hours in this duration of time
* @param minutes
* Number of minutes in this duration of time
* @param seconds
* Number of seconds in this duration of time
* @param negative
* True if this duration of time represents a backwards passage
* through time. False otherwise
*/
public XSDayTimeDuration(int days, int hours, int minutes, double seconds,
boolean negative) {
super(0, 0, days, hours, minutes, seconds, negative);
}
/**
* Initialises to the given number of seconds
*
* @param secs
* Number of seconds in the duration of time
*/
public XSDayTimeDuration(double secs) {
super(0, 0, 0, 0, 0, Math.abs(secs), secs < 0);
}
/**
* Initialises to a duration of no time (0days, 0hours, 0minutes, 0seconds)
*/
public XSDayTimeDuration() {
super(0, 0, 0, 0, 0, 0.0, false);
}
/**
* Creates a copy of this representation of a time duration
*
* @return New XSDayTimeDuration representing the duration of time stored
* @throws CloneNotSupportedException
*/
public Object clone() throws CloneNotSupportedException {
return new XSDayTimeDuration(days(), hours(), minutes(), seconds(),
negative());
}
public ResultSequence constructor(ResultSequence arg) throws DynamicError {
ResultSequence rs = ResultSequenceFactory.create_new();
if (arg.empty())
return rs;
AnyAtomicType aat = (AnyAtomicType) arg.first();
if (aat instanceof NumericType || aat instanceof CalendarType ||
aat instanceof XSBoolean || aat instanceof XSBase64Binary ||
aat instanceof XSHexBinary || aat instanceof XSAnyURI) {
throw DynamicError.invalidType();
}
if (!isCastable(aat)) {
throw DynamicError.cant_cast(null);
}
XSDuration dtd = castDayTimeDuration(aat);
if (dtd == null)
throw DynamicError.cant_cast(null);
rs.add(dtd);
return rs;
}
private XSDuration castDayTimeDuration(AnyAtomicType aat) {
if (aat instanceof XSDuration) {
XSDuration duration = (XSDuration) aat;
return new XSDayTimeDuration(duration.days(), duration.hours(), duration.minutes(), duration.seconds(), duration.negative());
}
return parseDTDuration(aat.string_value());
}
/**
* Creates a new XSDayTimeDuration by parsing the supplied String
* represented duration of time
*
* @param str
* String represented duration of time
* @return New XSDayTimeDuration representing the duration of time supplied
*/
public static XSDuration parseDTDuration(String str) {
boolean negative = false;
int days = 0;
int hours = 0;
int minutes = 0;
double seconds = 0;
// string following the P
String pstr = null;
String tstr = null;
// get the negative and pstr
if (str.startsWith("-P")) {
negative = true;
pstr = str.substring(2, str.length());
} else if (str.startsWith("P")) {
negative = false;
pstr = str.substring(1, str.length());
} else
return null;
try {
// get the days
int index = pstr.indexOf('D');
boolean did_something = false;
// no D... must have T
if (index == -1) {
if (pstr.startsWith("T")) {
tstr = pstr.substring(1, pstr.length());
} else
return null;
} else {
String digit = pstr.substring(0, index);
days = Integer.parseInt(digit);
tstr = pstr.substring(index + 1, pstr.length());
if (tstr.startsWith("T")) {
tstr = tstr.substring(1, tstr.length());
} else {
if (tstr.length() > 0)
return null;
tstr = "";
did_something = true;
}
}
// do the T str
// hour
index = tstr.indexOf('H');
if (index != -1) {
String digit = tstr.substring(0, index);
hours = Integer.parseInt(digit);
tstr = tstr.substring(index + 1, tstr.length());
did_something = true;
}
// minute
index = tstr.indexOf('M');
if (index != -1) {
String digit = tstr.substring(0, index);
minutes = Integer.parseInt(digit);
tstr = tstr.substring(index + 1, tstr.length());
did_something = true;
}
// seconds
index = tstr.indexOf('S');
if (index != -1) {
String digit = tstr.substring(0, index);
seconds = Double.parseDouble(digit);
tstr = tstr.substring(index + 1, tstr.length());
did_something = true;
}
if (did_something) {
// make sure we parsed it all
if (tstr.length() != 0)
return null;
} else {
return null;
}
} catch (NumberFormatException err) {
return null;
}
return new XSDayTimeDuration(days, hours, minutes, seconds, negative);
}
/**
* Retrives the datatype's name
*
* @return "dayTimeDuration" which is the datatype's name
*/
public String type_name() {
return "dayTimeDuration";
}
/**
* Retrieves the datatype's full pathname
*
* @return "xs:dayTimeDuration" which is the datatype's full pathname
*/
public String string_type() {
return XS_DAY_TIME_DURATION;
}
/**
* Mathematical addition between this duration stored and the supplied
* duration of time (of type XSDayTimeDuration)
*
* @param arg
* The duration of time to add
* @return New XSDayTimeDuration representing the resulting duration after
* the addition
* @throws DynamicError
*/
public ResultSequence plus(ResultSequence arg) throws DynamicError {
XSDuration val = (XSDuration) NumericType
.get_single_type(arg, XSDayTimeDuration.class);
double res = value() + val.value();
return ResultSequenceFactory.create_new(new XSDayTimeDuration(res));
}
/**
* Mathematical subtraction between this duration stored and the supplied
* duration of time (of type XSDayTimeDuration)
*
* @param arg
* The duration of time to subtract
* @return New XSDayTimeDuration representing the resulting duration after
* the subtraction
* @throws DynamicError
*/
public ResultSequence minus(ResultSequence arg) throws DynamicError {
XSDuration val = (XSDuration) NumericType
.get_single_type(arg, XSDayTimeDuration.class);
double res = value() - val.value();
return ResultSequenceFactory.create_new(new XSDayTimeDuration(res));
}
/**
* Mathematical multiplication between this duration stored and the supplied
* duration of time (of type XSDayTimeDuration)
*
* @param arg
* The duration of time to multiply by
* @return New XSDayTimeDuration representing the resulting duration after
* the multiplication
* @throws DynamicError
*/
public ResultSequence times(ResultSequence arg) throws DynamicError {
ResultSequence convertedRS = arg;
if (arg.size() == 1) {
AnyType argValue = arg.first();
if (argValue instanceof XSDecimal) {
convertedRS = ResultSequenceFactory.create_new(new XSDouble(argValue.string_value()));
}
}
XSDouble val = (XSDouble) NumericType.get_single_type(convertedRS,
XSDouble.class);
if (val.nan()) {
throw DynamicError.nan();
}
double res = value() * val.double_value();
return ResultSequenceFactory.create_new(new XSDayTimeDuration(res));
}
/**
* Mathematical division between this duration stored and the supplied
* duration of time (of type XSDayTimeDuration)
*
* @param arg
* The duration of time to divide by
* @return New XSDayTimeDuration representing the resulting duration after
* the division
* @throws DynamicError
*/
public ResultSequence div(ResultSequence arg) throws DynamicError {
if (arg.size() != 1)
DynamicError.throw_type_error();
AnyType at = arg.first();
if (at instanceof XSDouble) {
XSDouble dt = (XSDouble) at;
double retval = 0;
if (dt.nan()) {
throw DynamicError.nan();
}
if (!dt.zero()) {
BigDecimal ret = new BigDecimal(0);
if (dt.infinite()) {
retval = value() / dt.double_value();
} else {
ret = new BigDecimal(value());
ret = ret.divide(new BigDecimal(dt.double_value()), 18, BigDecimal.ROUND_HALF_EVEN);
retval = ret.doubleValue();
}
} else {
throw DynamicError.overflowUnderflow();
}
// ret = value() / dt.double_value();
return ResultSequenceFactory
.create_new(new XSDayTimeDuration(retval));
} else if (at instanceof XSDecimal) {
XSDecimal dt = (XSDecimal) at;
BigDecimal ret = new BigDecimal(0);
if (!dt.zero()) {
ret = new BigDecimal(value());
ret = ret.divide(dt.getValue(), 18, BigDecimal.ROUND_HALF_EVEN);
} else {
throw DynamicError.overflowUnderflow();
}
return ResultSequenceFactory.create_new(new XSDayTimeDuration(
ret.intValue()));
} else if (at instanceof XSDayTimeDuration) {
XSDuration md = (XSDuration) at;
BigDecimal res = null;
try {
Duration thisDuration = DatatypeFactory.newInstance().newDuration(string_value());
Duration mdduration = DatatypeFactory.newInstance().newDuration(md.string_value());
double thistime = thisDuration.getTimeInMillis(Calendar.getInstance());
double thattime = mdduration.getTimeInMillis(Calendar.getInstance());
res = new BigDecimal(thistime);
BigDecimal l = new BigDecimal(thattime);
res = res.divide(l, 18, BigDecimal.ROUND_HALF_EVEN);
} catch (DatatypeConfigurationException ex) {
}
// double res = value() / md.value();
return ResultSequenceFactory.create_new(new XSDecimal(res));
} else {
DynamicError.throw_type_error();
return null; // unreach
}
}
}