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