/**
* The contents of this file are subject to the OpenMRS Public License
* Version 1.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://license.openmrs.org
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* Copyright (C) OpenMRS, LLC. All Rights Reserved.
*/
package org.openmrs.module.reporting.web.datasets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Properties;
import javax.servlet.http.HttpSession;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.api.context.Context;
import org.openmrs.module.htmlwidgets.web.WidgetUtil;
import org.openmrs.module.htmlwidgets.web.html.Option;
import org.openmrs.module.reporting.cohort.definition.CohortDefinition;
import org.openmrs.module.reporting.common.ObjectUtil;
import org.openmrs.module.reporting.data.DataDefinition;
import org.openmrs.module.reporting.data.patient.definition.PatientDataDefinition;
import org.openmrs.module.reporting.data.person.definition.PersonDataDefinition;
import org.openmrs.module.reporting.dataset.column.definition.RowPerObjectColumnDefinition;
import org.openmrs.module.reporting.dataset.definition.PatientDataSetDefinition;
import org.openmrs.module.reporting.dataset.definition.service.DataSetDefinitionService;
import org.openmrs.module.reporting.evaluation.parameter.Mapped;
import org.openmrs.module.reporting.evaluation.parameter.Parameter;
import org.openmrs.module.reporting.propertyeditor.MappedEditor;
import org.openmrs.module.reporting.web.util.ParameterUtil;
import org.openmrs.web.WebConstants;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.context.request.WebRequest;
/**
* For creating and editing {@link PatientDataSetDefinition}s
*/
@Controller
public class PatientDataSetEditor {
public final static String DSD_ATTR = "PatientDataSetEditor_dsd";
public final static String IS_UNSAVED_ATTR = "PatientDataSetEditor_is_unsaved";
public final static String SUCCESS_URL_ATTR = "PatientDataSetEditor_successUrl";
public final static String DISCARD_URL_ATTR = "PatientDataSetEditor_discardUrl";
Log log = LogFactory.getLog(getClass());
@ModelAttribute("dsd")
public PatientDataSetDefinition getDataSetDefinition(@RequestParam(required=false, value="uuid") String uuid,
@RequestParam(required=false) String successUrl,
@RequestParam(required=false) String discardUrl, HttpSession session) {
PatientDataSetDefinition dsd = getFromSession(session);
if (dsd != null && uuid != null && !uuid.equals(dsd.getUuid())) {
removeFromSession(session);
dsd = null;
}
if (dsd == null) {
if (uuid != null) {
dsd = (PatientDataSetDefinition) Context.getService(DataSetDefinitionService.class).getDefinitionByUuid(uuid);
if (dsd == null)
throw new RuntimeException("No PatientDataSetDefinition found with uuid " + uuid);
putInSession(session, dsd, false);
} else {
dsd = new PatientDataSetDefinition();
dsd.setName("Untitled");
putInSession(session, dsd, true);
}
}
if (!StringUtils.isBlank(successUrl)) {
session.setAttribute(SUCCESS_URL_ATTR, successUrl);
}
if (!StringUtils.isBlank(discardUrl)) {
session.setAttribute(DISCARD_URL_ATTR, discardUrl);
}
return dsd;
}
@ModelAttribute("parameterTypes")
public List<Option> getAvailableParameterTypes() {
return ParameterUtil.getSupportedTypes();
}
@ModelAttribute("parameterCollectionTypes")
public List<Option> getAvailableParameterCollectionTypes() {
return ParameterUtil.getSupportedCollectionTypes();
}
private void putInSession(HttpSession session, PatientDataSetDefinition dsd, boolean isUnsaved) {
session.setAttribute(DSD_ATTR, dsd);
session.setAttribute(IS_UNSAVED_ATTR, isUnsaved);
}
private void removeFromSession(HttpSession session) {
session.removeAttribute(DSD_ATTR);
session.removeAttribute(IS_UNSAVED_ATTR);
session.removeAttribute(SUCCESS_URL_ATTR);
session.removeAttribute(DISCARD_URL_ATTR);
}
private PatientDataSetDefinition getFromSession(HttpSession session) {
try {
return (PatientDataSetDefinition) session.getAttribute(DSD_ATTR);
} catch (ClassCastException ex) {
// module has been reloaded
removeFromSession(session);
return null;
}
}
@RequestMapping("/module/reporting/datasets/patientDataSetEditor")
public void showDataset(HttpSession session,
Model model) {
model.addAttribute("unsaved", session.getAttribute(IS_UNSAVED_ATTR));
model.addAttribute("dsd", session.getAttribute(DSD_ATTR));
model.addAttribute("dataDefinitionTypes", PatientDataDefinition.class.getName() + "," + PersonDataDefinition.class.getName());
}
@RequestMapping(value="/module/reporting/datasets/patientDataSetEditor-nameDescription", method=RequestMethod.POST)
public String changeNameAndDescription(@RequestParam("name") String name,
@RequestParam("description") String description,
HttpSession session) {
PatientDataSetDefinition dsd = getFromSession(session);
dsd.setName(name);
dsd.setDescription(description);
putInSession(session, dsd, true);
return "redirect:patientDataSetEditor.form";
}
@RequestMapping(value="/module/reporting/datasets/patientDataSetEditor-addParam", method=RequestMethod.POST)
public String addParameter(@RequestParam(value="collectionType", required=false) Class<? extends Collection<?>> collectionType,
@RequestParam(value="parameterType", required=false) Class<?> parameterType,
@RequestParam(value="name", required=false) String name,
@RequestParam(value="label", required=false) String label,
@RequestParam(value="widgetConfiguration", required=false) String widgetConfiguration,
HttpSession session) {
if (parameterType == null || name == null || label == null) {
session.setAttribute(WebConstants.OPENMRS_ERROR_ATTR, "Type, Name, and Label are required");
return "redirect:patientDataSetEditor.form";
}
Properties widgetConfig = null;
if (ObjectUtil.notNull(widgetConfiguration)) {
widgetConfig = WidgetUtil.parseInput(widgetConfiguration, Properties.class);
}
PatientDataSetDefinition dsd = getFromSession(session);
dsd.addParameter(new Parameter(name, label, parameterType, collectionType, null, widgetConfig));
putInSession(session, dsd, true);
return "redirect:patientDataSetEditor.form";
}
@RequestMapping(value="/module/reporting/datasets/patientDataSetEditor-removeParam", method=RequestMethod.POST)
public String removeParameter(@RequestParam("name") String name,
HttpSession session) {
PatientDataSetDefinition dsd = getFromSession(session);
dsd.removeParameter(name);
putInSession(session, dsd, true);
return "redirect:patientDataSetEditor.form";
}
@RequestMapping(value="/module/reporting/datasets/patientDataSetEditor-addColumn", method=RequestMethod.POST)
public String addColumn(@RequestParam(value="label", required=false) String label,
@RequestParam(value="columnDefinition", required=false) String columnDefinition,
HttpSession session) {
if (StringUtils.isBlank(label) || StringUtils.isBlank(columnDefinition)) {
session.setAttribute(WebConstants.OPENMRS_ERROR_ATTR, "Label and Definition are required");
return "redirect:patientDataSetEditor.form";
}
PatientDataSetDefinition dsd = getFromSession(session);
for (RowPerObjectColumnDefinition col : dsd.getColumnDefinitions()) {
if (label.equals(col.getName())) {
session.setAttribute(WebConstants.OPENMRS_ERROR_ATTR, "There is already a column named '" + label + "'");
return "redirect:patientDataSetEditor.form";
}
}
MappedEditor editor = new MappedEditor();
editor.setAsText(columnDefinition);
Mapped<DataDefinition> mappedDef = (Mapped<DataDefinition>) editor.getValue();
dsd.addColumn(label, mappedDef.getParameterizable(), mappedDef.getParameterMappings());
putInSession(session, dsd, true);
return "redirect:patientDataSetEditor.form";
}
@RequestMapping(value="/module/reporting/datasets/patientDataSetEditor-removeColumn", method=RequestMethod.POST)
public String removeColumn(@RequestParam("name") String name,
HttpSession session) {
PatientDataSetDefinition dsd = getFromSession(session);
dsd.removeColumnDefinition(name);
putInSession(session, dsd, true);
return "redirect:patientDataSetEditor.form";
}
@RequestMapping(value="/module/reporting/datasets/patientDataSetEditor-addFilter", method=RequestMethod.POST)
public String addFilter(@RequestParam(value="filterDefinition", required=false) String filterDefinition,
HttpSession session) {
if (StringUtils.isBlank(filterDefinition)) {
session.setAttribute(WebConstants.OPENMRS_ERROR_ATTR, "Definition is required");
return "redirect:patientDataSetEditor.form";
}
PatientDataSetDefinition dsd = getFromSession(session);
MappedEditor editor = new MappedEditor();
editor.setAsText(filterDefinition);
Mapped<CohortDefinition> mappedDef = (Mapped<CohortDefinition>) editor.getValue();
dsd.addRowFilter(mappedDef);
putInSession(session, dsd, true);
return "redirect:patientDataSetEditor.form";
}
@RequestMapping(value="/module/reporting/datasets/patientDataSetEditor-removeFilter", method=RequestMethod.POST)
public String removeFilter(@RequestParam("filterIndex") int index,
HttpSession session) {
PatientDataSetDefinition dsd = getFromSession(session);
dsd.getRowFilters().remove(index);
putInSession(session, dsd, true);
return "redirect:patientDataSetEditor.form";
}
@RequestMapping(value="/module/reporting/datasets/patientDataSetEditor-sortColumns", method=RequestMethod.POST)
public String sortColumns(WebRequest request,
HttpSession session) {
final List<String> columnOrder = new ArrayList<String>();
int i = 0;
while (true) {
String colName = request.getParameter("column" + i);
if (colName == null)
break;
columnOrder.add(colName);
++i;
}
PatientDataSetDefinition dsd = getFromSession(session);
Collections.sort(dsd.getColumnDefinitions(), new Comparator<RowPerObjectColumnDefinition>() {
public int compare(RowPerObjectColumnDefinition left, RowPerObjectColumnDefinition right) {
Integer leftIndex = columnOrder.indexOf(left.getName());
Integer rightIndex = columnOrder.indexOf(right.getName());
return leftIndex.compareTo(rightIndex);
}
});
putInSession(session, dsd, true);
return "redirect:patientDataSetEditor.form";
}
@RequestMapping(value="/module/reporting/datasets/patientDataSetEditor-save", method=RequestMethod.POST)
public String save(HttpSession session) {
PatientDataSetDefinition dsd = getFromSession(session);
String successUrl = (String) session.getAttribute(SUCCESS_URL_ATTR);
Context.getService(DataSetDefinitionService.class).saveDefinition(dsd);
removeFromSession(session);
if (!StringUtils.isBlank(successUrl)) {
return "redirect:" + successUrl;
} else {
return "redirect:patientDataSetEditor.form?uuid=" + dsd.getUuid();
}
}
@RequestMapping(value="/module/reporting/datasets/patientDataSetEditor-discard", method=RequestMethod.POST)
public String discard(HttpSession session) {
String discardUrl = (String) session.getAttribute(DISCARD_URL_ATTR);
removeFromSession(session);
if (!StringUtils.isBlank(discardUrl)) {
return "redirect:" + discardUrl;
} else {
return "redirect:/module/reporting/definition/manageDefinitions.form?type=org.openmrs.module.reporting.dataset.definition.DataSetDefinition";
}
}
}