package com.pr0gramm.statistics.predicate;
import com.pr0gramm.statistics.helper.DecimalHelper;
import com.pr0gramm.statistics.helper.ReflectionHelper;
import com.pr0gramm.statistics.toolbox.OperatorType;
import java.lang.reflect.Field;
import java.math.BigDecimal;
/**
* A predicate which combines two verbs with an operator.
* <p>
* Created by koray on 29/01/2017.
*/
public class OperatorPredicate<T> implements ParsablePredicate<T> {
private Class<T> type;
private boolean predicateParsed = false;
private String fieldName;
private OperatorType operatorType;
private String value;
public OperatorPredicate(Class<T> type) {
this.type = type;
}
@Override
public void parsePredicate(String[] verbs) throws UnsupportedOperationException, NoSuchFieldException {
if (predicateParsed) {
throw new UnsupportedOperationException("This predicate was already parsed!");
}
if (verbs.length != 3) {
throw new UnsupportedOperationException("The verbs have an invalid format!");
}
fieldName = verbs[0];
operatorType = OperatorType.fromString(verbs[1]);
value = verbs[2];
if (operatorType == null) {
throw new UnsupportedOperationException("The operator " + verbs[1]
+ " is not supported. Please use one of the following: ==, !=, >, <, >=, <=");
}
getField(fieldName);
predicateParsed = true;
}
@Override
public boolean satisfiesPredicate(T obj) throws UnsupportedOperationException {
if (!predicateParsed) {
throw new UnsupportedOperationException("parsePredicate must be called before calling satisfiesPredicate!");
}
Object actualValue;
try {
actualValue = ReflectionHelper.getObject(fieldName, obj, type);
} catch (NoSuchFieldException | IllegalAccessException e) {
// This will never happen because we are setting the field to accessible above...
throw new RuntimeException("This should not happen. Something went totally wrong.");
}
if (actualValue == null) {
// If actualValue is null we can't compare it so it doesn't satisfy the predicate.
return false;
}
switch (operatorType) {
case EQUAL:
return actualValue.toString().equals(value);
case NOT_EQUAL:
return !actualValue.toString().equals(value);
case GREATER:
if (DecimalHelper.isDecimal(actualValue.toString()) && DecimalHelper.isDecimal(value)) {
return (new BigDecimal(actualValue.toString())).compareTo(new BigDecimal(value)) > 0;
}
return actualValue.toString().compareTo(value) > 0;
case LESS:
if (DecimalHelper.isDecimal(actualValue.toString()) && DecimalHelper.isDecimal(value)) {
return (new BigDecimal(actualValue.toString())).compareTo(new BigDecimal(value)) < 0;
}
return actualValue.toString().compareTo(value) < 0;
case GREATER_OR_EQUAL:
if (DecimalHelper.isDecimal(actualValue.toString()) && DecimalHelper.isDecimal(value)) {
return (new BigDecimal(actualValue.toString())).compareTo(new BigDecimal(value)) >= 0;
}
return actualValue.toString().compareTo(value) >= 0;
case LESS_OR_EQUAL:
if (DecimalHelper.isDecimal(actualValue.toString()) && DecimalHelper.isDecimal(value)) {
return (new BigDecimal(actualValue.toString())).compareTo(new BigDecimal(value)) <= 0;
}
return actualValue.toString().compareTo(value) <= 0;
}
return false;
}
@Override
public String toString() {
return fieldName + " " + operatorType.toString() + " " + value;
}
private Field getField(String name) throws NoSuchFieldException {
if (name.contains(".")) {
String[] splittedFields = name.split("\\.");
Field f = null;
for (String s : splittedFields) {
if (f == null) {
f = type.getDeclaredField(s);
} else {
f = f.getType().getDeclaredField(s);
}
}
return f;
} else {
return type.getDeclaredField(name);
}
}
}