package hirondelle.fish.main.search;
import java.util.regex.Pattern;
import hirondelle.web4j.model.Check;
import hirondelle.web4j.model.ModelCtorException;
import hirondelle.web4j.util.Util;
import hirondelle.web4j.model.ModelUtil;
import static hirondelle.web4j.util.Consts.FAILS;
import hirondelle.web4j.security.SafeText;
import hirondelle.web4j.model.Decimal;
import static hirondelle.web4j.model.Decimal.ZERO;;
public final class RestoSearchCriteria {
enum SortColumn {Name, Price};
public RestoSearchCriteria(
SafeText aStartsWith, Decimal aMinPrice, Decimal aMaxPrice,
SafeText aOrderBy, Boolean aIsReverseOrder
) throws ModelCtorException {
fStartsWith = aStartsWith;
fMinPrice = aMinPrice;
fMaxPrice = aMaxPrice;
fOrderBy = aOrderBy == null ? null : SortColumn.valueOf(aOrderBy.getRawString());
fIsReverseOrder = Util.nullMeansFalse(aIsReverseOrder);
validateState();
}
static final String WILDCARD = "%";
static final int MAX_LENGTH = 20;
SafeText getStartsWith() {
return Util.textHasContent(fStartsWith) ? SafeText.from(fStartsWith + WILDCARD) : null;
}
Decimal getMinPrice() { return fMinPrice; }
Decimal getMaxPrice() { return fMaxPrice; }
SortColumn getOrderBy() { return fOrderBy; }
Boolean isReverseOrder() { return fIsReverseOrder; }
@Override public String toString() {
return ModelUtil.toStringFor(this);
}
@Override public boolean equals(Object aThat){
Boolean result = ModelUtil.quickEquals(this, aThat);
if ( result == null ){
RestoSearchCriteria that = (RestoSearchCriteria) aThat;
result = ModelUtil.equalsFor(this.getSignificantFields(), that.getSignificantFields());
}
return result;
}
@Override public int hashCode(){
return ModelUtil.hashCodeFor(getSignificantFields());
}
private final SafeText fStartsWith;
private final Decimal fMinPrice;
private final Decimal fMaxPrice;
private final SortColumn fOrderBy;
private final Boolean fIsReverseOrder;
private static final Decimal HUNDRED = Decimal.from("100.00");
private static final Pattern NO_WILDCARD = Pattern.compile(".*[^" + WILDCARD + "]$");
private void validateState() throws ModelCtorException {
ModelCtorException ex = new ModelCtorException();
if( FAILS == Check.optional(fStartsWith, Check.max(MAX_LENGTH)) ) {
ex.add("Please enter a shorter Restaurant Name.");
}
if( FAILS == Check.optional(fStartsWith, Check.pattern(NO_WILDCARD)) ){
ex.add("Restaurant name (_1_) cannot have this character at the end : _2_", fStartsWith, Util.quote(WILDCARD));
}
if( FAILS == Check.optional(fMinPrice, Check.range(ZERO,HUNDRED), Check.numDecimalsAlways(2)) ){
ex.add("Minimum Price (_1_) must be in the range 0.00 to 100.00, 2 decimals", fMinPrice.toString());
}
if( FAILS == Check.optional(fMaxPrice, Check.range(ZERO,HUNDRED), Check.numDecimalsAlways(2)) ){
ex.add("Maximum Price (_1_) must be in the range 0.00 to 100.00, 2 decimals", fMaxPrice.toString() );
}
if ( fMaxPrice != null || fMinPrice != null ){
if( fMaxPrice == null || fMinPrice == null ){
ex.add("When specifying price, please specify both minimum and maximum.");
}
}
if( fMaxPrice != null && fMinPrice != null ){
if ( fMinPrice.gt(fMaxPrice) ){
ex.add("Minimum price cannot be greater than maximum price.");
}
}
if ( ! Util.textHasContent(fStartsWith) && fMinPrice == null && fMaxPrice == null ) {
ex.add("Please enter criteria on name and/or price.");
}
if ( ex.isNotEmpty() ) throw ex;
}
private Object[] getSignificantFields(){
return new Object[] {fStartsWith, fMinPrice, fMaxPrice, fOrderBy, fIsReverseOrder};
}
}