/************************************************************************************ * * Copyright (c) 2003, 2004, 2005, 2006 The Sakai Foundation. * @author mustansar@rice.edu * Licensed under the Educational Community License, Version 1.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.opensource.org/licenses/ecl1.php * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * **********************************************************************************/ package org.sakaiproject.calendar.impl; import java.util.GregorianCalendar; import java.util.Stack; import java.util.TimeZone; import java.util.Vector; import java.util.List; import org.sakaiproject.time.api.Time; import org.sakaiproject.time.api.TimeRange; import org.sakaiproject.time.cover.TimeService; import org.sakaiproject.time.api.TimeBreakdown; import org.w3c.dom.Document; import org.w3c.dom.Element; /** * <p> TTh RecurrenceRule is a time range generating rule that is based on a weekly recurrence. repeating Tuesdays and Thursdays</p> * <p>The recurrences happen on the same day-of-week, at the same time as the prototype.</p> * <p>TODO: support changing the day-of-week of recurrences Mustansar</p> */ public class TThRecurrenceRule extends RecurrenceRuleBase { /** The unique type / short frequency description. */ protected final static String FREQ = "TTh"; /** * Construct. */ public TThRecurrenceRule() { super(); } // TThRecurrenceRule /** * Construct with no limits. * @param interval Every this many number of weeks: 1 would be weekly. */ public TThRecurrenceRule(int interval) { super(interval); } // TThRecurrenceRule /** * Construct with count limit. * @param interval Every this many number of weeks: 1 would be weekly. * @param count For this many occurrences - if 0, does not limit. */ public TThRecurrenceRule(int interval, int count) { super(interval, count); } // TThRecurrenceRule /** * Construct with time limit. * @param interval Every this many number of weeks: 1 would be weekly. * @param until No time ranges past this time are generated - if null, does not limit. */ public TThRecurrenceRule(int interval, Time until) { super(interval, until); } // TThRecurrenceRule /** * Serialize the resource into XML, adding an element to the doc under the top of the stack element. * @param doc The DOM doc to contain the XML (or null for a string return). * @param stack The DOM elements, the top of which is the containing element of the new "resource" element. * @return The newly added element. */ public Element toXml(Document doc, Stack stack) { // add the "rule" element to the stack'ed element Element rule = doc.createElement("rule"); ((Element)stack.peek()).appendChild(rule); // set the class name - old style for CHEF 1.2.10 compatibility rule.setAttribute("class", "org.chefproject.osid.calendar.TThRecurrenceRule"); // set the rule class name w/o package, for modern usage rule.setAttribute("name", "TThRecurrenceRule"); // Do the base class part. setBaseClassXML(rule); return rule; } // toXml /* (non-Javadoc) * @see org.chefproject.service.calendar.RecurrenceRuleBase#getRecurrenceType() */ protected int getRecurrenceType() { return GregorianCalendar.WEEK_OF_MONTH; } /** * {@inheritDoc} */ public String getFrequencyDescription() { return rb.getString("set.TTh"); } /** * {@inheritDoc} */ public String getFrequency() { return FREQ; } /** * Return a List of all RecurrenceInstance objects generated by this rule within the given time range, based on the * prototype first range, in time order. * @param prototype The prototype first TimeRange. * @param range A time range to limit the generated ranges. * @param timeZone The time zone to use for displaying times. * %%% Note: this is currently not implemented, and always uses the "local" zone. * @return a List of RecurrenceInstance generated by this rule in this range. */ public List generateInstances(TimeRange prototype, TimeRange range, TimeZone timeZone) { TimeBreakdown startBreakdown = prototype.firstTime().breakdownLocal(); List rv = new Vector(); GregorianCalendar startCalendarDate = TimeService.getCalendar(TimeService.getLocalTimeZone(),0,0,0,0,0,0,0); startCalendarDate.set( startBreakdown.getYear(), startBreakdown.getMonth() - 1, startBreakdown.getDay(), startBreakdown.getHour(), startBreakdown.getMin(), startBreakdown.getSec()); //may have to move this line ahead GregorianCalendar nextCalendarDate = (GregorianCalendar) startCalendarDate.clone(); //if day of week is not Tuesday or Thursday if( ((startCalendarDate.get(GregorianCalendar.DAY_OF_WEEK)!=3) && ((startCalendarDate.get(GregorianCalendar.DAY_OF_WEEK))!=5 )) ) { //if day of week is Sunday, add two to make it Tuesday if (startCalendarDate.get(GregorianCalendar.DAY_OF_WEEK)==1){ startCalendarDate.add(java.util.Calendar.DAY_OF_MONTH, 2); } //if day of week is Monday, add one to make it Tuesday else if (startCalendarDate.get(GregorianCalendar.DAY_OF_WEEK)==2){ startCalendarDate.add(java.util.Calendar.DAY_OF_MONTH, 1); } //if day of week is Wednesday, add one to make it Thursday else if (startCalendarDate.get(GregorianCalendar.DAY_OF_WEEK)==4){ startCalendarDate.add(java.util.Calendar.DAY_OF_MONTH, 1); } //if day of week is Friday, add four to make it next Tuesday else if (startCalendarDate.get(GregorianCalendar.DAY_OF_WEEK)==6){ startCalendarDate.add(java.util.Calendar.DAY_OF_MONTH, 4); } //must be Saturday, add three to make it next Tuesday else { startCalendarDate.add(java.util.Calendar.DAY_OF_MONTH, 3); } } // end of else shifting startdate for TTh nextCalendarDate = (GregorianCalendar) startCalendarDate.clone(); int currentCount = 1; int hitCount=1; //counts tth/mwf occurences when getCount()>0 do { Time nextTime = TimeService.newTime(nextCalendarDate); // is this past count? if ((getCount() > 0) && (hitCount > getCount())) break; // is this past until? if ((getUntil() != null) && isAfter(nextTime, getUntil()) ) break; TimeRange nextTimeRange = TimeService.newTimeRange(nextTime.getTime(), prototype.duration()); // Is this out of the range? if (isOverlap(range, nextTimeRange)) { TimeRange eventTimeRange = null; // Single time cases require special handling. if ( prototype.isSingleTime() ) { eventTimeRange = TimeService.newTimeRange(nextTimeRange.firstTime()); } else { eventTimeRange = TimeService.newTimeRange(nextTimeRange.firstTime(), nextTimeRange.lastTime(), true, false); } // use this one String eventHR=eventTimeRange.toStringHR(); rv.add(new RecurrenceInstance(eventTimeRange, currentCount)); } // if next starts after the range, stop generating I have added an extra condition here to test TTH/MWF Number of times repetition else if (isAfter(nextTime, range.lastTime()) ) { break; } // Deal with finding respective Tuesdays and Thursdays do { nextCalendarDate = (GregorianCalendar) startCalendarDate.clone();//this line seems pointless nextCalendarDate.add(java.util.Calendar.DAY_OF_MONTH, currentCount); //"1" is the supposed recurrence Type int weekDay=nextCalendarDate.get(GregorianCalendar.DAY_OF_WEEK); if((getInterval()>1&&(weekDay==6))) { nextCalendarDate.add(java.util.Calendar.DAY_OF_MONTH, ((getInterval()-1)*7)+currentCount+2);//"1" is the supposed recurrence Type currentCount+=((getInterval()-1)*7)+2; } else { nextCalendarDate.add(java.util.Calendar.DAY_OF_MONTH, 1); //"1" is the supposed recurrence Type currentCount++; } } while(((nextCalendarDate.get(GregorianCalendar.DAY_OF_WEEK)!=3)&&((nextCalendarDate.get(GregorianCalendar.DAY_OF_WEEK))!=5 ))); hitCount++; } while (true); return rv; } } // TThRecurrenceRule