/*
* Copyright (c) 2017 OBiBa. All rights reserved.
*
* This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.obiba.magma.js.methods;
import javax.annotation.Nullable;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.Scriptable;
import org.obiba.magma.Value;
import org.obiba.magma.js.MagmaJsEvaluationRuntimeException;
import org.obiba.magma.js.ScriptableValue;
import org.obiba.magma.type.BooleanType;
import org.obiba.magma.type.DecimalType;
import org.obiba.magma.type.IntegerType;
import org.obiba.magma.type.TextType;
@SuppressWarnings(
{ "UnusedParameters", "StaticMethodOnlyUsedInOneClass" })
public class CompareMethods {
private CompareMethods() {
}
/**
* Returns a new {@link ScriptableValue} of the {@link IntegerType} indicating if the first parameter is greater than,
* equal to, or less than the second parameter. Both parameters must either both be numeric, both be BooleanType or
* both be TextType. Zero (0) is returned if the values are equal. A number greater than zero (1) is returned if the
* first parameter is greater than the second. A number less than zero (-1) is returned is the first parameter is
* less
* than the second.
* <p/>
* <pre>
* $('NumberVarOne').compare($('NumberVarTwo'))
* $('BooleanVarOne').compare($('BooleanVarTwo'))
* $('TextVarOne').compare($('TextVarTwo'))
* </pre>
*
* @throws MagmaJsEvaluationRuntimeException if operands are not ScriptableValue Objects of a numeric type,
* BooleanType or TextType. Also thrown if operands are null.
*/
public static ScriptableValue compare(Context ctx, Scriptable thisObj, Object[] args, @Nullable Function funObj)
throws MagmaJsEvaluationRuntimeException {
ScriptableValue firstOperand = (ScriptableValue) thisObj;
if(firstOperand.getValue().isNull()) {
throw new MagmaJsEvaluationRuntimeException("Cannot invoke compare() with null argument.");
}
if(args != null && args.length > 0 && args[0] instanceof ScriptableValue &&
!((ScriptableValue) args[0]).getValue().isNull()) {
ScriptableValue secondOperand = (ScriptableValue) args[0];
if(firstOperand.getValueType().isNumeric() && secondOperand.getValueType().isNumeric()) {
return numericCompare(thisObj, firstOperand, secondOperand);
}
if(firstOperand.getValueType().equals(BooleanType.get()) &&
secondOperand.getValueType().equals(BooleanType.get())) {
return booleanCompare(thisObj, firstOperand, secondOperand);
}
if(firstOperand.getValueType().equals(TextType.get()) && secondOperand.getValueType().equals(TextType.get())) {
return textCompare(thisObj, firstOperand, secondOperand);
}
throw new MagmaJsEvaluationRuntimeException(
"Cannot invoke compare() with arguments of type '" + firstOperand.getValueType().getName() + "' and '" +
secondOperand.getValueType().getName() + "'.");
}
throw new MagmaJsEvaluationRuntimeException(
"Cannot invoke compare() with null argument or argument that is not a ScriptableValue.");
}
private static ScriptableValue numericCompare(Scriptable thisObj, ScriptableValue firstOperand,
ScriptableValue secondOperand) {
Value firstOperandValue = firstOperand.getValue();
Value secondOperandValue = secondOperand.getValue();
if(firstOperandValue.isNull() && secondOperandValue.isNull()) {
return new ScriptableValue(thisObj, IntegerType.get().valueOf(0));
}
if(firstOperandValue.isNull()) {
return new ScriptableValue(thisObj, IntegerType.get().valueOf(-1));
}
if(secondOperandValue.isNull()) {
return new ScriptableValue(thisObj, IntegerType.get().valueOf(1));
}
Number firstNumber = (Number) firstOperandValue.getValue();
Number secondNumber = (Number) secondOperandValue.getValue();
if(firstOperand.getValueType().equals(IntegerType.get()) &&
secondOperand.getValueType().equals(IntegerType.get())) {
return new ScriptableValue(thisObj,
IntegerType.get().valueOf(((Long) firstNumber).compareTo((Long) secondNumber)));
}
if(firstOperand.getValueType().equals(IntegerType.get()) &&
secondOperand.getValueType().equals(DecimalType.get())) {
return new ScriptableValue(thisObj,
IntegerType.get().valueOf(Double.compare(firstNumber.doubleValue(), (Double) secondNumber)));
}
if(firstOperand.getValueType().equals(DecimalType.get()) &&
secondOperand.getValueType().equals(IntegerType.get())) {
return new ScriptableValue(thisObj,
IntegerType.get().valueOf(Double.compare((Double) firstNumber, secondNumber.doubleValue())));
}
return new ScriptableValue(thisObj,
IntegerType.get().valueOf(((Double) firstNumber).compareTo((Double) secondNumber)));
}
private static ScriptableValue booleanCompare(Scriptable thisObj, ScriptableValue firstOperand,
ScriptableValue secondOperand) {
Value firstOperandValue = firstOperand.getValue();
Boolean firstBoolean = firstOperandValue.isNull() ? Boolean.FALSE : (Boolean) firstOperandValue.getValue();
Value secondOperandValue = secondOperand.getValue();
Boolean secondBoolean = secondOperandValue.isNull() ? Boolean.FALSE : (Boolean) secondOperandValue.getValue();
return new ScriptableValue(thisObj, IntegerType.get().valueOf(firstBoolean.compareTo(secondBoolean)));
}
private static ScriptableValue textCompare(Scriptable thisObj, ScriptableValue firstOperand,
ScriptableValue secondOperand) {
Value firstOperandValue = firstOperand.getValue();
Value secondOperandValue = secondOperand.getValue();
if(firstOperandValue.isNull() && secondOperandValue.isNull()) {
return new ScriptableValue(thisObj, IntegerType.get().valueOf(0));
}
if(firstOperandValue.isNull()) {
return new ScriptableValue(thisObj, IntegerType.get().valueOf(-1));
}
if(secondOperandValue.isNull()) {
return new ScriptableValue(thisObj, IntegerType.get().valueOf(1));
}
String firstString = (String) firstOperandValue.getValue();
String secondString = (String) secondOperandValue.getValue();
return new ScriptableValue(thisObj, IntegerType.get().valueOf(firstString.compareTo(secondString)));
}
/**
* Returns a new {@link ScriptableValue} of the {@link IntegerType} indicating if the first parameter is greater than,
* equal to, or less than the second parameter. Both parameters must be TextType. Case is ignored. Zero (0) is
* returned if the values are equal. A number greater than zero (1) is returned if the first parameter is greater
* than
* the second. A number less than zero (-1) is returned is the first parameter is less than the second.
* <p/>
* <pre>
* $('TextVarOne').compareNoCase($('TextVarTwo'))
* </pre>
*
* @throws MagmaJsEvaluationRuntimeException if operands are not ScriptableValue Objects of TextType. Also thrown if
* operands are null.
*/
public static ScriptableValue compareNoCase(Context ctx, Scriptable thisObj, Object[] args, @Nullable Function funObj)
throws MagmaJsEvaluationRuntimeException {
ScriptableValue firstOperand = (ScriptableValue) thisObj;
Value firstOperandValue = firstOperand.getValue();
if(firstOperandValue.isNull()) {
throw new MagmaJsEvaluationRuntimeException("Cannot invoke compareNoCase() with null argument.");
}
if(args != null && args.length > 0 && args[0] instanceof ScriptableValue &&
!((ScriptableValue) args[0]).getValue().isNull()) {
ScriptableValue secondOperand = (ScriptableValue) args[0];
if(firstOperand.getValueType().equals(TextType.get()) && secondOperand.getValueType().equals(TextType.get())) {
String firstString = (String) firstOperandValue.getValue();
Value secondOperandValue = secondOperand.getValue();
String secondString = secondOperandValue.isNull() ? null : (String) secondOperandValue.getValue();
return new ScriptableValue(thisObj, IntegerType.get().valueOf(firstString.compareToIgnoreCase(secondString)));
}
throw new MagmaJsEvaluationRuntimeException(
"Cannot invoke compareNoCase() with arguments of type '" + firstOperand.getValueType().getName() +
"' and '" + secondOperand.getValueType().getName() + "'. Use type 'text' only.");
}
throw new MagmaJsEvaluationRuntimeException(
"Cannot invoke compareNoCase() with null argument or argument that is not a ScriptableValue.");
}
}