package org.jblooming.agenda; import net.sf.json.JSONObject; import net.sf.json.JSONArray; import java.util.*; import org.jblooming.utilities.CollectionUtilities; public class ScheduleWeekly extends ScheduleSupport implements Schedule { private int dayArray[]; //specifies the days the event is repeated {Calendar.Monday,... and so on.... public ScheduleWeekly() { } public ScheduleWeekly(int days[], Date start, int duration, boolean onlyWorkingDays) { this(days, start, duration, 1, 1, onlyWorkingDays); } public ScheduleWeekly(int days[], Date start, int duration, int freq, int repetition, boolean onlyWorkingDays) { this(days, start, new CompanyCalendar(start).getMillisFromMidnight(), duration, freq, repetition, onlyWorkingDays); } public ScheduleWeekly(int days[], Date start, int startTime, int duration, boolean onlyWorkingDays) { this(days, start, startTime, duration, 1, 1, onlyWorkingDays); } public ScheduleWeekly(int days[], Date start, int startTime, int duration, int freq, int repetition, boolean onlyWorkingDays) { // added by bicch and chelazz 17/12/2008 if (start.before(new Date(0))) start = new Date(0); this.setStartTime(startTime); this.setStart(start); CompanyCalendar cal = new CompanyCalendar(); cal.setTimeInMillis(this.getValidityStartTime()); cal.setMillisFromMidnight(startTime); this.setStart(cal.getTime()); buildSchedule(days, duration, freq, repetition, onlyWorkingDays); } private void buildSchedule(int[] days, int duration, int freq, int repetition, boolean onlyWorkingDays) { CompanyCalendar cc = new CompanyCalendar(); cc.set(CompanyCalendar.DAY_OF_WEEK, cc.getFirstDayOfWeek()); List daysL = new ArrayList(); for (int i = 0; i < 7; i++) { int d = cc.get(CompanyCalendar.DAY_OF_WEEK); for (int j = 0; j < days.length; j++) { if (d == days[j]) { daysL.add(d); break; } } cc.add(CompanyCalendar.DAY_OF_YEAR, 1); } int dayArrayLocal[] = new int[daysL.size()]; int j = 0; for (Object o : daysL) { dayArrayLocal[j] = (Integer) o; j++; } this.dayArray = dayArrayLocal; this.setDuration(duration); this.setFreq((freq > 0 ? freq : 1)); this.setRepeat(repetition != -1 ? repetition : 0); this.setOnlyWorkingDays(onlyWorkingDays); recalculateFields(); } private int[] getDayArray() { return dayArray; } private void setDayArray(int[] dayArray) { this.dayArray = dayArray; } public int[] getDays() { return dayArray; } public void setDays(int[] dayArray) { this.dayArray = dayArray; recalculateFields(); } public void recalculateFields() { int eventsFired = 0; CompanyCalendar cal = new CompanyCalendar(); cal.setTimeInMillis(this.getValidityStartTime()); boolean found = false; int freq = (this.getFreq() > 0 ? this.getFreq() : 1); int daysSkipped = 0; //begin first week match while (!found) { if (dayArray != null) { for (int day : dayArray) { if (getRepeat() > 0 && eventsFired >= getRepeat()) break; cal.set(Calendar.DAY_OF_WEEK, day); if (!found && cal.getTime().getTime() >= getStart().getTime()) { setStart(cal.getTime()); found = true; } else if (!found) daysSkipped++; if (found) eventsFired++; } } if (!found) cal.add(Calendar.WEEK_OF_YEAR, freq); } setStartTime(cal.getMillisFromMidnight()); //end first week match //begin big leap if (getRepeat() - eventsFired > 0) { int numberOfDaysSelected = getDays().length; int eventsToFireInWeeks = (int) Math.ceil(((double) getRepeat() - (double) eventsFired) / (double) numberOfDaysSelected); cal.add(Calendar.WEEK_OF_YEAR, eventsToFireInWeeks * freq); cal.set(Calendar.DAY_OF_WEEK, dayArray.length > 0 ? dayArray[0] : cal.getFirstDayOfWeek()); eventsFired = eventsFired + (Math.max(eventsToFireInWeeks - 1, 0) * numberOfDaysSelected); } else if (getRepeat() == 0) { cal.setTime(CompanyCalendar.MAX_DATE); } //end big leap cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE,0); cal.set(Calendar.SECOND,0); cal.set(Calendar.MILLISECOND,0); cal.add(Calendar.MILLISECOND, getStartTimeInMillis()); cal.add(Calendar.MILLISECOND, (int) this.getDuration()); //begin eventual last week int dayPos = 0; while (eventsFired < getRepeat()) { if (dayPos >= dayArray.length) dayPos = 0; cal.set(Calendar.DAY_OF_WEEK, dayArray[dayPos]); eventsFired++; dayPos++; } //end eventual last week setEnd(cal.getTime()); } public long getNextFireTimeAfter(long afterTime) { long returnTime = Long.MAX_VALUE; if (afterTime <= getEnd().getTime()) { if (afterTime > getStart().getTime()) { long lstart = getStart().getTime(); CompanyCalendar cal = new CompanyCalendar(); cal.setTimeInMillis(lstart); int posOfWeekOfStart = 0; for (int i = 0; i < dayArray.length; i++) { if (dayArray[i] == cal.get(CompanyCalendar.DAY_OF_WEEK)) { posOfWeekOfStart = i + 1; break; } } if (posOfWeekOfStart >= dayArray.length) posOfWeekOfStart = 0; TimeZone timeZone = cal.getTimeZone(); int ofset = (timeZone.getOffset(lstart) - timeZone.getOffset(afterTime)); // questo serve per calcolare i millisecondi effettivi in caso di ora legale long distInMillisec = afterTime - lstart - ofset; long distInDays = distInMillisec / CompanyCalendar.MILLIS_IN_DAY; long distInWeek = (long) Math.floor(distInDays / 7.0); int freq = (this.getFreq() > 0 ? this.getFreq() : 1); int rep = ((int) distInWeek / freq); //setting ouselves on the first "good" week (i.e. one of those not empty because of frequency) before cal.add(Calendar.WEEK_OF_YEAR, rep * freq); //check whether there is a week day greater than afterTime boolean foundMatchingDay = false; for (int i = 0; i < dayArray.length; i++) { cal.set(CompanyCalendar.DAY_OF_WEEK, dayArray[i]); if (cal.getTime().getTime() >= afterTime) { foundMatchingDay = true; returnTime = cal.getTime().getTime(); break; } } if (!foundMatchingDay) { cal.add(Calendar.WEEK_OF_YEAR, freq); for (int i = 0; i < dayArray.length; i++) { cal.set(CompanyCalendar.DAY_OF_WEEK, dayArray[i]); if (cal.getTime().getTime() >= afterTime) { returnTime = cal.getTime().getTime(); break; } } } } else { returnTime = getStart().getTime(); } } return returnTime; } /* public long getPreviousFireTimeBefore(long beforeTime) { long returnTime = Long.MIN_VALUE; if (beforeTime > getStart().getTime()) { if (beforeTime <= getEnd().getTime()) { long lstart = getStart().getTime(); CompanyCalendar cal = new CompanyCalendar(); cal.setTimeInMillis(lstart); TimeZone timeZone = cal.getTimeZone(); int ofset = (timeZone.getOffset(lstart) - timeZone.getOffset(beforeTime)); // questo server per calcolare i millisecondi effettivi in caso di ora legale long distInMillisec = beforeTime - lstart - ofset; double ddistInDays = (double) distInMillisec / (double) CompanyCalendar.MILLIS_IN_DAY; int distInDays = (int) ddistInDays; long distInWeek = (distInDays / 7); int freq = (this.getFreq() > 0 ? this.getFreq() : 1); int rep = ((int) distInWeek / freq) / Math.max(dayArray.length,1); if (this.getRepeat() == 0 || rep <= (this.getRepeat() - 1)) { cal.setTime(getStart()); cal.add(Calendar.WEEK_OF_YEAR, rep * freq); long next = cal.getTimeInMillis(); for (int i = 0; i < dayArray.length; i++) { cal.set(Calendar.DAY_OF_WEEK, dayArray[i]); if (cal.getTimeInMillis() > next && beforeTime >= cal.getTimeInMillis()) next = cal.getTimeInMillis(); } returnTime = next; } } else { returnTime = getEnd().getTime() - getDuration(); } } return returnTime; }*/ public long getPreviousFireTimeBefore(long beforeTime) { long returnTime = Long.MIN_VALUE; if (beforeTime > getStart().getTime()) { if (beforeTime <= getEnd().getTime()) { CompanyCalendar cal = new CompanyCalendar(getStart()); TimeZone timeZone = cal.getTimeZone(); int ofset = (timeZone.getOffset(getStart().getTime()) - timeZone.getOffset(beforeTime)); // questo server per calcolare i millisecondi effettivi in caso di ora legale //cal.setTime(getStart()); cal.set(CompanyCalendar.DAY_OF_WEEK, cal.getFirstDayOfWeek()); cal.setAndGetTimeToDayStart(); long monThis = cal.getTimeInMillis(); // int dayOfStart=cal.get(CompanyCalendar.DAY_OF_WEEK); cal.setTimeInMillis(beforeTime); cal.set(CompanyCalendar.DAY_OF_WEEK, cal.getFirstDayOfWeek()); cal.setAndGetTimeToDayStart(); long monBefor = cal.getTimeInMillis(); // long distInMillisec = beforeTime - lstart - ofset; long distInMillisec = monBefor - monThis - ofset; double ddistInDays = (double) distInMillisec / (double) CompanyCalendar.MILLIS_IN_DAY; int distInDays = (int) ddistInDays; long distInWeek = (distInDays / 7); int freq = (this.getFreq() > 0 ? this.getFreq() : 1); int jumpInWeeks = ((int) distInWeek / freq); //int rep = ((int) distInWeek / freq) / Math.max(dayArray.length,1); //if (this.getRepeat() == 0 || rep <= (this.getRepeat() - 1)) { // zomp in the correct week cal.setTimeInMillis(monThis); cal.set(CompanyCalendar.DAY_OF_WEEK, cal.getFirstDayOfWeek()); cal.add(Calendar.WEEK_OF_YEAR, jumpInWeeks * freq); long next = Long.MIN_VALUE; cal.setMillisFromMidnight(getStartTimeInMillis()); for (int i = 0; i < dayArray.length; i++) { cal.set(Calendar.DAY_OF_WEEK, dayArray[i]); if (cal.getTimeInMillis() < beforeTime && cal.getTimeInMillis()>next) next = cal.getTimeInMillis(); } if (next== Long.MIN_VALUE){ //zomp back 1 freq cal.add(Calendar.WEEK_OF_YEAR, - freq); for (int i = 0; i < dayArray.length; i++) { cal.set(Calendar.DAY_OF_WEEK, dayArray[i]); if (cal.getTimeInMillis() < beforeTime && cal.getTimeInMillis()>next) next = cal.getTimeInMillis(); } } returnTime = next; //} } else { returnTime = getEnd().getTime() - getDuration(); } } return returnTime; } public JSONObject jsonify() { JSONObject ret = super.jsonify(); ret.element("type","weekly"); /*JSONArray days= new JSONArray(); days.addAll(CollectionUtilities.toList(getDays()));*/ ret.element("days",getDays()); return ret; } }