Package org.exist.xquery.value

Source Code of org.exist.xquery.value.YearMonthDurationValue

/*
*  eXist Open Source Native XML Database
*  Copyright (C) 2001-06 Wolfgang M. Meier
*  wolfgang@exist-db.org
*  http://exist.sourceforge.net
*  This program is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Lesser General Public License
*  as published by the Free Software Foundation; either version 2
*  of the License, or (at your option) any later version.
*  This program 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 Lesser General Public License for more details.
*  You should have received a copy of the GNU Lesser General Public License
*  along with this program; if not, write to the Free Software
*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*  $Id$
*/

package org.exist.xquery.value;

import java.math.BigDecimal;
import java.math.BigInteger;

import javax.xml.datatype.DatatypeConstants;
import javax.xml.datatype.Duration;

import org.exist.util.FastStringBuffer;
import org.exist.xquery.ErrorCodes;
import org.exist.xquery.XPathException;

/**
* @author <a href="mailto:piotr@ideanest.com">Piotr Kaminski</a>
*/
public class YearMonthDurationValue extends OrderedDurationValue {

  public static final Duration CANONICAL_ZERO_DURATION =
    TimeUtils.getInstance().newDuration(true, null, BigInteger.ZERO, null, null, null, null);
 
  YearMonthDurationValue(Duration duration) throws XPathException
    super(duration);
    if (!duration.equals(DurationValue.CANONICAL_ZERO_DURATION)) {
      if (duration.isSet(DatatypeConstants.DAYS) ||   
        duration.isSet(DatatypeConstants.HOURS) ||
        duration.isSet(DatatypeConstants.MINUTES) ||
        //Always set !
        //!duration.getField(DatatypeConstants.SECONDS).equals(BigInteger.ZERO))
        duration.isSet(DatatypeConstants.SECONDS))
        {throw new XPathException(ErrorCodes.XPTY0004, "The value '" + duration + "' is not an " + Type.getTypeName(getType()) +
            " since it specifies days, hours, minutes or seconds values");}
    }   
  }

  public YearMonthDurationValue(String str) throws XPathException {
    this(createDurationYearMonth(str));   
  }
 
  private static Duration createDurationYearMonth(String str) throws XPathException {
    try {
      return TimeUtils.getInstance().newDurationYearMonth(StringValue.trimWhitespace(str));
    } catch (final IllegalArgumentException e) {
      throw new XPathException(ErrorCodes.FORG0001, "cannot construct " + Type.getTypeName(Type.YEAR_MONTH_DURATION) +
          " from \"" + str + "\"");           
    }
  }
 
  public DurationValue wrap() {
    return this;
  }
 
  protected Duration canonicalZeroDuration() {
    return CANONICAL_ZERO_DURATION;
  }
 
  public int getValue() {
    return duration.getSign() * (duration.getYears() * 12 + duration.getMonths());
  }

  public int getType() {
    return Type.YEAR_MONTH_DURATION;
  }
 
  public String getStringValue() {
        final FastStringBuffer sb = new FastStringBuffer(32);
        if (getCanonicalDuration().getSign() < 0) {
            sb.append('-');
        }
        sb.append('P');
        if (getCanonicalDuration().getYears() != 0) {
            sb.append(getCanonicalDuration().getYears() + "Y");
        }
        if (getCanonicalDuration().getMonths() !=0 || getCanonicalDuration().getYears() == 0) {
            sb.append(getCanonicalDuration().getMonths() + "M");
        }
        return sb.toString();
 

  public AtomicValue convertTo(int requiredType) throws XPathException {
    switch (requiredType) {
      case Type.ITEM :
      case Type.ATOMIC :
      case Type.YEAR_MONTH_DURATION :
        return this;
      case Type.STRING :
        return new StringValue(getStringValue());
      case Type.DURATION :
        return new DurationValue(TimeUtils.getInstance().newDuration(
            duration.getSign() >= 0,
            (BigInteger) duration.getField(DatatypeConstants.YEARS),
            (BigInteger) duration.getField(DatatypeConstants.MONTHS),
            null, null, null, null
        ));
      case Type.DAY_TIME_DURATION:
        return new DayTimeDurationValue(DayTimeDurationValue.CANONICAL_ZERO_DURATION);
      //case Type.DOUBLE:
        //return new DoubleValue(monthsValueSigned().doubleValue());
        //return new DoubleValue(Double.NaN);
      //case Type.DECIMAL:
        //return new DecimalValue(monthsValueSigned().doubleValue());
      case Type.UNTYPED_ATOMIC :
        return new UntypedAtomicValue(getStringValue());       
      default :
        throw new XPathException(ErrorCodes.XPTY0004,
          "cannot cast 'xs:yearMonthDuration(\"" + getStringValue() +
          "\")' to " + Type.getTypeName(requiredType));
    }
  }

  protected DurationValue createSameKind(Duration dur) throws XPathException {
    return new YearMonthDurationValue(dur);
  }
 
  public ComputableValue plus(ComputableValue other) throws XPathException {
    try {
      if (other.getType() == Type.TIME) {throw new IllegalArgumentException();}
      return super.plus(other);
    } catch (final IllegalArgumentException e) {
      throw new XPathException(
          "Operand to plus should be of type xdt:yearMonthDuration, xs:date, "
            + "or xs:dateTime; got: "
            + Type.getTypeName(other.getType()));
    }
  }
 
  public ComputableValue mult(ComputableValue other) throws XPathException {
    if (other instanceof NumericValue) {
      //If $arg2 is NaN an error is raised [err:FOCA0005]
      if (((NumericValue)other).isNaN()) {
        throw new XPathException(ErrorCodes.FOCA0005, "Operand is not a number");       
      }   
      //If $arg2 is positive or negative infinity, the result overflows
      if (((NumericValue)other).isInfinite()) {
        throw new XPathException(ErrorCodes.FODT0002, "Multiplication by infinity overflow");   
      }   
    }
    final BigDecimal factor = numberToBigDecimal(other, "Operand to mult should be of numeric type; got: ");
   
    final boolean isFactorNegative = factor.signum() < 0;   
   
    final YearMonthDurationValue product = fromDecimalMonths(
      new BigDecimal(monthsValueSigned())
      .multiply(factor.abs())
      .setScale(0, (isFactorNegative)? BigDecimal.ROUND_HALF_DOWN : BigDecimal.ROUND_HALF_UP)
    );
   
    if (isFactorNegative)
      {return product.negate();}
   
    return product;
  }

  public ComputableValue div(ComputableValue other) throws XPathException {
    if (other.getType() == Type.YEAR_MONTH_DURATION) {
      return new IntegerValue(getValue()).div(new IntegerValue(((YearMonthDurationValue) other).getValue()));
    }
    if (other instanceof NumericValue) {
      if (((NumericValue)other).isNaN()) {
        throw new XPathException(ErrorCodes.FOCA0005, "Operand is not a number");       
      }
      if (((NumericValue)other).isInfinite()) {
        return new YearMonthDurationValue("P0M");
      }
      //If $arg2 is positive or negative zero, the result overflows and is handled as discussed in 10.1.1 Limits and Precision
      if (((NumericValue)other).isZero()) {
        throw new XPathException(ErrorCodes.FODT0002, "Division by zero overflow");
      }     
    }
    final BigDecimal divisor = numberToBigDecimal(other, "Can not divide xdt:yearMonthDuration by '" + Type.getTypeName(other.getType())+ "'");
   
    final boolean isDivisorNegative = divisor.signum() < 0;
   
    final YearMonthDurationValue quotient = fromDecimalMonths(
      new BigDecimal(monthsValueSigned())
      .divide(divisor.abs(), 0, (isDivisorNegative)? BigDecimal.ROUND_HALF_DOWN : BigDecimal.ROUND_HALF_UP));   
   
    if (isDivisorNegative)
      {return quotient.negate();}
   
    return new YearMonthDurationValue(quotient.getCanonicalDuration())
  }
 
  private YearMonthDurationValue fromDecimalMonths(BigDecimal x) throws XPathException {
    return new YearMonthDurationValue(TimeUtils.getInstance().newDurationYearMonth(
        x.signum() >= 0, null, x.toBigInteger()));
  }
 
    public boolean effectiveBooleanValue() throws XPathException {
        throw new XPathException(ErrorCodes.FORG0006,
        "value of type " + Type.getTypeName(getType()) +
            " has no boolean value.");
    }
}
TOP

Related Classes of org.exist.xquery.value.YearMonthDurationValue

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.