/*****************************************************************************************
 * Copyright © 2006 VHA. All rights reserved
 ****************************************************************************************/
package gov.va.med.esr.common.model.report;

// Java classes
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
// Library classes
import org.apache.commons.lang.Validate;
import org.apache.commons.lang.builder.ToStringBuilder;
// Framework classes
import gov.va.med.fw.model.AbstractEntity;
import gov.va.med.fw.model.AbstractKeyedEntity;
import gov.va.med.fw.model.EntityKey;
// EDB Classes
import gov.va.med.esr.common.model.lookup.DayOfMonth;
import gov.va.med.esr.common.model.lookup.DayOfQuarter;
import gov.va.med.esr.common.model.lookup.DayOfWeek;
import gov.va.med.esr.common.model.lookup.Month;
import gov.va.med.esr.common.model.lookup.ReportRunFrequency;
import gov.va.med.esr.common.model.lookup.ReportScheduleType;
import gov.va.med.esr.common.model.lookup.WeekOfMonth;


/**
 * @author Yi He
 * @version 1.0 Scheduling information for a report
 */
public class ReportSchedule extends AbstractEntity {

   /**
    * An instance of serialVersionUID
    */
   private static final long serialVersionUID = -3780350573837478688L;

   public ReportRunFrequency getRunFrequency() {
      return this.runFrequency;
   }

   public void setRunFrequency(ReportRunFrequency runFrequency) {
      this.runFrequency = runFrequency;
   }

   public ReportScheduleType getScheduleType() {
      return this.scheduleType;
   }

   public void setScheduleType(ReportScheduleType scheduleType) {
      this.scheduleType = scheduleType;
   }

   public DayOfMonth getDayOfMonth() {
      return this.dayOfMonth;
   }

   public void setDayOfMonth(DayOfMonth dayOfMonth) {
      this.dayOfMonth = dayOfMonth;
   }

   public WeekOfMonth getWeekOfMonth() {
      return this.weekOfMonth;
   }

   public void setWeekOfMonth(WeekOfMonth weekOfMonth) {
      this.weekOfMonth = weekOfMonth;
   }

   public DayOfWeek getDayOfWeek() {
      return this.dayOfWeek;
   }

   public void setDayOfWeek(DayOfWeek dayOfWeek) {
      this.dayOfWeek = dayOfWeek;
   }

   public DayOfQuarter getDayOfQuarter() {
      return this.dayOfQuarter;
   }

   public void setDayOfQuarter(DayOfQuarter dayOfQuarter) {
      this.dayOfQuarter = dayOfQuarter;
   }

   public Month getMonth() {
      return this.month;
   }

   public void setMonth(Month month) {
      this.month = month;
   }

   public Integer getNumericDayOfMonth() {
      return this.numericDayOfMonth;
   }

   public void setNumericDayOfMonth(Integer numericDayOfMonth) {
      this.numericDayOfMonth = numericDayOfMonth;
   }

   public Date getDateToGenerate() {
      return dateToGenerate;
   }

   public void setDateToGenerate(Date dateToGenerate) {
      this.dateToGenerate = dateToGenerate;
   }

   public Integer getHour() {
      return this.hour;
   }

   public void setHour(Integer hour) {
      this.hour = hour;
   }

   public Integer getMinute() {
      return this.minute;
   }

   public void setMinute(Integer minute) {
      this.minute = minute;
   }

   /**
    * @return A collection of ReportMessageType object
    */
   public Set getDaysOfWeek() {
      return Collections.unmodifiableSet(getInternalDaysOfWeek());
   }

   public ReportDayOfWeek getDayOfWeekByEntityKey(EntityKey identifier) {
      return (ReportDayOfWeek)AbstractKeyedEntity.getEntityByEntityKey(getDaysOfWeek(),
            identifier);
   }

   public ReportDayOfWeek removeDayOfWeekByEntityKey(EntityKey identifier) {
      return (ReportDayOfWeek)AbstractKeyedEntity.removeEntityByEntityKey(
            getInternalDaysOfWeek(), identifier);
   }

   /**
    * Getter - for hibernate use only.
    * 
    * @return
    */
   private Set getInternalDaysOfWeek() {
      if( this.internalDaysOfWeek == null ) {
         this.internalDaysOfWeek = new HashSet();
      }
      return this.internalDaysOfWeek;
   }

   /**
    * Setter - for hibernate use only.
    * 
    * @param dayOfWeeks
    */
   private void setInternalDaysOfWeek(Set dayOfWeeks) {
      this.internalDaysOfWeek = dayOfWeeks;
   }

   /**
    * Add a ReportDayOfWeek for this report setup. This method takes care of Bidirectional
    * setting of ReportDayOfWeek's report setup.
    * 
    * @param dayOfWeek
    */
   public void addDayOfWeek(ReportDayOfWeek dayOfWeek) {
      Validate.notNull(dayOfWeek, "Null dayOfWeek specified.");
      dayOfWeek.setReportSetup(reportSetup);
      getInternalDaysOfWeek().add(dayOfWeek);
   }

   /**
    * Add a collection of DaysOfWeek to this report setup. This method takes care of
    * Bidirectional setting of ReportDayOfWeek's report setup.
    * 
    * @param dayOfWeeks
    */
   public void addAllDaysOfWeek(Set dayOfWeeks) {
      Validate.notNull(dayOfWeeks, "Null set of dayOfWeeks specified.");
      this.setParameterOwner(dayOfWeeks);
      Set internal = this.getInternalDaysOfWeek();
      internal.addAll(dayOfWeeks);
   }

   /**
    * Remove an ReportDayOfWeek for this report setup. This method takes care of
    * Bidirectional setting of ReportDayOfWeek's report setup.
    * 
    * @param dayOfWeek
    */
   public void removeDayOfWeek(ReportDayOfWeek dayOfWeek) {
      Validate.notNull(dayOfWeek, "Null dayOfWeek specified.");
      getInternalDaysOfWeek().remove(dayOfWeek);
      dayOfWeek.setReportSetup(null);
   }

   public void removeAllDaysOfWeek() {
      this.getInternalDaysOfWeek().clear();
   }

   public ReportSetup getReportSetup() {
      return this.reportSetup;
   }

   public void setReportSetup(ReportSetup reportSetup) {
      this.reportSetup = reportSetup;
   }

   protected void buildToString(ToStringBuilder builder) {
      // TODO Auto-generated method stub
   }

   /**
    * @param p
    *           A collection of ReportParameter
    */
   private void setParameterOwner(Collection p) {
      Iterator iter = p.iterator();
      while( iter.hasNext() ) {
         ( (ReportParameter)iter.next() ).setReportSetup(reportSetup);
      }
   }

   private ReportSetup reportSetup;

   private ReportRunFrequency runFrequency;

   private ReportScheduleType scheduleType;

   private DayOfMonth dayOfMonth;

   private WeekOfMonth weekOfMonth;

   private DayOfWeek dayOfWeek;

   private DayOfQuarter dayOfQuarter;

   private Month month;

   private Integer numericDayOfMonth;

   private Date dateToGenerate;

   private Integer hour;

   private Integer minute;

   private Set internalDaysOfWeek;

   protected void finalize() throws Throwable {
      super.finalize();
      setInternalDaysOfWeek( null );
   }
}
