/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
*
* 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 net.java.sip.communicator.plugin.addrbook.msoutlook.calendar;
import java.nio.*;
import java.text.*;
import java.util.*;
import net.java.sip.communicator.service.calendar.*;
/**
* The class represents the recurring pattern structure of calendar item.
*
* @author Hristo Terezov
*/
public class RecurringPattern
{
/**
* Enum for the type of the pattern.
*/
public enum PatternType
{
/**
* Daily recurrence.
*/
Day((short)0x0000),
/**
* Weekly recurrence.
*/
Week((short)0x0001),
/**
* Monthly recurrence.
*/
Month((short)0x0002),
/**
* Monthly recurrence.
*/
MonthNth((short)0x0003),
/**
* Monthly recurrence.
*/
MonthEnd((short)0x004),
/**
* Monthly recurrence.
*/
HjMonth((short)0x000A),
/**
* Monthly recurrence.
*/
HjMonthNth((short)0x000B),
/**
* Monthly recurrence.
*/
HjMonthEnd((short)0x000C);
/**
* The value of the type.
*/
private final short value;
/**
* Constructs new <tt>PatternType</tt> instance.
* @param value the value.
*/
PatternType(short value)
{
this.value = value;
}
/**
* Returns the value of the <tt>PatternType</tt> instance.
* @return the value
*/
public short getValue()
{
return value;
}
/**
* Finds the <tt>PatternType</tt> by given value.
* @param value the value
* @return the found <tt>PatternType</tt> instance or null if no type is
* found.
*/
public static PatternType getFromShort(short value)
{
for(PatternType type : values())
{
if(type.getValue() == value)
return type;
}
return null;
}
}
/**
* The value of recurFrequency field.
*/
private short recurFrequency;
/**
* The value of patternType field.
*/
private PatternType patternType;
/**
* The value of calendarType field.
*/
private short calendarType;
/**
* The value of firstDateTime field.
*/
private int firstDateTime;
/**
* The value of period field.
*/
private int period;
/**
* The value of slidingFlag field.
*/
private int slidingFlag;
/**
* The value of patternSpecific1 field.
*/
private int patternSpecific1;
/**
* The value of patternSpecific2 field.
*/
private int patternSpecific2;
/**
* The value of endType field.
*/
private int endType;
/**
* The value of occurenceCount field.
*/
private int occurenceCount;
/**
* The value of firstDow field.
*/
private int firstDow;
/**
* The value of deletedInstanceCount field.
*/
private int deletedInstanceCount;
/**
* The value of modifiedInstanceCount field.
*/
private int modifiedInstanceCount;
/**
* The value of startDate field.
*/
private int startDate;
/**
* The value of endDate field.
*/
private int endDate;
/**
* List with the start dates of deleted instances.
*/
private List<Date> deletedInstances = new ArrayList<Date>();
/**
* Array with the start dates of modified instances.
*/
private int[] modifiedInstances;
/**
* List of exception info structures included in the pattern.
*/
private List<ExceptionInfo> exceptionInfo;
/**
* The source calendar item of the recurrent series.
*/
private CalendarItemTimerTask sourceTask;
/**
* List of days of week when the calendar item occurred.
*/
private List<Integer> allowedDaysOfWeek = new LinkedList<Integer>();
/**
* The binary data of the pattern.
*/
private ByteBuffer dataBuffer;
/**
* Array with masks for days of week when the calendar item occurs.
*/
public static int[] weekOfDayMask
= {0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010,
0x00000020, 0x00000040};
/**
* Parses the binary data that describes the recurrent pattern.
* @param data the binary data.
* @param sourceTask the calendar item.
* @throws IndexOutOfBoundsException if data can't be parsed.
*/
public RecurringPattern(byte[] data, CalendarItemTimerTask sourceTask)
throws IndexOutOfBoundsException
{
this.sourceTask = sourceTask;
dataBuffer = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
int offset = 4;
recurFrequency = dataBuffer.getShort(offset);
offset += 2;
patternType = PatternType.getFromShort(dataBuffer.getShort(offset));
offset += 2;
calendarType = dataBuffer.getShort(offset);
offset += 2;
firstDateTime = dataBuffer.getInt(offset);
offset += 4;
period = dataBuffer.getInt(offset);
offset += 4;
slidingFlag = dataBuffer.getInt(offset);
offset += 4;
switch(patternType)
{
case Week:
case Month:
case MonthEnd:
case HjMonth:
case HjMonthEnd:
patternSpecific1 = dataBuffer.getInt(offset);
patternSpecific2 = 0;
offset +=4;
if(patternType == PatternType.Week)
{
for(int day = firstDow; day < firstDow + 7; day++)
{
if((patternSpecific1 & (weekOfDayMask[day%7])) != 0)
allowedDaysOfWeek.add((day%7) + 1);
}
}
break;
case MonthNth:
case HjMonthNth:
patternSpecific1 = dataBuffer.getInt(offset);
patternSpecific2 = dataBuffer.getInt(offset + 4);
if(patternSpecific1 == 0x7f && patternSpecific2 != 0x5)
{
patternType = PatternType.Month;
}
for(int day = 0; day < 7; day++)
{
if((patternSpecific1 & (weekOfDayMask[day])) != 0)
allowedDaysOfWeek.add((day) + 1);
}
offset +=8;
break;
default:
break;
}
//endType
endType = dataBuffer.getInt(offset);
offset += 4;
occurenceCount = dataBuffer.getInt(offset);
offset += 4;
firstDow = dataBuffer.getInt(offset);
offset += 4;
deletedInstanceCount = dataBuffer.getInt(offset);
offset += 4;
//deleted instances
for(int i = 0; i < deletedInstanceCount; i ++)
{
deletedInstances.add(
windowsTimeToDateObject(dataBuffer.getInt(offset)));
offset += 4;
}
modifiedInstanceCount = dataBuffer.getInt(offset);
offset += 4;
//modified instances
modifiedInstances = new int[modifiedInstanceCount];
for(int i = 0; i < modifiedInstanceCount; i ++)
{
modifiedInstances[i] = dataBuffer.getInt(offset);
offset += 4;
}
startDate = dataBuffer.getInt(offset);
offset += 4;
endDate = dataBuffer.getInt(offset);
offset += 4;
offset += 16;
short exceptionCount = dataBuffer.getShort(offset);
offset += 2;
exceptionInfo = new ArrayList<ExceptionInfo>(exceptionCount);
for(int i = 0; i < exceptionCount;i++)
{
ExceptionInfo tmpExceptionInfo = new ExceptionInfo(offset);
exceptionInfo.add(tmpExceptionInfo);
offset += tmpExceptionInfo.sizeInBytes();
CalendarService.BusyStatusEnum status
= tmpExceptionInfo.getBusyStatus();
Date startTime = tmpExceptionInfo.getStartDate();
Date endTime = tmpExceptionInfo.getEndDate();
if(status == CalendarService.BusyStatusEnum.FREE
|| startTime == null || endTime == null)
continue;
Date currentTime = new Date();
if(endTime.before(currentTime) || endTime.equals(currentTime))
return;
boolean executeNow = false;
if(startTime.before(currentTime) || startTime.equals(currentTime))
executeNow = true;
CalendarItemTimerTask task = new CalendarItemTimerTask(status,
startTime, endTime, sourceTask.getId(), executeNow, this);
task.scheduleTasks();
}
}
/**
* Converts windows time in minutes from 1/1/1601 to <tt>Date</tt> object.
* @param time the number of minutes from 1/1/1601
* @return the <tt>Date</tt> object
*/
public static Date windowsTimeToDateObject(long time) {
// Date.parse("1/1/1601") == 11644473600000L
long date = time * 60000 - 11644473600000L;
date -= TimeZone.getDefault().getOffset(date);
return new Date(date);
}
/**
* Prints the properties of the class for debugging purpose.
*/
@Override
public String toString()
{
String result = "";
result
+= "recurFrequency: " + String.format("%#02x", this.recurFrequency)
+ "\n";
result += "patternType: "
+ String.format("%#02x", this.patternType.getValue()) + "\n";
result += "calendarType: "
+ String.format("%#02x", this.calendarType) + "\n";
result += "endType: " + String.format("%#04x", this.endType) + "\n";
result += "period: " + this.period + "\n";
result += "occurenceCount: "
+ String.format("%#04x", this.occurenceCount) + "\n";
result += "patternSpecific1: "
+ String.format("%#04x", this.patternSpecific1) + "\n";
result += "patternSpecific2: "
+ String.format("%#04x", this.patternSpecific2) + "\n";
result += "startDate hex: " + String.format("%#04x", this.startDate)
+ "\n";
result += "endDate hex: " + String.format("%#04x", this.endDate) + "\n";
result += "startDate: "
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(
windowsTimeToDateObject(this.startDate)) + "\n";
result += "endDate: "
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(
windowsTimeToDateObject(this.endDate)) + "\n";
for(int i = 0; i < modifiedInstanceCount; i++)
{
result += "modified Instance date hex: "
+ String.format("%#04x", this.modifiedInstances[i]) + "\n";
result += "modified Instance date: "
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z").format(
windowsTimeToDateObject(this.modifiedInstances[i])) + "\n";
}
for(int i = 0; i < deletedInstanceCount; i++)
{
result += "deleted Instance date: "
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z").format(
deletedInstances.get(i)) + "\n";
}
result += "patternSpecific2: "
+ String.format("%#04x", this.patternSpecific2) + "\n";
result += "\n\n =====================Exeptions====================\n\n";
for(ExceptionInfo info : exceptionInfo)
{
result += info.toString() + "\n\n";
}
return result;
}
/**
* Checks whether the given date is in the recurrent pattern range or not
* @param date the date
* @return <tt>true</tt> if the date is in the pattern range.
*/
private boolean dateOutOfRange(Date date)
{
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE,0);
cal.set(Calendar.SECOND,0);
if((endType != 0x00002023) && (endType != 0xFFFFFFFF)
&& cal.getTime().after(windowsTimeToDateObject(this.endDate)))
{
return true;// the series are finished
}
return false;
}
/**
* Calculates and creates the next calendar item.
* @param previousStartDate the start date of the previous occurrence.
* @param previousEndDate the end date of the previous occurrence.
* @return the new calendar item or null if there are no more calendar items
* from that recurrent series.
*/
public CalendarItemTimerTask next(Date previousStartDate,
Date previousEndDate)
{
if(dateOutOfRange(new Date()))
{
return null;
}
Date startDate = previousStartDate;
Date endDate = null;
boolean executeNow = false;
long duration = sourceTask.getEndDate().getTime()
- sourceTask.getStartDate().getTime();
switch(patternType)
{
case Day:
{
startDate
= new Date(startDate.getTime() + period * 60000);
endDate = new Date(
previousEndDate.getTime() + period * 60000);
Date currentDate = new Date();
if(endDate.before(currentDate))
{
long offset
= currentDate.getTime() - endDate.getTime();
offset -= offset % (period * 60000);
if(endDate.getTime() + offset < currentDate.getTime())
{
offset += period * 60000;
}
startDate = new Date(startDate.getTime() + offset);
}
Calendar cal = Calendar.getInstance();
cal.setTime(startDate);
Calendar cal2 = (Calendar) cal.clone();
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
while(deletedInstances.contains(cal.getTime()))
{
cal.add(Calendar.MINUTE, period);
cal2.add(Calendar.MINUTE, period);
}
if(dateOutOfRange(cal.getTime()))
{
return null;
}
startDate = cal2.getTime();
endDate = new Date(startDate.getTime() + duration);
if(startDate.before(currentDate))
{
executeNow = true;
}
return new CalendarItemTimerTask(
sourceTask.getStatus(),
startDate, endDate, sourceTask.getId(), executeNow, this);
}
case Week:
{
Calendar cal = Calendar.getInstance();
/**
* The enum for the firstDow field is the same as Calendar day of
* week enum + 1 day
*/
cal.setFirstDayOfWeek(firstDow + 1);
cal.setTime(startDate);
int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
int index = allowedDaysOfWeek.indexOf(dayOfWeek);
if(++index < allowedDaysOfWeek.size())
{
cal.set(Calendar.DAY_OF_WEEK, allowedDaysOfWeek.get(index));
startDate = cal.getTime();
endDate = new Date(startDate.getTime() + duration);
}
else
{
cal.set(Calendar.DAY_OF_WEEK, allowedDaysOfWeek.get(0));
cal.add(Calendar.WEEK_OF_YEAR, period);
startDate = cal.getTime();
endDate = new Date(startDate.getTime() + duration);
}
Date currentDate = new Date();
if(endDate.before(currentDate))
{
cal.set(Calendar.DAY_OF_WEEK, allowedDaysOfWeek.get(0));
endDate = new Date(cal.getTimeInMillis() + duration);
long offset = (currentDate.getTime() - endDate.getTime());
//1 week = 604800000 is milliseconds
offset -= offset % (period * 604800000);
if(endDate.getTime() + offset < currentDate.getTime())
{
cal.add(Calendar.WEEK_OF_YEAR,
(int)(offset / (period * 604800000)));
int i = 1;
while(((cal.getTimeInMillis() + duration)
< (currentDate.getTime())))
{
if(i == allowedDaysOfWeek.size())
{
cal.add(Calendar.WEEK_OF_YEAR, period);
i = 0;
}
cal.set(Calendar.DAY_OF_WEEK, allowedDaysOfWeek.get(i));
i++;
}
startDate = cal.getTime();
}
else
{
startDate = new Date(cal.getTimeInMillis() + offset);
}
}
cal.setTime(startDate);
Calendar cal2 = (Calendar) cal.clone();
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
index = allowedDaysOfWeek.indexOf(dayOfWeek) + 1;
while(deletedInstances.contains(cal.getTime()))
{
if(index >= allowedDaysOfWeek.size())
{
index = 0;
cal.add(Calendar.WEEK_OF_YEAR, period);
cal2.add(Calendar.WEEK_OF_YEAR, period);
}
cal.set(Calendar.DAY_OF_WEEK, allowedDaysOfWeek.get(index));
cal2.set(Calendar.DAY_OF_WEEK, allowedDaysOfWeek.get(index));
index++;
}
startDate = cal2.getTime();
endDate = new Date(startDate.getTime() + duration);
if(dateOutOfRange(endDate))
return null;
if(startDate.before(currentDate))
{
executeNow = true;
}
return new CalendarItemTimerTask(
sourceTask.getStatus(),
startDate, endDate, sourceTask.getId(), executeNow, this);
}
case Month:
case MonthEnd:
case HjMonth:
case HjMonthEnd:
{
return nextMonth(startDate, endDate, false);
}
case MonthNth:
case HjMonthNth:
{
if(patternSpecific1 == 0x7f && patternSpecific2 == 0x05)
return nextMonth(startDate, endDate, true);
else
return nextMonthN(startDate, endDate);
}
}
return null;
}
/**
* Finds the occurrence of the events in the next months
* @param cal the calendar object
* @param lastDay if <tt>true</tt> it will return the last day of the month
* @param period the number of months to add
* @return the calendar object with set date
*/
private Calendar incrementMonths(Calendar cal, boolean lastDay,
int period)
{
int dayOfMonth = patternSpecific1;
cal.set(Calendar.DAY_OF_MONTH, 1);
cal.add(Calendar.MONTH, period);
if(lastDay
|| (cal.getActualMaximum(Calendar.DAY_OF_MONTH) < dayOfMonth))
dayOfMonth = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
cal.set(Calendar.DAY_OF_MONTH, dayOfMonth);
return cal;
}
/**
* Finds the next occurrence for monthly recurrence.
* @param startDate the start date of the previous calendar item.
* @param endDate the end date of the previous calendar item.
* @param lastDay if <tt>true</tt> we are interested in last day of the
* month
* @return the next item
*/
public CalendarItemTimerTask nextMonth(Date startDate, Date endDate,
boolean lastDay)
{
long duration = sourceTask.getEndDate().getTime()
- sourceTask.getStartDate().getTime();
Calendar cal = Calendar.getInstance();
cal.setTime(startDate);
cal = incrementMonths(cal, lastDay, period);
Date currentDate = new Date();
if(cal.getTimeInMillis() + duration < currentDate.getTime())
{
Calendar cal2 = Calendar.getInstance();
cal2.setTime(currentDate);
int years
= cal2.get(Calendar.YEAR) - cal.get(Calendar.YEAR);
int months = (years * 12)
+ (cal2.get(Calendar.MONTH) - cal.get(Calendar.MONTH));
int monthsToAdd = months;
monthsToAdd -= months % period;
cal = incrementMonths(cal, lastDay, monthsToAdd);
if(cal.getTimeInMillis() + duration < currentDate.getTime())
{
cal = incrementMonths(cal, lastDay, period);
}
}
Calendar cal2 = (Calendar) cal.clone();
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
while(deletedInstances.contains(cal.getTime()))
{
cal = incrementMonths(cal, lastDay, period);
cal2 = incrementMonths(cal2, lastDay, period);
}
startDate = cal2.getTime();
endDate = new Date(startDate.getTime() + duration);
if(dateOutOfRange(endDate))
{
return null;
}
boolean executeNow = startDate.before(currentDate);
return new CalendarItemTimerTask(
sourceTask.getStatus(),
startDate, endDate, sourceTask.getId(), executeNow, this);
}
/**
* Finds the occurrence of the events in the next months
* @param startDate the start date if the calendar item
* @param dayOfWeekInMonth the number of week days occurrences
* @return the date of the next occurrence
*/
private Date getMonthNStartDate(Date startDate, int dayOfWeekInMonth)
{
Calendar cal = Calendar.getInstance();
cal.setTime(startDate);
if(dayOfWeekInMonth == -1)
{
Date result = null;
cal.set(Calendar.DAY_OF_WEEK_IN_MONTH, dayOfWeekInMonth);
for(int day : allowedDaysOfWeek)
{
cal.set(Calendar.DAY_OF_WEEK, day);
if(result == null || result.before(cal.getTime()))
result = cal.getTime();
}
return result;
}
else
while(dayOfWeekInMonth > 0)
{
int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
if(allowedDaysOfWeek.contains(dayOfWeek))
dayOfWeekInMonth--;
if(dayOfWeekInMonth > 0)
cal.add(Calendar.DAY_OF_MONTH, 1);
}
return cal.getTime();
}
/**
* Finds the next occurrence for monthly Nth recurrence.
* @param startDate the start date of the previous calendar item.
* @param endDate the end date of the previous calendar item.
* @return the next item
*/
public CalendarItemTimerTask nextMonthN(Date startDate, Date endDate)
{
int dayOfWeekInMonth = (patternSpecific2 == 5? -1 : patternSpecific2);
long duration = sourceTask.getEndDate().getTime()
- sourceTask.getStartDate().getTime();
Calendar cal = Calendar.getInstance();
cal.setTime(startDate);
cal.set(Calendar.DAY_OF_MONTH, 1);
cal.add(Calendar.MONTH, period);
cal.setTime(getMonthNStartDate(cal.getTime(), dayOfWeekInMonth));
Date currentDate = new Date();
if(cal.getTimeInMillis() + duration < currentDate.getTime())
{
Calendar cal2 = Calendar.getInstance();
cal2.setTime(currentDate);
int years
= cal2.get(Calendar.YEAR) - cal.get(Calendar.YEAR);
int months = (years * 12)
+ (cal2.get(Calendar.MONTH) - cal.get(Calendar.MONTH));
int monthsToAdd = months;
monthsToAdd -= months % period;
cal.set(Calendar.DAY_OF_MONTH, 1);
cal.add(Calendar.MONTH, monthsToAdd);
cal.setTime(getMonthNStartDate(cal.getTime(), dayOfWeekInMonth));
if(cal.getTimeInMillis() + duration < currentDate.getTime())
{
cal.set(Calendar.DAY_OF_MONTH, 1);
cal.add(Calendar.MONTH, monthsToAdd);
cal.setTime(getMonthNStartDate(cal.getTime(), dayOfWeekInMonth));
}
}
Calendar cal2 = (Calendar) cal.clone();
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
while(deletedInstances.contains(cal.getTime()))
{
cal.set(Calendar.DAY_OF_MONTH, 1);
cal.add(Calendar.MONTH, period);
startDate = null;
for(int dayOfWeek : allowedDaysOfWeek)
{
cal.set(Calendar.DAY_OF_WEEK, dayOfWeek);
cal.set(Calendar.DAY_OF_WEEK_IN_MONTH,dayOfWeekInMonth);
if((cal.after(startDate) && dayOfWeekInMonth == -1)
|| (cal.before(startDate) && dayOfWeekInMonth != -1)
|| startDate == null)
{
startDate = cal.getTime();
cal2.set(Calendar.YEAR,cal.get(Calendar.YEAR));
cal2.set(Calendar.MONTH,cal.get(Calendar.MONTH));
cal2.set(Calendar.DATE,cal.get(Calendar.DATE));
}
}
}
startDate = cal2.getTime();
endDate = new Date(startDate.getTime() + duration);
if(dateOutOfRange(endDate))
return null;
boolean executeNow = false;
if(startDate.before(currentDate))
{
executeNow = true;
}
return new CalendarItemTimerTask(
sourceTask.getStatus(),
startDate, endDate, sourceTask.getId(), executeNow, this);
}
/**
* Represents the exception info structure.
*/
public class ExceptionInfo
{
/**
* The start date of the exception.
*/
private final Date startDate;
/**
* The end date of the exception.
*/
private final Date endDate;
/**
* The original start date of the exception.
*/
private final Date originalStartDate;
/**
* The modified flags of the exception.
*/
private final short overrideFlags;
/**
* The new busy status of the exception.
*/
private CalendarService.BusyStatusEnum busyStatus;
/**
* The size of the fixed fields.
*/
private int size = 22;
/**
* Parses the data of the exception.
* @param offset the position where the exception starts in the binary
* data
*/
public ExceptionInfo(int offset)
{
startDate = windowsTimeToDateObject(dataBuffer.getInt(offset));
offset += 4;
endDate = windowsTimeToDateObject(dataBuffer.getInt(offset));
offset += 4;
originalStartDate
= windowsTimeToDateObject(dataBuffer.getInt(offset));
offset += 4;
overrideFlags = dataBuffer.getShort(offset);
offset += 2;
int[] fieldMasks = {0x0001, 0x0002, 0x0004, 0x0008, 0x0010,
0x0020, 0x0040, 0x0080};
for(int mask : fieldMasks)
{
if(mask == 0x0020)
{
if((overrideFlags & mask) != 0)
{
busyStatus = CalendarService.BusyStatusEnum.getFromLong(
(long)dataBuffer.getInt(offset));
}
if(busyStatus == null)
{
busyStatus = sourceTask.getStatus();
}
}
if((overrideFlags & mask) != 0)
{
if(mask == 0x0010 || mask == 0x0001)
{
short size = dataBuffer.getShort(offset + 2);
offset += size;
size += size;
}
offset += 4;
size += 4;
}
}
offset += 4;
int reservedBlockSize = dataBuffer.getShort(offset);
size += reservedBlockSize;
}
/**
* Returns the size of the exception
* @return the size of the exception
*/
public int sizeInBytes()
{
return size;
}
/**
* Returns the start date
* @return the start date
*/
public Date getStartDate()
{
return startDate;
}
/**
* Returns the end date
* @return the end date
*/
public Date getEndDate()
{
return endDate;
}
/**
* Returns the busy status
* @return the busy status
*/
public CalendarService.BusyStatusEnum getBusyStatus()
{
return busyStatus;
}
/**
* Prints the properties of the class for debugging purpose.
*/
@Override
public String toString()
{
String result = "";
result += "startDate: "
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z")
.format(startDate) + "\n";
result += "endDate: "
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z")
.format(endDate) + "\n";
result += "originalStartDate: "
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z")
.format(originalStartDate) + "\n";
return result;
}
}
}