/***********************************************************************************
*
* 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.Calendar;
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;
/**
* Sunday, Monday, Wednesday recurrence rule
*/
public class SMWRecurrenceRule extends RecurrenceRuleBase
{
protected final static String FREQ = "SMW";
public SMWRecurrenceRule() {
super();
}
public SMWRecurrenceRule(int interval) {
super(interval);
}
public SMWRecurrenceRule(int interval, int count) {
super(interval, count);
}
public SMWRecurrenceRule(int interval, Time until) {
super(interval, until);
}
public Element toXml(Document doc, Stack stack) {
Element rule = doc.createElement("rule");
((Element)stack.peek()).appendChild(rule);
rule.setAttribute("class", "org.chefproject.osid.calendar.SMWRecurrenceRule");
rule.setAttribute("name", "SMWRecurrenceRule");
setBaseClassXML(rule);
return rule;
}
protected int getRecurrenceType() {
return GregorianCalendar.WEEK_OF_MONTH;
}
/**
* {@inheritDoc}
*/
public String getFrequencyDescription() {
return rb.getString("set.SMW");
}
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 Sunday, Monday or Wednesday
if( ((startCalendarDate.get(GregorianCalendar.DAY_OF_WEEK)!=1) && (startCalendarDate.get(GregorianCalendar.DAY_OF_WEEK)!=2) && ((startCalendarDate.get(GregorianCalendar.DAY_OF_WEEK))!=4 ))){
//if day of week is Tuesday, add one to make it Wednesday
if (startCalendarDate.get(GregorianCalendar.DAY_OF_WEEK)==3){
startCalendarDate.add(java.util.Calendar.DAY_OF_MONTH, 1);
}
//if day of week is Thursday, add three to make it next Sunday
else if (startCalendarDate.get(GregorianCalendar.DAY_OF_WEEK)==5){
startCalendarDate.add(java.util.Calendar.DAY_OF_MONTH, 3);
}
//if day of week is Friday, add two to make it next Sunday
else if (startCalendarDate.get(GregorianCalendar.DAY_OF_WEEK)==6){
startCalendarDate.add(java.util.Calendar.DAY_OF_MONTH, 2);
}
//must be Saturday, add one to make it next Sunday
else {
startCalendarDate.add(java.util.Calendar.DAY_OF_MONTH, 1);
}
}
nextCalendarDate = (GregorianCalendar) startCalendarDate.clone();
int currentCount = 1;
int hitCount=1;
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
else if (isAfter(nextTime, range.lastTime()) ) {
break;
}
// Examine every day in the calendar, if next date is not Sunday or Monday or Wednesday
do{
int weekDay=nextCalendarDate.get(GregorianCalendar.DAY_OF_WEEK);
//if we have past all applicable days for this week, skip the (interval weeks-1) + 1 day, then continue processing.
//for example if this is a thursday and interval is two weeks, we skip to friday of next week then continue.
if((getInterval()>1&&(weekDay==5)))
{
int increment = (((getInterval()-1)*7)+1);
nextCalendarDate.add(java.util.Calendar.DAY_OF_MONTH, increment);
currentCount+=increment;
}
else
//check next day
{
nextCalendarDate.add(java.util.Calendar.DAY_OF_MONTH, 1);
currentCount++;
}
} while((nextCalendarDate.get(GregorianCalendar.DAY_OF_WEEK)!=1)&&(nextCalendarDate.get(GregorianCalendar.DAY_OF_WEEK)!=2)&&((nextCalendarDate.get(GregorianCalendar.DAY_OF_WEEK))!=4));
hitCount++;
} while (true);
return rv;
}
}