/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package photoSpreadParser.photoSpreadExpression;
import java.util.Iterator;
import photoSpreadObjects.PhotoSpreadObject;
import photoSpreadParser.photoSpreadExpression.PhotoSpreadSpecialConstants.PhotoSpreadNullConstant;
import photoSpreadUtilities.Const;
import photoSpreadUtilities.TreeSetRandomSubsetIterable;
/**
*
* @author skandel
*/
abstract public class PhotoSpreadCondition extends PhotoSpreadFormulaComponent {
protected String _lhs;
protected String _rhs;
protected ComparisonOperator _compOp;
protected String _comparisionAsString;
// Whether formula explicitly includes
// 'null'. When this var is false, objects
// will be ignored in solving the formula
// if they do not have any value for a metadata
// key that is mentioned in the formula:
protected boolean _nullExplicit = false;
static private String EQUALS = "=";
static private String NOT_EQUALS = "!=";
static private String LESS_THAN = "<";
static private String GREATER_THAN = ">";
static private String LESS_THAN_EQUALS = "<=";
static private String GREATER_THAN_EQUALS = ">=";
/****************************************************
* Constructor(s)
*****************************************************/
public PhotoSpreadCondition(String lhs, String compOp) {
_lhs = lhs;
if (compOp.equals(EQUALS)) {
this._compOp = new EqualsOperator();
} else if (compOp.equals(NOT_EQUALS)) {
this._compOp = new NotEqualsOperator();
} else if (compOp.equals(LESS_THAN)) {
this._compOp = new LessThanOperator();
} else if (compOp.equals(GREATER_THAN)) {
this._compOp = new GreaterThanOperator();
} else if (compOp.equals(LESS_THAN_EQUALS)) {
this._compOp = new LessThanEqualsOperator();
} else if (compOp.equals(GREATER_THAN_EQUALS)) {
this._compOp = new GreaterThanEqualsOperator();
}
this._comparisionAsString = compOp;
}
public PhotoSpreadCondition(String lhs, String compOp, PhotoSpreadNullConstant rhs) {
// Represent the null constant as a string, so that
// all the string comparisons will do the right
// thing. But remember that this formula explicitly
// asked for comparisons to null:
this(lhs, compOp);
_rhs = Const.NULL_VALUE_STRING;
_nullExplicit = true;
}
/****************************************************
* Methods
*****************************************************/
public String getLhs() {
return _lhs;
}
public String toString() {
return "<PhotoSpreadCondition: _lhs=" + _lhs + "; CompOp="
+ _comparisionAsString + ">";
}
public String copyCondition(int rowOffset, int colOffset) {
return toString();
}
/**
* determines whether object satisfies this condition
*
* @param object
* the object being tested for satisfaction
* @return true if object satisfies this condition/false otherwise
*/
abstract public boolean satisfiesCondition(PhotoSpreadObject object);
/**
* determines whether object can be forced into a condition
*
* @param object
* the object being tested
* @return true if object can be forced/false otherwise
*/
public boolean canForceObject(PhotoSpreadObject object) {
return satisfiesCondition(object)
|| (_compOp instanceof EqualsOperator)
|| (_compOp instanceof NotEqualsOperator);
}
/**
* determines forces object into a condition
*
* @param object
* the object being forced
*/
abstract public void forceObject(PhotoSpreadObject object);
/****************************************************
* ComparisonOperator Abstract Class
*****************************************************/
abstract protected class ComparisonOperator {
String _op = Const.NULL_VALUE_STRING;
abstract public boolean satisfiesOperator(int comparision);
abstract public boolean satisfiesOperator(String lhs, String rhs);
abstract public boolean satisfiesOperator(String lhs,
TreeSetRandomSubsetIterable<PhotoSpreadObject> rhs);
public void forceObject(PhotoSpreadObject object, String lhs, String rhs) {
}
public void forceObject(PhotoSpreadObject object, String lhs,
TreeSetRandomSubsetIterable<PhotoSpreadObject> rhs) {
}
protected String adjustCaseSensitivity(String str) {
return str.toLowerCase();
}
public String toString() {
return "<ComparisonOperator '" + _op + "'>";
}
/**
* When a formula does not explicitly mention 'null' then we want all
* objects that are eligible to participate in the formula's solution to
* have values for the metadata keys that are mentioned in the formula.
* If the values for those metadata keys have never been set, then we
* want to exclude those objects. Ex.:
*
* =A1[Age != 10]
*
* This formula would retrieve all objects in A1 that do not have an Age
* metadata. That's not what we likely want. In contrast, we *do* want
* to include such objects in the following case:
*
* =A1[Age=null]
*
* Such a formula would be used, for instance, to find all the objects
* whose Age hasn't been recorded yet.
*
* @param lhs Left hand side of the formula
* @param rhs Right hand side fo the formula
* @return true if an object whose metadata
* produced one of the given values should be ignored.
*/
protected boolean excludeObjFromEval(String lhs, String rhs) {
if (_nullExplicit)
// If formula explicitly mentioned null,
// then all objects need to be included:
return false;
// Null was not mentioned in the formula. So,
// if either of the given values is the special
// null string, we should ignore the object:
if ((lhs.equals(Const.NULL_VALUE_STRING))
|| (rhs.equals(Const.NULL_VALUE_STRING)))
return true;
else
return false;
}
/**
* See comment in excludeObjFromEval(String,String) above.
* @param value The value that is either the special null string, or not.
* @return true if an object whose metadata
* produced one of the given values should be ignored.
*/
protected boolean excludeObjFromEval(String value) {
if (_nullExplicit)
return false;
if (value.equals(Const.NULL_VALUE_STRING))
return true;
return false;
}
}
/****************************************************
* EqualsOperator Extends the Abstract ComparisonOperator
*****************************************************/
protected class EqualsOperator extends ComparisonOperator {
public EqualsOperator() {
_op = "=";
}
public boolean satisfiesOperator(int comparison) {
return (comparison == 0);
}
@Override
public boolean satisfiesOperator(String lhs, String rhs) {
if (excludeObjFromEval(lhs, rhs))
return false;
return adjustCaseSensitivity(lhs)
.equals(adjustCaseSensitivity(rhs));
}
@Override
public void forceObject(PhotoSpreadObject object, String lhs, String rhs) {
object.setMetaData(lhs, rhs);
}
@Override
public void forceObject(PhotoSpreadObject object, String lhs,
TreeSetRandomSubsetIterable<PhotoSpreadObject> rhs) {
if (rhs.size() == 1) {
object.setMetaData(lhs, rhs.first().toString());
}
}
@Override
public boolean satisfiesOperator(String lhs,
TreeSetRandomSubsetIterable<PhotoSpreadObject> rhs) {
Iterator<PhotoSpreadObject> it = rhs.iterator();
while (it.hasNext()) {
PhotoSpreadObject object = it.next();
String objAsString = object.toString();
if (excludeObjFromEval(lhs, objAsString))
return false;
if (adjustCaseSensitivity(lhs).equals(
adjustCaseSensitivity(objAsString))) {
return true;
}
}
return false;
}
}
/****************************************************
* NotEqualsOperator Extends the Abstract ComparisonOperator
*****************************************************/
protected class NotEqualsOperator extends ComparisonOperator {
public NotEqualsOperator() {
_op = "!=";
}
public boolean satisfiesOperator(int comparison) {
return (comparison != 0);
}
@Override
public boolean satisfiesOperator(String lhs, String rhs) {
if (excludeObjFromEval(lhs, rhs))
return false;
return !adjustCaseSensitivity(lhs).equals(
adjustCaseSensitivity(rhs));
}
@Override
public boolean satisfiesOperator(String lhs,
TreeSetRandomSubsetIterable<PhotoSpreadObject> rhs) {
if (excludeObjFromEval(lhs))
return false;
return (!new EqualsOperator().satisfiesOperator(lhs, rhs));
}
}
/****************************************************
* LessThanOperator Extends the Abstract ComparisonOperator
*****************************************************/
protected class LessThanOperator extends ComparisonOperator {
public LessThanOperator() {
_op = "<";
}
public boolean satisfiesOperator(int comparison) {
return (comparison < 0);
}
@Override
public boolean satisfiesOperator(String lhs, String rhs) {
if (excludeObjFromEval(lhs, rhs))
return false;
try {
Double lhsDouble = Double.parseDouble(lhs);
Double rhsDouble = Double.parseDouble(rhs);
return lhsDouble < rhsDouble;
} catch (NumberFormatException e) {
return lhs.compareTo(rhs) < 0;
}
}
@Override
public boolean satisfiesOperator(String lhs,
TreeSetRandomSubsetIterable<PhotoSpreadObject> rhs) {
if (excludeObjFromEval(lhs))
return false;
Iterator<PhotoSpreadObject> it = rhs.iterator();
while (it.hasNext()) {
PhotoSpreadObject object = it.next();
String objAsString = object.toString();
if (satisfiesOperator(lhs, objAsString)) {
return true;
}
}
return false;
}
}
/****************************************************
* GreaterThanOperator Extends the Abstract ComparisonOperator
*****************************************************/
protected class GreaterThanOperator extends ComparisonOperator {
public GreaterThanOperator() {
_op = ">";
}
public boolean satisfiesOperator(int comparison) {
return (comparison > 0);
}
@Override
public boolean satisfiesOperator(String lhs, String rhs) {
if (excludeObjFromEval(lhs, rhs))
return false;
return !(new LessThanOperator().satisfiesOperator(lhs, rhs) || new EqualsOperator()
.satisfiesOperator(lhs, rhs));
}
@Override
public boolean satisfiesOperator(String lhs,
TreeSetRandomSubsetIterable<PhotoSpreadObject> rhs) {
if (excludeObjFromEval(lhs))
return false;
boolean lessOrEqual = (new LessThanOperator().satisfiesOperator(lhs, rhs) || new EqualsOperator()
.satisfiesOperator(lhs, rhs));
return !lessOrEqual;
}
}
/****************************************************
* LessThanEqualsOperator Extends the Abstract ComparisonOperator
*****************************************************/
protected class LessThanEqualsOperator extends ComparisonOperator {
public LessThanEqualsOperator() {
_op = "<=";
}
public boolean satisfiesOperator(int comparison) {
return (comparison <= 0);
}
@Override
public boolean satisfiesOperator(String lhs, String rhs) {
return new LessThanOperator().satisfiesOperator(lhs, rhs)
|| new EqualsOperator().satisfiesOperator(lhs, rhs);
}
@Override
public boolean satisfiesOperator(String lhs,
TreeSetRandomSubsetIterable<PhotoSpreadObject> rhs) {
if (excludeObjFromEval(lhs))
return false;
return new LessThanOperator().satisfiesOperator(lhs, rhs)
|| new EqualsOperator().satisfiesOperator(lhs, rhs);
}
}
/****************************************************
* GreaterThanEqualsOperator Extends the Abstract ComparisonOperator
*****************************************************/
protected class GreaterThanEqualsOperator extends ComparisonOperator {
public GreaterThanEqualsOperator() {
_op = ">=";
}
public boolean satisfiesOperator(int comparison) {
return (comparison >= 0);
}
@Override
public boolean satisfiesOperator(String lhs, String rhs) {
return new GreaterThanOperator().satisfiesOperator(lhs, rhs)
|| new EqualsOperator().satisfiesOperator(lhs, rhs);
}
@Override
public boolean satisfiesOperator(String lhs,
TreeSetRandomSubsetIterable<PhotoSpreadObject> rhs) {
if (excludeObjFromEval(lhs))
return false;
return new LessThanOperator().satisfiesOperator(lhs, rhs)
|| new EqualsOperator().satisfiesOperator(lhs, rhs);
}
}
}