/*
* 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.workreports.impl;
import java.text.MessageFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.xml.datatype.XMLGregorianCalendar;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.libreplan.business.common.Registry;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.business.costcategories.entities.TypeOfWorkHours;
import org.libreplan.business.labels.entities.Label;
import org.libreplan.business.labels.entities.LabelType;
import org.libreplan.business.orders.entities.OrderElement;
import org.libreplan.business.resources.entities.Resource;
import org.libreplan.business.workingday.EffortDuration;
import org.libreplan.business.workreports.entities.WorkReport;
import org.libreplan.business.workreports.entities.WorkReportLine;
import org.libreplan.business.workreports.entities.WorkReportType;
import org.libreplan.business.workreports.valueobjects.DescriptionValue;
import org.libreplan.ws.common.api.LabelReferenceDTO;
import org.libreplan.ws.common.impl.DateConverter;
import org.libreplan.ws.common.impl.LabelReferenceConverter;
import org.libreplan.ws.workreports.api.DescriptionValueDTO;
import org.libreplan.ws.workreports.api.IBindingOrderElementStrategy;
import org.libreplan.ws.workreports.api.OneOrderElementPerWorkReportLine;
import org.libreplan.ws.workreports.api.WorkReportDTO;
import org.libreplan.ws.workreports.api.WorkReportLineDTO;
import org.springframework.transaction.annotation.Transactional;
import org.zkoss.lang.Strings;
/**
* Converter from/to work report related entities to/from DTOs.
*
* @author Manuel Rego Casasnovas <mrego@igalia.com>
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
* @author Ignacio Diaz Teijido <ignacio.diaz@comtecsf.es>
*/
public final class WorkReportConverter {
private static IBindingOrderElementStrategy bindingStrategy = OneOrderElementPerWorkReportLine
.getInstance();
public static WorkReport toEntity(WorkReportDTO workReportDTO)
throws InstanceNotFoundException {
WorkReport workReport = WorkReport.create();
// Mandatory fields
workReport.setCode(workReportDTO.code);
try {
WorkReportType workReportType = Registry.getWorkReportTypeDAO()
.findUniqueByCode(workReportDTO.workReportType);
workReport.setWorkReportType(workReportType);
} catch (InstanceNotFoundException e) {
throw new ValidationException(
"There is no type of work report with this code");
}
for (WorkReportLineDTO workReportLineDTO : workReportDTO.workReportLines) {
workReport
.addWorkReportLine(toEntity(workReportLineDTO, workReport));
}
// Optional fields
if (workReportDTO.date != null) {
workReport.setDate(DateConverter.toDate(workReportDTO.date));
}
bindingStrategy.assignOrderElementsToWorkReportLine(workReport,
bindingStrategy.getOrderElementsBound(workReportDTO));
if (workReportDTO.resource != null) {
try {
Resource resource = Registry.getResourceDAO().findByCode(
workReportDTO.resource);
workReport.setResource(resource);
} catch (InstanceNotFoundException e) {
workReport.setResource(null);
throw new ValidationException(
"There is no resource with this code");
}
}
if (workReportDTO.labels != null && !workReportDTO.labels.isEmpty()) {
try {
workReport.setLabels(LabelReferenceConverter
.toEntity(workReportDTO.labels));
} catch (InstanceNotFoundException e) {
throw new ValidationException(MessageFormat.format(
"There is no label with this code ",
(String) e.getKey()));
}
}
if (workReportDTO.descriptionValues != null
&& !workReportDTO.descriptionValues.isEmpty()) {
workReport
.setDescriptionValues(toEntity(workReportDTO.descriptionValues));
}
return workReport;
}
private static WorkReportLine toEntity(WorkReportLineDTO workReportLineDTO,
WorkReport workReport)
throws InstanceNotFoundException {
WorkReportLine workReportLine = WorkReportLine.create(workReport);
// Mandatory fields
workReportLine.setCode(workReportLineDTO.code);
workReportLine.setEffort(EffortDuration
.parseFromFormattedString(workReportLineDTO.numHours));
if (workReportLineDTO.typeOfWorkHours != null) {
try {
TypeOfWorkHours typeOfWorkHours = Registry
.getTypeOfWorkHoursDAO().findUniqueByCode(
workReportLineDTO.typeOfWorkHours);
workReportLine.setTypeOfWorkHours(typeOfWorkHours);
} catch (InstanceNotFoundException e) {
throw new ValidationException(
"There is no type of work hours with this code");
}
}
// Optional fields
if (workReportLineDTO.date != null) {
workReportLine
.setDate(DateConverter.toDate(workReportLineDTO.date));
}
bindingStrategy.assignOrderElementsToWorkReportLine(workReportLine,
bindingStrategy.getOrderElementsBound(workReportLineDTO));
if (workReportLineDTO.resource != null) {
try {
Resource resource = Registry.getResourceDAO().findByCode(
workReportLineDTO.resource);
workReportLine.setResource(resource);
} catch (InstanceNotFoundException e) {
workReportLine.setResource(null);
throw new ValidationException(
"There is no resource with this code");
}
}
if (workReportLineDTO.clockStart != null) {
workReportLine.setClockStart(DateConverter
.toLocalTime(workReportLineDTO.clockStart));
}
if (workReportLineDTO.clockFinish != null) {
workReportLine.setClockFinish(DateConverter
.toLocalTime(workReportLineDTO.clockFinish));
}
if (workReportLineDTO.labels != null
&& !workReportLineDTO.labels.isEmpty()) {
workReportLine.setLabels(LabelReferenceConverter
.toEntity(workReportLineDTO.labels));
}
if (workReportLineDTO.descriptionValues != null) {
workReportLine
.setDescriptionValues(toEntity(workReportLineDTO.descriptionValues));
}
return workReportLine;
}
private static Set<DescriptionValue> toEntity(
Set<DescriptionValueDTO> descriptionValues) {
Set<DescriptionValue> result = new HashSet<DescriptionValue>();
for (DescriptionValueDTO descriptionValueDTO : descriptionValues) {
result.add(toEntity(descriptionValueDTO));
}
return result;
}
private static DescriptionValue toEntity(
DescriptionValueDTO descriptionValueDTO) {
return DescriptionValue.create(descriptionValueDTO.fieldName,
descriptionValueDTO.value);
}
public final static WorkReportDTO toDTO(WorkReport workReport) {
String code = workReport.getCode();
String workReportTypeCode = null;
if (workReport.getWorkReportType() != null) {
workReportTypeCode = workReport.getWorkReportType()
.getCode();
} else {
throw new ValidationException(
"missing work report code in a work report");
}
// Optional fields
XMLGregorianCalendar date = null;
if (workReport.getDate() != null) {
date = DateConverter.toXMLGregorianCalendar(workReport.getDate());
}
String orderElementCode = bindingStrategy
.getOrderElementCodesBound(workReport);
String resourceCode = null;
if ((workReport.getResource() != null)) {
resourceCode = workReport.getResource().getCode();
}
Set<LabelReferenceDTO> labelDTOs = LabelReferenceConverter
.toDTO(workReport.getLabels());
if (labelDTOs.isEmpty()) {
labelDTOs = null;
}
Set<DescriptionValueDTO> descriptionValuesDTOs = toDTO(workReport
.getDescriptionValues());
if (descriptionValuesDTOs.isEmpty()) {
descriptionValuesDTOs = null;
}
Set<WorkReportLineDTO> workReportLineDTOs = new HashSet<WorkReportLineDTO>();
for (WorkReportLine line : workReport.getWorkReportLines()) {
workReportLineDTOs.add(toDTO(line));
}
if (workReportLineDTOs.isEmpty()) {
workReportLineDTOs = null;
}
return new WorkReportDTO(code, workReportTypeCode, date, resourceCode,
orderElementCode, labelDTOs, descriptionValuesDTOs,
workReportLineDTOs);
}
public final static WorkReportLineDTO toDTO(WorkReportLine line){
String code = line.getCode();
XMLGregorianCalendar date = DateConverter.toXMLGregorianCalendar(line
.getDate());
String resource = null;
if (line.getResource() != null) {
resource = line.getResource().getCode();
}
String orderElement = bindingStrategy.getOrderElementCodesBound(line);
String typeOfWorkHours = null;
if(line.getTypeOfWorkHours() != null){
typeOfWorkHours = line.getTypeOfWorkHours().getCode();
}
XMLGregorianCalendar clockStart = null;
if(line.getClockStart() != null){
clockStart = DateConverter.toXMLGregorianCalendar(line.getClockStart());
}
XMLGregorianCalendar clockFinish = null;
if(line.getClockFinish() != null){
clockFinish = DateConverter.toXMLGregorianCalendar(line
.getClockFinish());
}
String numHours = null;
if (line.getEffort() != null) {
numHours = line.getEffort().toFormattedString();
}
Set<LabelReferenceDTO> labelDTOs = LabelReferenceConverter.toDTO(line
.getLabels());
if(labelDTOs.isEmpty()){
labelDTOs = null;
}
Set<DescriptionValueDTO> descriptionValuesDTOs = toDTO(line
.getDescriptionValues());
if (descriptionValuesDTOs.isEmpty()) {
descriptionValuesDTOs = null;
}
WorkReportLineDTO workReportLineDTO = new WorkReportLineDTO(code, date,
resource, orderElement, typeOfWorkHours, clockStart,
clockFinish, numHours, labelDTOs, descriptionValuesDTOs);
return workReportLineDTO;
}
private static Set<DescriptionValueDTO> toDTO(
Set<DescriptionValue> descriptionValues) {
Set<DescriptionValueDTO> result = new HashSet<DescriptionValueDTO>();
for (DescriptionValue descriptionValue : descriptionValues) {
result.add(toDTO(descriptionValue));
}
return result;
}
private static DescriptionValueDTO toDTO(DescriptionValue descriptionValue) {
return new DescriptionValueDTO(descriptionValue.getFieldName(),
descriptionValue.getValue());
}
public final static void updateWorkReport(WorkReport workReport,
WorkReportDTO workReportDTO) throws ValidationException {
if (StringUtils.isBlank(workReportDTO.code)) {
throw new ValidationException("missing code in a work report.");
}
/*
* 1: Update the existing work report line or add new
* work report line.
*/
for (WorkReportLineDTO lineDTO : workReportDTO.workReportLines) {
/* Step 1.1: requires each work report line DTO to have a code. */
if (StringUtils.isBlank(lineDTO.code)) {
throw new ValidationException(
"missing code in a work report line");
}
try {
WorkReportLine line = workReport
.getWorkReportLineByCode(lineDTO.code);
updateWorkReportLine(line, lineDTO);
} catch (InstanceNotFoundException e) {
try {
workReport.addWorkReportLine(toEntity(lineDTO, workReport));
} catch (InstanceNotFoundException o) {
throw new ValidationException(
"missing type of work hours in a work report line");
}
}
}
/*
* 2: Update the existing labels
*/
if (workReportDTO.labels != null) {
for (LabelReferenceDTO labelDTO : workReportDTO.labels) {
/* Step 2.1: requires each label reference DTO to have a code. */
if (StringUtils.isBlank(labelDTO.code)) {
throw new ValidationException("missing code in a label");
}
try {
Set<Label> labels = workReport.getLabels();
updateLabel(labelDTO, labels);
} catch (InstanceNotFoundException e) {
throw new ValidationException(
"work report has not this label type assigned");
}
}
}
/*
* 3: Update the existing description values
*/
if (workReportDTO.descriptionValues != null) {
for (DescriptionValueDTO valueDTO : workReportDTO.descriptionValues) {
/* Step 3.1: requires each description value DTO to have a code. */
if (StringUtils.isBlank(valueDTO.fieldName)) {
throw new ValidationException(
"missing field name in a description value");
}
try {
DescriptionValue value = workReport
.getDescriptionValueByFieldName(valueDTO.fieldName);
value.setValue(StringUtils.trim(valueDTO.value));
} catch (InstanceNotFoundException e) {
throw new ValidationException(
"work report has not any description value with this field name");
}
}
}
/*
* 4: Update basic properties in existing work report
*/
/* Step 4.1: Update the date. */
Date date = DateConverter.toDate(workReportDTO.date);
workReport.setDate(date);
/* Step 4.2: Update the resource. */
String resourceCode = workReportDTO.resource;
if (!Strings.isBlank(resourceCode)) {
try {
Resource resource = Registry.getResourceDAO().findByCode(
resourceCode);
workReport.setResource(resource);
} catch (InstanceNotFoundException e) {
throw new ValidationException(
"There is no resource with this code");
}
}
/* Step 4.3: Update the order element. */
String orderElementCode = workReportDTO.orderElement;
if ((orderElementCode != null) && (!orderElementCode.isEmpty())) {
try {
OrderElement orderElement = Registry.getOrderElementDAO()
.findUniqueByCode(orderElementCode);
workReport.setOrderElement(orderElement);
} catch (InstanceNotFoundException e) {
throw new ValidationException("There is no task with this code");
}
}
}
public final static void updateWorkReportLine(
WorkReportLine workReportLine, WorkReportLineDTO workReportLineDTO)
throws ValidationException {
/*
* 1: Update the existing labels
*/
if (workReportLineDTO.labels != null) {
for (LabelReferenceDTO labelDTO : workReportLineDTO.labels) {
// * Step 2.1: requires each label reference DTO to have a code.
// */
if (StringUtils.isBlank(labelDTO.code)) {
throw new ValidationException("missing code in a label");
}
try {
Set<Label> labels = workReportLine.getLabels();
updateLabel(labelDTO, labels);
} catch (InstanceNotFoundException e) {
throw new ValidationException(
"there are not work report lines with assigned labels of this type");
}
}
}
/*
* 2: Update the existing description values
*/
updateDescriptionValues(workReportLineDTO.descriptionValues,
workReportLine);
/*
* 3: Update basic properties in existing work report line
*/
/* Step 3.1: Update the date. */
Date date = DateConverter.toDate(workReportLineDTO.date);
workReportLine.setDate(date);
/* Step 3.2: Update the resource. */
String resourceCode = workReportLineDTO.resource;
if (!Strings.isBlank(resourceCode)) {
try {
Resource resource = Registry.getResourceDAO().findByCode(
resourceCode);
workReportLine.setResource(resource);
} catch (InstanceNotFoundException e) {
throw new ValidationException(
"There is no resource with this code");
}
}
/* Step 3.3: Update the order element. */
String orderElementCode = workReportLineDTO.orderElement;
try {
OrderElement orderElement = Registry.getOrderElementDAO()
.findUniqueByCode(orderElementCode);
workReportLine.setOrderElement(orderElement);
} catch (InstanceNotFoundException e) {
throw new ValidationException("There is no task with this code");
}
/* Step 3.4: Update the type of work hours. */
if(workReportLineDTO.typeOfWorkHours != null){
try{
TypeOfWorkHours typeOfWorkHours = Registry.getTypeOfWorkHoursDAO().findUniqueByCode(workReportLineDTO.typeOfWorkHours);
workReportLine.setTypeOfWorkHours(typeOfWorkHours);
} catch (InstanceNotFoundException e) {
throw new ValidationException(
"There is no type of work hours with this code");
}
}
/*
* Step 3.4: Update the clock start and the clock end and the number of
* hours.
*/
if (workReportLineDTO.clockStart != null) {
workReportLine.setClockStart(DateConverter
.toLocalTime(workReportLineDTO.clockStart));
}
if (workReportLineDTO.clockFinish != null) {
workReportLine.setClockFinish(DateConverter
.toLocalTime(workReportLineDTO.clockFinish));
}
if (workReportLineDTO.numHours != null) {
workReportLine.setEffort(EffortDuration
.parseFromFormattedString(workReportLineDTO.numHours));
}
}
private static void updateDescriptionValues(
Set<DescriptionValueDTO> descriptionValues,
WorkReportLine workReportLine) {
if (descriptionValues != null) {
for (DescriptionValueDTO valueDTO : descriptionValues) {
/* Step 3.1: requires each description value DTO to have a code. */
if (StringUtils.isBlank(valueDTO.fieldName)) {
throw new ValidationException(
"missing field name in a description value");
}
try {
DescriptionValue value = workReportLine
.getDescriptionValueByFieldName(valueDTO.fieldName);
value.setValue(StringUtils.trim(valueDTO.value));
} catch (InstanceNotFoundException e) {
throw new ValidationException(
"work report have not any description value with this field name");
}
}
}
}
@Transactional
private static void updateLabel(LabelReferenceDTO labelDTO,
Set<Label> labels)
throws InstanceNotFoundException {
Label labelToAdd = Registry.getLabelDAO().findByCode(labelDTO.code);
LabelType labelType = labelToAdd.getType();
Label labelToChange = getLabelByLabelType(labels, labelType);
if (labelToAdd.getCode() != labelToChange.getCode()) {
labels.remove(labelToChange);
labels.add(labelToAdd);
}
}
private static Label getLabelByLabelType(Set<Label> labels, LabelType type)
throws InstanceNotFoundException {
Validate.notNull(type);
for (Label l : labels) {
if (l.getType().equals(type)) {
return l;
}
}
throw new InstanceNotFoundException(type, LabelType.class.getName());
}
}