/*
* 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.application.holiday.business;
import java.util.Date;
import java.util.List;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.LocalDate;
import org.mifos.application.holiday.util.helpers.HolidayConstants;
import org.mifos.application.holiday.util.helpers.RepaymentRuleTypes;
import org.mifos.application.util.helpers.YesNoFlag;
import org.mifos.calendar.NextScheduledEventStrategy;
import org.mifos.calendar.NextWorkingDayStrategy;
import org.mifos.dto.domain.HolidayDetails;
import org.mifos.framework.business.AbstractBusinessObject;
import org.mifos.schedule.ScheduledEvent;
import org.mifos.service.BusinessRuleException;
public class HolidayBO extends AbstractBusinessObject implements Holiday {
private Date holidayThruDate;
private String holidayName;
private RepaymentRuleTypes repaymentRuleType;
private boolean validationEnabled = true;
private Short holidayChangesAppliedFlag = YesNoFlag.NO.getValue();
private Date holidayFromDate;
private Integer id;
public HolidayBO() {
}
public HolidayBO(HolidayDetails holidayDetails) {
this.holidayName = holidayDetails.getName();
this.holidayFromDate = holidayDetails.getFromDate().toDateMidnight().toDate();
if (holidayDetails.getThruDate() != null) {
this.holidayThruDate = holidayDetails.getThruDate().toDateMidnight().toDate();
}
if (holidayDetails.isHolidayChangesApplied()) {
this.holidayChangesAppliedFlag = YesNoFlag.YES.getValue();
}
this.repaymentRuleType = RepaymentRuleTypes.fromInt(holidayDetails.getRepaymentRuleType().intValue());
}
@Override
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public boolean isValidationEnabled() {
return validationEnabled;
}
public void setValidationEnabled(final boolean validationEnabled) {
this.validationEnabled = validationEnabled;
}
@Override
public RepaymentRuleTypes getRepaymentRuleType() {
return repaymentRuleType;
}
@Override
public DateTime getFromDate() {
return new DateTime(getHolidayFromDate());
}
public Date getHolidayFromDate() {
return holidayFromDate;
}
@Override
public DateTime getThruDate() {
return new DateTime(getHolidayThruDate());
}
public Date getHolidayThruDate() {
return this.holidayThruDate;
}
@Override
public String getName() {
return getHolidayName();
}
public String getHolidayName() {
return this.holidayName;
}
@SuppressWarnings("unused")
// see .hbm.xml file
private void setRepaymentRuleType(final RepaymentRuleTypes repaymentRuleType) {
this.repaymentRuleType = repaymentRuleType;
}
@SuppressWarnings("unused")
// see .hbm.xml file
private void setHolidayFromDate(final Date holidayFromDate) {
this.holidayFromDate = holidayFromDate;
}
@SuppressWarnings("unused")
// see .hbm.xml file
private void setHolidayThruDate(final Date holidayThruDate) {
this.holidayThruDate = holidayThruDate;
}
@SuppressWarnings("unused")
// see .hbm.xml file
private void setHolidayName(final String holidayName) {
this.holidayName = holidayName;
}
public Short getHolidayChangesAppliedFlag() {
return holidayChangesAppliedFlag;
}
public void setHolidayChangesAppliedFlag(final Short flag) {
this.holidayChangesAppliedFlag = flag;
}
@Override
public boolean encloses(final Date date) {
LocalDate dateToCheck = new LocalDate(date);
LocalDate fromDate = new LocalDate(getHolidayFromDate());
LocalDate thruDate = new LocalDate(getHolidayThruDate());
return ((dateToCheck.isEqual(fromDate) || dateToCheck.isAfter(fromDate)) &&
(dateToCheck.isBefore(thruDate) || dateToCheck.isEqual(thruDate)));
}
@Override
public boolean encloses(final DateTime dateTime) {
return encloses(dateTime.toDate());
}
/**
* Shift the scheduled day according to the holiday's repayment rule.
*/
@Override
public DateTime adjust(final DateTime scheduledDay, final List<Days> workingDays,
final ScheduledEvent scheduledEvent) {
// This is a hack -- need to refactor into cleaner code or subclass HolidayBO into
// specialized classes for each repayment rule
DateTime adjustedDate = scheduledDay;
switch (repaymentRuleType) {
case NEXT_MEETING_OR_REPAYMENT:
do {
adjustedDate = (new NextScheduledEventStrategy(scheduledEvent)).adjust(adjustedDate);
} while (this.containsDate(adjustedDate));
break;
case NEXT_WORKING_DAY:
adjustedDate = new NextWorkingDayStrategy(workingDays).adjust(new DateTime(this.getHolidayThruDate())
.plusDays(1));
break;
case SAME_DAY:
break;
case REPAYMENT_MORATORIUM:
do {
adjustedDate = (new NextScheduledEventStrategy(scheduledEvent)).adjust(adjustedDate);
} while (this.containsDate(adjustedDate));
break;
default:
break;
}
return adjustedDate;
}
private boolean containsDate(DateTime date) {
return !(date.isBefore(new DateTime(this.getHolidayFromDate())) || date.isAfter(new DateTime(this
.getHolidayThruDate())));
}
@Override
public void markAsApplied() {
this.setHolidayChangesAppliedFlag(YesNoFlag.YES.getValue());
}
@Override
public boolean equals(final Object o) {
if (id != null) {
return id.equals(((HolidayBO) o).getId());
}
return super.equals(o);
}
@Override
public int hashCode() {
if (id != null) {
return id.hashCode();
}
return super.hashCode();
}
public HolidayDetails toDto() {
return new HolidayDetails(this.holidayName, this.holidayFromDate, this.holidayThruDate, this.repaymentRuleType.getValue());
}
public static HolidayBO fromDto(HolidayDetails holidayDetails) {
return new HolidayBO(holidayDetails);
}
public void validate() {
validateFromDateAgainstCurrentDate(this.holidayFromDate);
validateFromDateAgainstThruDate(this.holidayFromDate, this.holidayThruDate);
}
@Override
public boolean isFutureRepayment() {
return repaymentRuleType != RepaymentRuleTypes.SAME_DAY;
}
private void validateFromDateAgainstCurrentDate(final Date fromDate) {
LocalDate currentDate = new LocalDate();
LocalDate fromLocalDate = new LocalDate(fromDate);
if (!fromLocalDate.isAfter(currentDate)) {
throw new BusinessRuleException(HolidayConstants.INVALIDFROMDATE);
}
}
private void validateFromDateAgainstThruDate(final Date fromDate, final Date thruDate) {
LocalDate fromLocalDate = new LocalDate(fromDate);
LocalDate thruLocalDate = new LocalDate(thruDate);
if (fromLocalDate.isAfter(thruLocalDate)) {
throw new BusinessRuleException(HolidayConstants.INVALIDTHRUDATE);
}
}
}