001    package org.hackystat.projectbrowser.page.validator;
002    
003    import java.util.Date;
004    import java.util.List;
005    
006    import javax.xml.datatype.XMLGregorianCalendar;
007    
008    import org.apache.wicket.markup.html.form.Form;
009    import org.apache.wicket.markup.html.form.FormComponent;
010    import org.apache.wicket.markup.html.form.ListMultipleChoice;
011    import org.apache.wicket.markup.html.form.validation.AbstractFormValidator;
012    import org.apache.wicket.extensions.markup.html.form.DateTextField;
013    import org.hackystat.sensorbase.resource.projects.ProjectUtils;
014    import org.hackystat.sensorbase.resource.projects.jaxb.Project;
015    import org.hackystat.utilities.tstamp.Tstamp;
016    
017    /**
018     * Provides a project date validator. This validator will work with forms that have 
019     * a multiple selection menu for Projects, plus either one or two date fields.
020     * It provides two constructors: one for forms with a Project menu and one date, 
021     * and one for forms with a Project menu and two dates.  
022     * @author Philip Johnson
023     */
024    public class ProjectDateValidator extends AbstractFormValidator {
025    
026      /** For serialization. */
027      private static final long serialVersionUID = 1L;
028    
029      /** 
030       * Form components to be checked. The first must be the projectMenu (a ListMultipleChoice),
031       * the second must be a date (a DateTextField), and the third (if present) is another
032       * DateTextField.  This enables the validator to be used with either forms with a single date
033       * (such as DPDs) as well as forms with a start and end date (such as Telmetry). 
034       */
035      private final FormComponent[] components;
036    
037      /**
038       * Takes a Project menu and a single Date field.
039       * @param projectMenu The project menu component. 
040       * @param dateField The Date field component.
041       */
042      public ProjectDateValidator(FormComponent projectMenu, FormComponent dateField) {
043        if (projectMenu == null) {
044          throw new IllegalArgumentException("projectMenu cannot be null");
045        }
046        if (dateField == null) {
047          throw new IllegalArgumentException("dateField cannot be null");
048        }
049        if (!(projectMenu instanceof ListMultipleChoice)) {
050          throw new IllegalArgumentException("ProjectDateValidator not given a ListMultipleChoice");
051        }
052        if (!(dateField instanceof DateTextField)) {
053          throw new IllegalArgumentException("ProjectDateValidator not given a DateTextField");
054        }
055        components = new FormComponent[] { projectMenu, dateField };
056      }
057      
058      /**
059       * Takes a Project menu (ListMultipleChoice) and two Date fields (DateTextField).
060       * @param projectMenu The project menu component. 
061       * @param startDateField The Date field component.
062       * @param endDateField The Date field component.
063       */
064      public ProjectDateValidator(FormComponent projectMenu, FormComponent startDateField, 
065          FormComponent endDateField) {
066        if (projectMenu == null) {
067          throw new IllegalArgumentException("projectMenu cannot be null");
068        }
069        if (startDateField == null) {
070          throw new IllegalArgumentException("startDateField cannot be null");
071        }
072        if (!(projectMenu instanceof ListMultipleChoice)) {
073          throw new IllegalArgumentException("ProjectDateValidator not given a ListMultipleChoice");
074        }
075        if (!(startDateField instanceof DateTextField)) {
076          throw new IllegalArgumentException("ProjectDateValidator not given a DateTextField");
077        }
078        if (!(endDateField instanceof DateTextField)) {
079          throw new IllegalArgumentException("ProjectDateValidator not given a DateTextField");
080        }
081        components = new FormComponent[] { projectMenu, startDateField, endDateField };
082      }
083    
084      /**
085       * Returns the form components.
086       * @return The form components. 
087       */
088      public FormComponent[] getDependentFormComponents() {
089        return components.clone();
090      }
091    
092      /**
093       * Performs the validation. 
094       * Note that this validation must handle a projectMenu plus a single date, or a 
095       * projectMenu plus two dates (start and end date). 
096       * This method is ran if all components returned by getDependentFormComponents() are valid.
097       * @param projectDateForm The form to validate. 
098       */
099      @SuppressWarnings("unchecked")
100      public void validate(Form projectDateForm) {
101        ListMultipleChoice projectMenu = (ListMultipleChoice)components[0]; 
102        DateTextField startDateField = (DateTextField)components[1];
103        DateTextField endDateField = null;
104        if (components.length == 3) {
105          endDateField = (DateTextField)components[2];
106        }
107        List<Project> projects = (List<Project>)projectMenu.getConvertedInput();
108        Date date1 = (Date)startDateField.getConvertedInput();
109        XMLGregorianCalendar tomorrow = Tstamp.incrementDays(Tstamp.makeTimestamp(), 1);
110        Date date2 = null;
111        if (endDateField != null) {
112          date2 = (Date)endDateField.getConvertedInput();
113        }
114        
115        for (Project project : projects) {
116          XMLGregorianCalendar startTime = Tstamp.makeTimestamp(date1.getTime());
117          if (!ProjectUtils.isValidStartTime(project, startTime)) { //NOPMD
118            error(startDateField, "DateBeforeProjectStartTime");
119          }
120          else if (!ProjectUtils.isValidEndTime(project, startTime)) { //NOPMD
121            error(startDateField, "DateAfterProjectEndTime");
122          }
123          else if (Tstamp.greaterThan(startTime, tomorrow)) {
124            error(startDateField, "DateInFuture");
125          }
126          // Only check the end date if this form actually contained an end date. 
127          if (date2 != null) { 
128            XMLGregorianCalendar endTime = Tstamp.makeTimestamp(date2.getTime());
129            if (!ProjectUtils.isValidStartTime(project, endTime)) { //NOPMD
130              error(endDateField, "DateBeforeProjectStartTime");
131            }
132            else if (!ProjectUtils.isValidEndTime(project, endTime)) { //NOPMD
133              error(endDateField, "DateAfterProjectEndTime");
134            }
135            else if (Tstamp.greaterThan(endTime, tomorrow)) {
136              error(endDateField, "DateInFuture");
137            }
138          }
139        }
140      }
141    }