/*
* This file is part of LibrePlan
*
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
* Desenvolvemento Tecnolóxico de Galicia
* Copyright (C) 2010-2011 Igalia, S.L.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.libreplan.ws.calendars.impl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.datatype.XMLGregorianCalendar;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.LocalDate;
import org.libreplan.business.calendars.entities.BaseCalendar;
import org.libreplan.business.calendars.entities.CalendarData;
import org.libreplan.business.calendars.entities.CalendarData.Days;
import org.libreplan.business.calendars.entities.CalendarException;
import org.libreplan.business.calendars.entities.CalendarExceptionType;
import org.libreplan.business.calendars.entities.Capacity;
import org.libreplan.business.common.Registry;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.business.workingday.EffortDuration;
import org.libreplan.ws.calendars.api.BaseCalendarDTO;
import org.libreplan.ws.calendars.api.CalendarDataDTO;
import org.libreplan.ws.calendars.api.CalendarExceptionDTO;
import org.libreplan.ws.calendars.api.HoursPerDayDTO;
import org.libreplan.ws.common.impl.DateConverter;
/**
* Converter from/to {@link BaseCalendar} related entities to/from DTOs.
* @author Manuel Rego Casasnovas <mrego@igalia.com>
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/
public final class CalendarConverter {
private CalendarConverter() {
}
public final static BaseCalendarDTO toDTO(BaseCalendar baseCalendar) {
List<CalendarExceptionDTO> calendarExceptionDTOs = new ArrayList<CalendarExceptionDTO>();
for (CalendarException calendarException : baseCalendar.getExceptions()) {
calendarExceptionDTOs.add(toDTO(calendarException));
}
List<CalendarDataDTO> calendarDataDTOs = new ArrayList<CalendarDataDTO>();
for (CalendarData calendarData : baseCalendar.getCalendarDataVersions()) {
calendarDataDTOs.add(toDTO(calendarData));
}
String parent = null;
if (baseCalendar.getParent() != null) {
parent = baseCalendar.getParent().getCode();
}
return new BaseCalendarDTO(baseCalendar.getCode(), baseCalendar
.getName(), parent, calendarExceptionDTOs, calendarDataDTOs);
}
private final static CalendarExceptionDTO toDTO(
CalendarException calendarException) {
XMLGregorianCalendar date = DateConverter
.toXMLGregorianCalendar(calendarException.getDate());
int hours = calendarException.getDuration().getHours();
String code = calendarException.getType().getCode();
return new CalendarExceptionDTO(calendarException.getCode(), date,
hours, code);
}
private final static CalendarDataDTO toDTO(CalendarData calendarData) {
List<HoursPerDayDTO> hoursPerDayDTOs = new ArrayList<HoursPerDayDTO>();
Days[] days = CalendarData.Days.values();
for (Integer day : calendarData.getHoursPerDay().keySet()) {
String dayName = days[day].name();
Integer hours = calendarData.getHoursPerDay().get(day);
hoursPerDayDTOs.add(new HoursPerDayDTO(dayName, hours));
}
XMLGregorianCalendar expiringDate = (calendarData.getExpiringDate() != null) ? DateConverter
.toXMLGregorianCalendar(calendarData
.getExpiringDate())
: null;
String parentCalendar = (calendarData.getParent() != null) ? calendarData
.getParent().getCode()
: null;
return new CalendarDataDTO(calendarData.getCode(), hoursPerDayDTOs,
expiringDate, parentCalendar);
}
public final static BaseCalendar toEntity(BaseCalendarDTO baseCalendarDTO) {
Set<CalendarException> exceptions = new HashSet<CalendarException>();
if (baseCalendarDTO.calendarExceptions != null) {
for (CalendarExceptionDTO exceptionDTO : baseCalendarDTO.calendarExceptions) {
exceptions.add(toEntity(exceptionDTO));
}
}
List<CalendarData> calendarDataVersions = new ArrayList<CalendarData>();
if (baseCalendarDTO.calendarData != null) {
for (CalendarDataDTO calendarDataDTO : baseCalendarDTO.calendarData) {
calendarDataVersions.add(toEntity(calendarDataDTO));
}
calendarDataVersions = getVersionsOrderedByExpiringDate(calendarDataVersions);
}
BaseCalendar parent = findBaseCalendarParent(baseCalendarDTO.parent);
try {
return BaseCalendar.createUnvalidated(baseCalendarDTO.code,
baseCalendarDTO.name, parent, exceptions, calendarDataVersions);
} catch (IllegalArgumentException e) {
throw new ValidationException(e.getMessage());
}
}
public final static CalendarException toEntity(
CalendarExceptionDTO calendarExceptionDTO) {
LocalDate date = null;
if (calendarExceptionDTO.date != null) {
date = DateConverter.toLocalDate(calendarExceptionDTO.date);
}
CalendarExceptionType type = findCalendarExceptionType(calendarExceptionDTO.calendarExceptionTypeCode);
return CalendarException.create(calendarExceptionDTO.code, date,
EffortDuration.hours(calendarExceptionDTO.hours), type);
}
public final static CalendarData toEntity(CalendarDataDTO calendarDataDTO) {
LocalDate expiringDate = null;
if (calendarDataDTO.expiringDate != null) {
expiringDate = DateConverter
.toLocalDate(calendarDataDTO.expiringDate);
}
BaseCalendar parent = findBaseCalendarParent(calendarDataDTO.parentCalendar);
CalendarData calendarData = CalendarData.createUnvalidated(
calendarDataDTO.code, expiringDate, parent);
Map<Integer, Capacity> capacitiesPerDays = getCapacitiesPerDays(calendarDataDTO.hoursPerDays);
try {
calendarData.updateCapacitiesPerDay(capacitiesPerDays);
} catch (IllegalArgumentException e) {
throw new ValidationException(e.getMessage());
}
return calendarData;
}
public final static void update(BaseCalendar baseCalendar,
BaseCalendarDTO baseCalendarDTO) {
if (baseCalendarDTO.calendarExceptions != null) {
for (CalendarExceptionDTO exceptionDTO : baseCalendarDTO.calendarExceptions) {
if (StringUtils.isBlank(exceptionDTO.code)) {
throw new ValidationException(
"missing code in a calendar exception");
}
if (exceptionDTO.date == null) {
throw new ValidationException(
"missing date in a calendar exception");
}
// find by code
try {
CalendarException exception = baseCalendar
.getCalendarExceptionByCode(exceptionDTO.code);
update(exception, exceptionDTO);
} catch (InstanceNotFoundException e) {
// find by date
CalendarException exception = baseCalendar
.getOwnExceptionDay(DateConverter
.toLocalDate(exceptionDTO.date));
if (exception != null) {
throw new ValidationException(
"exception date already exists");
} else {
try {
baseCalendar
.addExceptionDay(toEntity(exceptionDTO));
} catch (IllegalArgumentException o) {
throw new ValidationException(o.getMessage());
}
}
}
}
}
if (baseCalendarDTO.calendarData != null) {
for (CalendarDataDTO calendarDataDTO : baseCalendarDTO.calendarData) {
if (StringUtils.isBlank(calendarDataDTO.code)) {
throw new ValidationException(
"missing code in a calendar data version");
}
// find by code
try {
CalendarData version = baseCalendar
.getCalendarDataByCode(calendarDataDTO.code);
update(version, calendarDataDTO);
} catch (InstanceNotFoundException e) {
try {
baseCalendar.addNewVersion(toEntity(calendarDataDTO));
} catch (IllegalArgumentException o) {
throw new ValidationException(o.getMessage());
}
}
}
}
BaseCalendar parent = null;
if (!StringUtils.isBlank(baseCalendarDTO.parent)) {
try {
parent = Registry.getBaseCalendarDAO().findByCode(
baseCalendarDTO.parent);
} catch (InstanceNotFoundException e) {
throw new ValidationException(
"The base calendar parent not found");
}
}
baseCalendar.updateUnvalidated(baseCalendarDTO.name, parent);
}
public final static void update(CalendarException exception,
CalendarExceptionDTO calendarExceptionDTO) {
LocalDate date = null;
if (calendarExceptionDTO.date != null) {
date = DateConverter.toLocalDate(calendarExceptionDTO.date);
}
CalendarExceptionType type = findCalendarExceptionType(calendarExceptionDTO.calendarExceptionTypeCode);
exception.updateUnvalidated(date, calendarExceptionDTO.hours, type);
}
public final static void update(CalendarData calendarData,
CalendarDataDTO calendarDataDTO) {
LocalDate expiringDate = null;
if (calendarDataDTO.expiringDate != null) {
expiringDate = DateConverter
.toLocalDate(calendarDataDTO.expiringDate);
}
BaseCalendar parent = findBaseCalendarParent(calendarDataDTO.parentCalendar);
Map<Integer, Capacity> capacitiesPerDays = getCapacitiesPerDays(calendarDataDTO.hoursPerDays);
try {
calendarData.updateCapacitiesPerDay(capacitiesPerDays);
} catch (IllegalArgumentException e) {
throw new ValidationException(e.getMessage());
}
calendarData.updateUnvalidated(expiringDate, parent);
}
private static Map<Integer, Capacity> getCapacitiesPerDays(
List<HoursPerDayDTO> hoursPerDayDTOs) {
Map<Integer, Capacity> result = new HashMap<Integer, Capacity>();
if (hoursPerDayDTOs != null) {
for (HoursPerDayDTO hoursPerDayDTO : hoursPerDayDTOs) {
try {
Integer day = CalendarData.Days.valueOf(hoursPerDayDTO.day)
.ordinal();
Capacity capacity = Capacity.create(
EffortDuration.hours(hoursPerDayDTO.hours))
.overAssignableWithoutLimit();
result.put(day, capacity);
} catch (IllegalArgumentException e) {
throw new ValidationException("a day is not valid");
} catch (NullPointerException e) {
throw new ValidationException("a day is null");
}
}
}
return result;
}
private static BaseCalendar findBaseCalendarParent(String parentCode) {
if (StringUtils.isBlank(parentCode)) {
return null;
}
try {
return Registry.getBaseCalendarDAO().findByCode(parentCode);
} catch (InstanceNotFoundException e) {
throw new ValidationException("The base calendar parent not found");
}
}
private static CalendarExceptionType findCalendarExceptionType(
String typeCode) {
if (StringUtils.isBlank(typeCode)) {
return null;
}
try {
return Registry.getCalendarExceptionTypeDAO().findByCode(typeCode);
} catch (InstanceNotFoundException e) {
throw new ValidationException(
"The calendar exception type not found");
}
}
private static final List<CalendarData> getVersionsOrderedByExpiringDate(
List<CalendarData> versions) {
Collections.sort(versions, new Comparator<CalendarData>() {
@Override
public int compare(CalendarData o1, CalendarData o2) {
if (o1.getExpiringDate() == null) {
return 1;
}
if (o2.getExpiringDate() == null) {
return -1;
}
return o1.getExpiringDate().compareTo(o2.getExpiringDate());
}
});
return versions;
}
}