package com.revolsys.beans;
import java.math.BigDecimal;
import java.math.MathContext;
import javax.measure.Measure;
import javax.measure.converter.UnitConverter;
import javax.measure.quantity.Quantity;
import javax.measure.unit.Unit;
import org.apache.commons.jexl.Expression;
import org.apache.commons.jexl.JexlContext;
import com.revolsys.util.JexlUtil;
public class ExpressionMeasurable<Q extends Quantity> extends Measure<Q> {
private static final long serialVersionUID = 1L;
private JexlContext context;
private final Expression expression;
private final Unit<Q> unit;
protected ExpressionMeasurable(final Expression expression, final JexlContext context,
final Unit<Q> unit) {
this.expression = expression;
this.context = context;
this.unit = unit;
}
public ExpressionMeasurable(final String expression, final Unit<Q> unit) {
try {
this.expression = JexlUtil.newExpression(expression);
} catch (final Exception e) {
throw new IllegalArgumentException("Expression " + expression + " is not valid", e);
}
this.unit = unit;
}
@Override
public BigDecimal decimalValue(final Unit<Q> arg0, final MathContext arg1)
throws ArithmeticException {
throw new UnsupportedOperationException();
}
@Override
public double doubleValue(final Unit<Q> unit) {
final Double value = getValue();
if (unit == this.unit || this.unit.equals(unit)) {
return value;
} else {
final UnitConverter unitConverter = this.unit.getConverterTo(unit);
return unitConverter.convert(value);
}
}
@Override
public Unit<Q> getUnit() {
return this.unit;
}
@Override
public Double getValue() {
if (this.expression == null) {
return Double.NaN;
} else {
try {
return Double
.valueOf(JexlUtil.evaluateExpression(this.context, this.expression).toString());
} catch (final NullPointerException e) {
return 0.0;
}
}
}
public void setContext(final JexlContext context) {
this.context = context;
}
@Override
public Measure to(final Unit<Q> unit) {
if (unit == this.unit || this.unit.equals(unit)) {
return this;
} else {
final UnitConverter unitConverter = this.unit.getConverterTo(unit);
final Unit<Q> transformedUnit = this.unit.transform(unitConverter);
return new ExpressionMeasurable<>(this.expression, this.context, transformedUnit);
}
}
}