package jadex.rules.rulesystem.rules;
import jadex.commons.SUtil;
import jadex.rules.state.IOAVState;
import jadex.rules.state.OAVObjectType;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
/**
* The operator class contains the implementation of all
* operators for evaluating two values.
*/
public class Operator
{
/**
* Test two objects for equality.
*/
public static class Equal implements IOperator
{
/**
* Evaluate two objects with respect to the
* operator semantics.
* @param state The state.
* @param val1 The first object.
* @param val2 The second object.
* @return True, if objects fit wrt. the operator semantics.
*/
public boolean evaluate(IOAVState state, Object val1, Object val2)
{
val1 = val1 instanceof ILazyValue? ((ILazyValue)val1).getValue(): val1;
val2 = val2 instanceof ILazyValue? ((ILazyValue)val2).getValue(): val2;
return val1 instanceof Number && val2 instanceof Number
? compare(val1,val2)==0
: (val1==null && val2==null) || val1!=null && (val1.getClass().isArray() && val2!=null && val2.getClass().isArray() ? SUtil.arrayEquals(val1, val2) : val1.equals(val2));
}
/**
* Get the string representation.
* @return The string representation.
*/
public String toString()
{
return "==";
}
}
/**
* Test two objects for non-equality.
*/
public static class NotEqual implements IOperator
{
/**
* Evaluate two objects with respect to the
* operator semantics.
* @param state The state.
* @param val1 The first object.
* @param val2 The second object.
* @return True, if objects fit wrt. the operator semantics.
*/
public boolean evaluate(IOAVState state, Object val1, Object val2)
{
val1 = val1 instanceof ILazyValue? ((ILazyValue)val1).getValue(): val1;
val2 = val2 instanceof ILazyValue? ((ILazyValue)val2).getValue(): val2;
return val1 instanceof Number && val2 instanceof Number
? compare(val1,val2)!=0
: (val1==null && val2!=null) || val1!=null && !val1.equals(val2);
}
/**
* Get the string representation.
* @return The string representation.
*/
public String toString()
{
return "!=";
}
}
/**
* Test two objects for less than.
*/
public static class Less implements IOperator
{
/**
* Evaluate two objects with respect to the
* operator semantics.
* @param state The state.
* @param val1 The first object.
* @param val2 The second object.
* @return True, if objects fit wrt. the operator semantics.
*/
public boolean evaluate(IOAVState state, Object val1, Object val2)
{
val1 = val1 instanceof ILazyValue? ((ILazyValue)val1).getValue(): val1;
val2 = val2 instanceof ILazyValue? ((ILazyValue)val2).getValue(): val2;
return val1!=null && val2!=null && compare(val1, val2)<0;
}
/**
* Get the string representation.
* @return The string representation.
*/
public String toString()
{
return "<";
}
}
/**
* Test two objects for less or equal.
*/
public static class LessOrEqual implements IOperator
{
/**
* Evaluate two objects with respect to the
* operator semantics.
* @param state The state.
* @param val1 The first object.
* @param val2 The second object.
* @return True, if objects fit wrt. the operator semantics.
*/
public boolean evaluate(IOAVState state, Object val1, Object val2)
{
val1 = val1 instanceof ILazyValue? ((ILazyValue)val1).getValue(): val1;
val2 = val2 instanceof ILazyValue? ((ILazyValue)val2).getValue(): val2;
return val1!=null && val2!=null && compare(val1, val2)<=0;
}
/**
* Get the string representation.
* @return The string representation.
*/
public String toString()
{
return "<=";
}
}
/**
* Test two objects for greater than.
*/
public static class Greater implements IOperator
{
/**
* Evaluate two objects with respect to the
* operator semantics.
* @param state The state.
* @param val1 The first object.
* @param val2 The second object.
* @return True, if objects fit wrt. the operator semantics.
*/
public boolean evaluate(IOAVState state, Object val1, Object val2)
{
val1 = val1 instanceof ILazyValue? ((ILazyValue)val1).getValue(): val1;
val2 = val2 instanceof ILazyValue? ((ILazyValue)val2).getValue(): val2;
return val1!=null && val2!=null && compare(val1, val2)>0;
}
/**
* Get the string representation.
* @return The string representation.
*/
public String toString()
{
return ">";
}
}
/**
* Test two objects for greater or equal.
*/
public static class GreaterOrEqual implements IOperator
{
/**
* Evaluate two objects with respect to the
* operator semantics.
* @param state The state.
* @param val1 The first object.
* @param val2 The second object.
* @return True, if objects fit wrt. the operator semantics.
*/
public boolean evaluate(IOAVState state, Object val1, Object val2)
{
val1 = val1 instanceof ILazyValue? ((ILazyValue)val1).getValue(): val1;
val2 = val2 instanceof ILazyValue? ((ILazyValue)val2).getValue(): val2;
return val1!=null && val2!=null && compare(val1, val2)>=0;
}
/**
* Get the string representation.
* @return The string representation.
*/
public String toString()
{
return ">=";
}
}
/**
* Requires strings as both parameters.
* Test two strings for matches.
*/
public static class Matches implements IOperator
{
/**
* Evaluate two objects with respect to the
* operator semantics.
* @param state The state.
* @param val1 The first object.
* @param val2 The second object.
* @return True, if objects fit wrt. the operator semantics.
*/
public boolean evaluate(IOAVState state, Object val1, Object val2)
{
val1 = val1 instanceof ILazyValue? ((ILazyValue)val1).getValue(): val1;
val2 = val2 instanceof ILazyValue? ((ILazyValue)val2).getValue(): val2;
if(!(val1 instanceof String))
throw new IllegalArgumentException("Matches operator only applies for strings: +"+val1);
if(!(val2 instanceof String))
throw new IllegalArgumentException("Matches operator only applies for strings: +"+val2);
// val1 is the value to test
// val2 should be the pattern
return ((String)val1).matches((String)val2);
}
/**
* Get the string representation.
* @return The string representation.
*/
public String toString()
{
return "matches";
}
}
/**
* Requires strings as both parameters.
* Test two strings for matches.
*/
public static class StartsWith implements IOperator
{
/**
* Evaluate two objects with respect to the
* operator semantics.
* @param state The state.
* @param val1 The first object.
* @param val2 The second object.
* @return True, if objects fit wrt. the operator semantics.
*/
public boolean evaluate(IOAVState state, Object val1, Object val2)
{
val1 = val1 instanceof ILazyValue? ((ILazyValue)val1).getValue(): val1;
val2 = val2 instanceof ILazyValue? ((ILazyValue)val2).getValue(): val2;
if(!(val1 instanceof String))
throw new IllegalArgumentException("Matches operator only applies for strings: +"+val1);
if(!(val2 instanceof String))
throw new IllegalArgumentException("Matches operator only applies for strings: +"+val2);
// val1 is the value to test
// val2 should be the pattern
return ((String)val1).startsWith((String)val2);
}
/**
* Get the string representation.
* @return The string representation.
*/
public String toString()
{
return "startsWith";
}
}
/**
* Test if an object is contained in a collection.
*/
public static class Contains implements IOperator
{
/**
* Evaluate two objects with respect to the
* operator semantics.
* @param state The state.
* @param val1 The first object.
* @param val2 The second object.
* @return True, if objects fit wrt. the operator semantics.
*/
public boolean evaluate(IOAVState state, Object val1, Object val2)
{
val1 = val1 instanceof ILazyValue? ((ILazyValue)val1).getValue(): val1;
val2 = val2 instanceof ILazyValue? ((ILazyValue)val2).getValue(): val2;
return contains(val1, val2);
}
/**
* Get the string representation.
* @return The string representation.
*/
public String toString()
{
return "contains";
}
}
/**
* Test if an object is excluded from a collection.
*/
public static class Excludes implements IOperator
{
/**
* Evaluate two objects with respect to the
* operator semantics.
* @param state The state.
* @param val1 The first object.
* @param val2 The second object.
* @return True, if objects fit wrt. the operator semantics.
*/
public boolean evaluate(IOAVState state, Object val1, Object val2)
{
val1 = val1 instanceof ILazyValue? ((ILazyValue)val1).getValue(): val1;
val2 = val2 instanceof ILazyValue? ((ILazyValue)val2).getValue(): val2;
return !contains(val1, val2);
}
/**
* Get the string representation.
* @return The string representation.
*/
public String toString()
{
return "excludes";
}
}
/**
* Test if an object is instanceof a class.
*/
public static class InstanceOf implements IOperator
{
/**
* Evaluate two objects with respect to the
* operator semantics.
* @param state The state.
* @param val1 The first object.
* @param val2 The second object.
* @return True, if objects fit wrt. the operator semantics.
*/
public boolean evaluate(IOAVState state, Object val1, Object val2)
{
val1 = val1 instanceof ILazyValue? ((ILazyValue)val1).getValue(): val1;
val2 = val2 instanceof ILazyValue? ((ILazyValue)val2).getValue(): val2;
boolean ret;
if(val2 instanceof Class)
{
ret = ((Class)val2).isAssignableFrom(val2 instanceof Class? (Class)val2: val2.getClass());
}
else //if(val2 instanceof OAVObjectType)
{
ret = val1 instanceof OAVObjectType? ((OAVObjectType)val1).isSubtype((OAVObjectType)val2)
:state.getType(val1).isSubtype((OAVObjectType)val2);
}
return ret;
}
/**
* Get the string representation.
* @return The string representation.
*/
public String toString()
{
return "instanceof";
}
}
/**
* Compare two values.
* @param val1 The first value.
* @param val2 The second value.
* @return A negative integer, zero, or a positive integer as the
* first value is less than, equal to, or greater than the second value.
* @throws ClassCastException when the values are not comparable.
*/
protected static int compare(Object val1, Object val2)
{
val1 = val1 instanceof ILazyValue? ((ILazyValue)val1).getValue(): val1;
val2 = val2 instanceof ILazyValue? ((ILazyValue)val2).getValue(): val2;
// Should support some external comparators???
// Check for null values.
if(val1==null || val2==null)
{
throw new NullPointerException("Cannot compare null "+val1+" "+val2);
}
// Compare numbers.
// Number.compareTo() works only for number objects of same type, grrr...
else if(val1 instanceof Number && val2 instanceof Number)
{
Number numval1 = (Number)val1;
Number numval2 = (Number)val2;
if(numval1 instanceof Double || numval2 instanceof Double
|| numval1 instanceof Float || numval2 instanceof Float)
{
double cmp = numval1.doubleValue() - numval2.doubleValue();
return cmp>0 ? 1 : (cmp<0 ? -1 : 0);
}
else if(numval1 instanceof Long || numval2 instanceof Long)
{
return (int)(numval1.longValue() - numval2.longValue());
}
else
{
return numval1.intValue() - numval2.intValue();
}
}
// Use Comparable interface.
else
{
return ((Comparable)val1).compareTo(val2);
}
}
/**
* Test if a collection contains a value.
* @param val1 The collection.
* @param val2 The value to test.
* @return True, if contained.
*/
protected static boolean contains(Object val1, Object val2)
{
val1 = val1 instanceof ILazyValue? ((ILazyValue)val1).getValue(): val1;
val2 = val2 instanceof ILazyValue? ((ILazyValue)val2).getValue(): val2;
if(val1==null)
return false;
boolean ret = false;
// val1 should be the collection,
// val2 is the value to test
if(val1.getClass().isArray())
{
Object[] array = (Object[])val1;
for(int i=0; !ret && i<array.length; i++)
{
Object totest = array[i];
ret = (totest==null && val2==null) || totest!=null && totest.equals(val2);
}
}
else if(val1 instanceof Collection)
{
ret = ((Collection)val1).contains(val2);
}
else if(val1 instanceof Enumeration)
{
for(Enumeration e =(Enumeration)val1; !ret && e.hasMoreElements();)
{
Object totest = e.nextElement();
ret = (totest==null && val2==null) || totest!=null && totest.equals(val2);
}
}
else if(val1 instanceof Iterator)
{
for(Iterator it =(Iterator)val1; !ret && it.hasNext();)
{
Object totest = it.next();
ret = (totest==null && val2==null) || totest!=null && totest.equals(val2);
}
}
else
{
throw new IllegalArgumentException("First value is no collection "+val1+" "+val2);
}
return ret;
}
}