/*
* Copyright (c) 2005-2011 Grameen Foundation USA
* All rights reserved.
*
* 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.
*
* See also http://www.apache.org/licenses/LICENSE-2.0.html for an
* explanation of the license and how it is applied.
*/
package org.mifos.schedule.internal;
import org.mifos.schedule.ScheduledEvent;
public abstract class AbstractScheduledEvent implements ScheduledEvent {
/**
* Count the number of occurrences of the dependent event that would roll up to the given occurrence of this event.
* It is assumed that the two events have like recurrences (e.g both meet on Tuesdays) but may differ in
* the number of periods skipped. It is also assumed that the dependent schedule starts on startingOccurrence
* of this event.
*
* <p> See {@liink FeeInstallment#createMergedFeeInstallments()} in which this method is used to determine how
* many fee installments roll up to meeting or loan installments.</p>
*
* <p>For example, if this event's schedule is every Tuesday but the dependent schedule is every other Tuesday,
* and the dependent schedule starts on this event's third occurrence:
*
*<pre>
* ---------------------------------------------
*|installment | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
* --------------------------------------------
*|returns | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
* ---------------------------------------------
*</pre>
*
*<p>A more complex example: This event is scheduled for every third week and the dependent event is scheduled
*for every other week. Assume the dependent schedule starts with this event's 5th occurrence (table has
*one column for each week)
*
*<pre>
* -------------------------------------------------------------------------------------------
* | this occurrences | 5 | | | 6 | | | 7 | | | 8 | | | 9 |
* | dependent occurrences. | X | | X | | X | | X | | X | | | X | |
* | returns | 1 | | | 1 | | | 2 | | | 1 | | | 2 |
* -------------------------------------------------------------------------------------------
*</pre>
*
*<p>Switching around: This event is scheduled for every third week and the dependent event is scheduled
*for every second week:
*
*
* @param dependentEvent the ScheduledEvent whose dates roll up to dates of this event
* @param occurrence the index of the date of this event that dependent events roll up to
* @param startingOccurrence the dependent event's occurrences start with this occurrence of this event
* @return the number of installments of the dependent event falling between the given installment of this event
* and the previous installment, not including the previous but including the given installment.
* @throws IllegalArgumentException if occurrence or startingOccurrence is not positive
* @throws IllegalArgumentException if the two events' recurrences do not match
*/
@Override
public int numberOfDependentOccurrencesRollingUpToThisOccurrenceStartingWith
(ScheduledEvent dependentEvent, int occurrence, int startingOccurrence) {
if ((occurrence <=0) || (startingOccurrence <= 0)) {
throw new IllegalArgumentException("Occurrences must not be negative.");
}
if (occurrence < startingOccurrence) {
throw new IllegalArgumentException("Occurrence must be on or after starting occurrence.");
}
//TODO KRP: add check that events have similar recurrences (e.g. both weekly)
if (occurrence == startingOccurrence) {
return 1;
}
return numberOfEventsOnOrBefore (dependentEvent, occurrence, startingOccurrence)
- numberOfEventsOnOrBefore (dependentEvent, occurrence - 1, startingOccurrence);
}
/**
* Assume that this event's occurrences are numbered consecutively.
* Assume that this event and the dependent event have the same recurrence period (e.g., both are weekly events).
* Also assume this and the dependent event's first occurrence coincide.
* Then return the number of dependent event's occurrence that occur before or on
* this event's occurrence but after this event's previous occurrence.
*/
@Override
public int numberOfEventsRollingUpToThis(ScheduledEvent dependentEvent, int occurrence) {
return numberOfDependentOccurrencesRollingUpToThisOccurrenceStartingWith(dependentEvent, occurrence, 1);
}
/**
* Same as above, but assume that an occurrence of the dependent event coincides with this event's startingEventNumber.
*/
// private int numberOfDependentOccurrencesRollingUpToThisOccurrenceWithStartingOccurrence
// (ScheduledEvent dependentEvent, int occurrence, int startingOccurrence) {
//
// if ((occurrence <=0) || (startingOccurrence <= 0)) {
// throw new IllegalArgumentException("Installment number must be positive.");
// }
// //TODO KRP: add check that events have similar recurrences (e.g. both weekly)
//
// if (occurrence == startingOccurrence) {
// return 1;
// }
// return numberOfEventsOnOrBefore (dependentEvent, occurrence, startingOccurrence)
// - numberOfEventsOnOrBefore (dependentEvent, occurrence - 1, startingOccurrence);
// }
/**
* Assume that this event's occurrences are numbered consecutively.
* Assume that this event and the dependent event have the same recurrence period (e.g., both are weekly events).
* Also assume that an occurrence of the dependent event coincides with this event's startingOccurrence.
* Then return the number of dependent event's occurrence that occur before or on
* this event's occurrence, starting with startingOdduccence.
*/
private int numberOfEventsOnOrBefore (ScheduledEvent dependentEvent, int occurrence, int startingOccurrence) {
return ((occurrence - startingOccurrence) * this.getEvery()) / dependentEvent.getEvery() + 1;
}
}