package org.sigmah.server.service;
/*
* #%L
* Sigmah
* %%
* Copyright (C) 2010 - 2016 URD
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.sigmah.server.dao.ProjectReportDAO;
import org.sigmah.server.dispatch.impl.UserDispatch.UserExecutionContext;
import org.sigmah.server.domain.OrgUnit;
import org.sigmah.server.domain.Project;
import org.sigmah.server.domain.User;
import org.sigmah.server.domain.element.ReportElement;
import org.sigmah.server.domain.report.KeyQuestion;
import org.sigmah.server.domain.report.ProjectReport;
import org.sigmah.server.domain.report.ProjectReportModel;
import org.sigmah.server.domain.report.ProjectReportModelSection;
import org.sigmah.server.domain.report.ProjectReportVersion;
import org.sigmah.server.domain.report.RichTextElement;
import org.sigmah.server.domain.value.Value;
import org.sigmah.server.service.base.AbstractEntityService;
import org.sigmah.server.service.util.PropertyMap;
import org.sigmah.shared.dto.report.ProjectReportDTO;
import org.sigmah.shared.util.ValueResultUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.sigmah.server.domain.element.FlexibleElement;
import org.sigmah.server.domain.element.ReportListElement;
/**
* Handle the creation and the update procedure of the project reports.
*
* @author Raphaƫl Calabro (rcalabro@ideia.fr)
* @author Maxime Lombard (mlombard@ideia.fr)
* @author Denis Colliot (dcolliot@ideia.fr)
*/
@Singleton
public class ProjectReportService extends AbstractEntityService<ProjectReport, Integer, ProjectReportDTO> {
/**
* Logger.
*/
private static final Logger LOG = LoggerFactory.getLogger(ProjectService.class);
private final ProjectReportDAO dao;
private final ValueService valueService;
@Inject
public ProjectReportService(final ProjectReportDAO dao, final ValueService valueService) {
this.dao = dao;
this.valueService = valueService;
}
/**
* <p>
* Creates a new report.
* </p>
* <p>
* Requires the following properties :
* <ul>
* <li><code>name</code> - Name of the report.</li>
* <li><code>phaseName</code> - Name of the current phase.</li>
* <li><code>reportModelId</code> - ID of the project report model to use.</li>
* <li><code>projectId</code> - ID of the project owning the report.</li>
* <li><code>containerId</code> - ID of the project owning the report.</li>
* <li><code>flexibleElementId</code> - ID of the flexible element owning the report.</li>
* </ul>
* </p>
*
* @param properties
* Properties of the new report.
* @param context
* User context creating the report.
* @return The ID of the new report.
*/
@Override
public ProjectReport create(PropertyMap properties, final UserExecutionContext context) {
return createReport(context, properties);
}
/**
* Creates a new report version in draft mode.<br>
* <br>
* Requires the following properties :<br>
* <code>reportId</code> - ID of the report<br>
* <code>phaseName</code> - Name of the current phase.<br>
*
* @param user
* User creating the draft.
* @param properties
* Properties of the draft.
* @return The ID of the new draft.
*/
public Integer createDraft(User user, PropertyMap properties) {
return createReportDraft(user, properties).getId();
}
private void iterateOnSection(ProjectReportModelSection section, List<RichTextElement> elements, ProjectReportVersion version) {
int areaCount = section.getNumberOfTextarea();
// Key questions
List<KeyQuestion> keyQuestions = section.getKeyQuestions();
if (keyQuestions == null) {
keyQuestions = Collections.emptyList();
}
for (int index = 0; index < keyQuestions.size(); index++) {
final RichTextElement element = new RichTextElement();
element.setIndex(index);
element.setSectionId(section.getId());
element.setVersion(version);
elements.add(element);
}
int index = 0;
// Sub sections and rich text elements
List<ProjectReportModelSection> subSections = section.getSubSections();
if (subSections == null) {
subSections = Collections.emptyList();
}
for (final ProjectReportModelSection subSection : subSections) {
LOG.debug("Sub-section: {}", subSection);
while (index < subSection.getIndex() && areaCount > 0) {
// New rich text element
final RichTextElement element = new RichTextElement();
element.setIndex(index + keyQuestions.size());
element.setSectionId(section.getId());
element.setVersion(version);
elements.add(element);
index++;
areaCount--;
}
iterateOnSection(subSection, elements, version);
}
while (areaCount > 0) {
// New rich text element
final RichTextElement element = new RichTextElement();
element.setIndex(index + keyQuestions.size());
element.setSectionId(section.getId());
element.setVersion(version);
elements.add(element);
index++;
areaCount--;
}
}
protected ProjectReport createReport(final UserExecutionContext context, PropertyMap properties) {
final User user = context.getUser();
final ProjectReport report = new ProjectReport();
final ProjectReportVersion initialVersion = new ProjectReportVersion();
report.setCurrentVersion(initialVersion);
// Defining the common properties
report.setName((String) properties.get(ProjectReportDTO.NAME));
initialVersion.setReport(report);
initialVersion.setVersion(1);
initialVersion.setEditor(user);
initialVersion.setEditDate(new Date());
initialVersion.setPhaseName((String) properties.get(ProjectReportDTO.PHASE_NAME));
final ProjectReportModel model;
final Integer reportModelId = properties.get(ProjectReportDTO.REPORT_MODEL_ID);
if(reportModelId != null) {
model = dao.findModelById((Integer) properties.get(ProjectReportDTO.REPORT_MODEL_ID));
} else if(properties.get(ProjectReportDTO.FLEXIBLE_ELEMENT_ID) != null) {
final int flexibleElementId = properties.get(ProjectReportDTO.FLEXIBLE_ELEMENT_ID);
final FlexibleElement element = em().find(FlexibleElement.class, flexibleElementId);
if(element instanceof ReportListElement) {
model = ((ReportListElement) element).getModel();
} else if(element instanceof ReportElement) {
model = ((ReportElement) element).getModel();
} else {
model = null;
}
} else {
model = null;
}
if(model == null) {
throw new IllegalStateException("Impossible to find the requested project model.");
}
report.setModel(model);
final Integer projectId = (Integer) properties.get(ProjectReportDTO.PROJECT_ID);
if (projectId != null) {
final Project project = new Project();
project.setId(projectId);
report.setProject(project);
}
final Integer orgUnitId = (Integer) properties.get(ProjectReportDTO.ORGUNIT_ID);
if (orgUnitId != null) {
final OrgUnit orgUnit = new OrgUnit();
orgUnit.setId(orgUnitId);
report.setOrgUnit(orgUnit);
}
// Parent
final Integer flexibleElementId = (Integer) properties.get(ProjectReportDTO.FLEXIBLE_ELEMENT_ID);
final Integer containerId = (Integer) properties.get(ProjectReportDTO.CONTAINER_ID);
final boolean multiple;
if (properties.get(ProjectReportDTO.MULTIPLE) == null) {
multiple = false;
} else {
multiple = (Boolean) properties.get(ProjectReportDTO.MULTIPLE);
}
final Value flexibleElementValue;
if (flexibleElementId != null && containerId != null) {
final ReportElement element = new ReportElement();
element.setId(flexibleElementId);
report.setFlexibleElement(element);
flexibleElementValue = valueService.retrieveOrCreateValue(containerId, flexibleElementId, user);
if (!multiple && !(flexibleElementValue == null || flexibleElementValue.getValue() == null || "".equals(flexibleElementValue.getValue()))) {
throw new IllegalStateException("A report has already been created for the flexible element " + flexibleElementId);
}
} else {
flexibleElementValue = null;
}
// RichTextElements
final ArrayList<RichTextElement> elements = new ArrayList<RichTextElement>();
for (final ProjectReportModelSection section : model.getSections()) {
iterateOnSection(section, elements, initialVersion);
}
initialVersion.setTexts(elements);
// Saving
dao.persist(report, user);
// Updating the flexible element
if (flexibleElementValue != null) {
final String value;
if (multiple && flexibleElementValue.getValue() != null) {
// Multiple values mode
value = flexibleElementValue.getValue() + ValueResultUtils.DEFAULT_VALUE_SEPARATOR + report.getId().toString();
} else {
// Single value mode
value = report.getId().toString();
}
flexibleElementValue.setValue(value);
dao.merge(flexibleElementValue);
}
return report;
}
protected ProjectReportVersion createReportDraft(User user, PropertyMap properties) {
final ProjectReportVersion version = new ProjectReportVersion();
version.setEditor(user);
version.setEditDate(new Date());
version.setPhaseName((String) properties.get(ProjectReportDTO.PHASE_NAME));
// Linking the draft to the report
final ProjectReport report = dao.findReportById((Integer) properties.get(ProjectReportDTO.REPORT_ID));
version.setReport(report);
// Copying the current values
final ArrayList<RichTextElement> texts = new ArrayList<RichTextElement>();
final List<RichTextElement> currentTexts = report.getCurrentVersion().getTexts();
for (final RichTextElement text : currentTexts) {
final RichTextElement element = text.duplicate();
element.setVersion(version);
texts.add(element);
}
version.setTexts(texts);
// Saving
dao.persist(version);
return version;
}
/**
* {@inheritDoc}
*/
@Override
public ProjectReport update(Integer entityId, PropertyMap changes, final UserExecutionContext context) {
for (final Map.Entry<String, Object> entry : changes.entrySet()) {
if (ProjectReportDTO.CURRENT_PHASE.equals(entry.getKey())) {
final ProjectReportVersion version = dao.findReportVersionById(entityId);
version.setPhaseName((String) entry.getValue());
version.setEditor(context.getUser());
version.setEditDate(new Date());
dao.merge(version);
} else {
final RichTextElement element = dao.findRichTextElementById(new Integer(entry.getKey()));
element.setText((String) entry.getValue());
dao.merge(element);
}
}
return dao.findById(entityId);
}
}