package hirondelle.predict.pub.search;
import static hirondelle.web4j.util.Consts.FAILS;
import hirondelle.web4j.model.Check;
import hirondelle.web4j.model.ModelCtorException;
import hirondelle.web4j.model.ModelUtil;
import hirondelle.web4j.model.DateTime;
import hirondelle.web4j.security.SafeText;
import hirondelle.predict.main.prediction.Prediction;
/**
Model object for user input of search criteria.
<P>In this case, the <i>getXXX</i> methods are package-private.
<P>The user enters dates only, without times. The underlying data, the creation date-time of the
{@link Prediction}, carries both date and time. To account for this, the {@link #getFromDate()}
and {@link #getToDate()} methods return {@link DateTime} objects that are coerced to specific times
of day, using {@link DateTime#getStartOfDay()} and {@link DateTime#getEndOfDay()}, respectively.
*/
public final class SearchCriteria {
/**
Full constructor.
<P>The dates can occur in any combination.
If both the From-Date and To-Date are present, however,
then the From-Date can never come after the To-Date.
<P>No checks are made for 'future dates'.
@param aSearchText number of characters in range 2..255 (required)
@param aSearchStyle required
@param aFromDate minimum creation date, must never be after <tt>aToDate</tt> (optional)
@param aToDate maximum creation date (optional)
*/
public SearchCriteria(SafeText aSearchText, SafeText aSearchStyle, DateTime aFromDate, DateTime aToDate) throws ModelCtorException {
fSearchText = aSearchText;
fFromDate = aFromDate;
fToDate = aToDate;
fSearchStyle = SearchStyle.valueOf(aSearchStyle.getRawString());
validateState();
}
SafeText getSearchText() {
return fSearchText;
}
/** The date passed to the constructor, if any, but with time coerced to the start of the day. */
DateTime getFromDate(){
return fFromDate != null? fFromDate.getStartOfDay() : null;
}
/** The date passed to the constructor, if any, but with time coerced to the end of the day. */
DateTime getToDate(){
return fToDate!= null ? fToDate.getEndOfDay() : null;
}
SearchStyle getSearchStyle(){ return fSearchStyle; }
/** Intended for debugging only. */
@Override public String toString(){
return ModelUtil.toStringFor(this);
}
@Override public boolean equals(Object aThat){
Boolean result = ModelUtil.quickEquals(this, aThat);
if ( result == null ) {
SearchCriteria that = (SearchCriteria)aThat;
result = ModelUtil.equalsFor(this.getSignificantFields(), that.getSignificantFields());
}
return result;
}
@Override public int hashCode(){
if ( fHashCode == 0 ) {
fHashCode = ModelUtil.hashCodeFor(getSignificantFields());
}
return fHashCode;
}
// PRIVATE
private SafeText fSearchText;
private DateTime fFromDate;
private DateTime fToDate;
private SearchStyle fSearchStyle;
private int fHashCode;
private Object[] getSignificantFields(){
return new Object[] {fSearchText, fFromDate, fToDate, fSearchStyle};
}
private void validateState() throws ModelCtorException {
ModelCtorException ex = new ModelCtorException();
if ( FAILS == Check.required(fSearchText, Check.range(2, 255)) ) {
ex.add("Please input between 2 and 255 characters.");
}
if(FAILS == Check.required(fSearchStyle)){
ex.add("Please check off the style of search.");
}
if( fFromDate != null && fToDate != null ){
if(fFromDate.gt(fToDate)){
ex.add("The From Date cannot come after the To Date");
}
}
if ( ! ex.isEmpty() ) throw ex;
}
}