/*
* OpenClinica is distributed under the
* GNU Lesser General Public License (GNU LGPL).
* For details see: http://www.openclinica.org/license
* copyright 2003-2005 Akaza Research
*/
package org.akaza.openclinica.control.managestudy;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.akaza.openclinica.bean.admin.CRFBean;
import org.akaza.openclinica.bean.core.Role;
import org.akaza.openclinica.bean.core.Status;
import org.akaza.openclinica.bean.core.Utils;
import org.akaza.openclinica.bean.login.StudyUserRoleBean;
import org.akaza.openclinica.bean.login.UserAccountBean;
import org.akaza.openclinica.bean.managestudy.EventDefinitionCRFBean;
import org.akaza.openclinica.bean.managestudy.StudyBean;
import org.akaza.openclinica.bean.managestudy.StudyEventBean;
import org.akaza.openclinica.bean.managestudy.StudyEventDefinitionBean;
import org.akaza.openclinica.bean.managestudy.StudySubjectBean;
import org.akaza.openclinica.bean.submit.CRFVersionBean;
import org.akaza.openclinica.bean.submit.DisplayItemBean;
import org.akaza.openclinica.bean.submit.DisplayItemGroupBean;
import org.akaza.openclinica.bean.submit.DisplaySectionBean;
import org.akaza.openclinica.bean.submit.DisplayTableOfContentsBean;
import org.akaza.openclinica.bean.submit.EventCRFBean;
import org.akaza.openclinica.bean.submit.ItemBean;
import org.akaza.openclinica.bean.submit.ItemFormMetadataBean;
import org.akaza.openclinica.bean.submit.SectionBean;
import org.akaza.openclinica.bean.submit.SubjectBean;
import org.akaza.openclinica.control.form.DiscrepancyValidator;
import org.akaza.openclinica.control.form.FormProcessor;
import org.akaza.openclinica.control.submit.DataEntryServlet;
import org.akaza.openclinica.dao.managestudy.StudyDAO;
import org.akaza.openclinica.dao.managestudy.StudyEventDAO;
import org.akaza.openclinica.dao.managestudy.StudyEventDefinitionDAO;
import org.akaza.openclinica.dao.managestudy.StudySubjectDAO;
import org.akaza.openclinica.dao.submit.SubjectDAO;
import org.akaza.openclinica.view.Page;
import org.akaza.openclinica.web.InsufficientPermissionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Bruce W. Perry
*
* Preview a CRF version section data entry. This class is based almost entirely
* on ViewSectionDataEntryServlet; Except that it's designed to provide a
* preview of a crf before the crfversion is inserted into the database.
*/
public class ViewSectionDataEntryPreview extends DataEntryServlet {
private static final Logger LOGGER = LoggerFactory.getLogger(ViewSectionDataEntryPreview.class);
public static String SECTION_TITLE = "section_title";
public static String SECTION_LABEL = "section_label";
public static String SECTION_SUBTITLE = "subtitle";
public static String INSTRUCTIONS = "instructions";
public static String BORDERS = "borders";
/**
* Checks whether the user has the correct privilege. This is from
* ViewSectionDataEntryServlet.
*/
@Override
public void mayProceed(HttpServletRequest request, HttpServletResponse response) throws InsufficientPermissionException {
UserAccountBean ub =(UserAccountBean) request.getSession().getAttribute(USER_BEAN_NAME);
StudyUserRoleBean currentRole = (StudyUserRoleBean) request.getSession().getAttribute("userRole");
if (ub.isSysAdmin()) {
return;
}
if (currentRole.getRole().equals(Role.STUDYDIRECTOR) || currentRole.getRole().equals(Role.COORDINATOR)
|| currentRole.getRole().equals(Role.INVESTIGATOR) || currentRole.getRole().equals(Role.RESEARCHASSISTANT) || currentRole.getRole().equals(Role.RESEARCHASSISTANT2)) {
return;
}
addPageMessage(respage.getString("no_have_correct_privilege_current_study") + " " + respage.getString("change_active_study_or_contact"), request);
throw new InsufficientPermissionException(Page.MENU_SERVLET, resexception.getString("not_director"), "1");
}
@Override
public void processRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
FormProcessor fp = new FormProcessor(request);
EventCRFBean ecb = (EventCRFBean)request.getAttribute(INPUT_EVENT_CRF);
SectionBean sb = (SectionBean)request.getAttribute(SECTION_BEAN);
// These numbers will be zero if the
// params are not present in the URL
int crfid = fp.getInt("crfId");
int tabNum = fp.getInt("tabId");
HttpSession session = request.getSession();
request.setAttribute("crfId", crfid);
String crfName = "";
String verNumber = "";
// All the data on the uploaded Excel file
// see org.akaza.openclinica.control.admin.SpreadsheetPreview
// createCrfMetaObject() method
Map<String, Map> crfMap = (Map) session.getAttribute("preview_crf");
if (crfMap == null) {
// addPageMessage
String msg = respage.getString("preview_data_has_timed_out");
this.addPageMessage(msg, request);
LOGGER.debug("The session attribute \"preview_crf\" has expired or gone out of scope in: " + this.getClass().getName());
this.forwardPage(Page.CRF_LIST_SERVLET, request, response);
}
Map<String, String> crfIdnameInfo = null;
if (crfMap != null) {
crfIdnameInfo = crfMap.get("crf_info");
}
// Get the CRF name and version String
if (crfIdnameInfo != null) {
Map.Entry mapEnt = null;
for (Object element : crfIdnameInfo.entrySet()) {
mapEnt = (Map.Entry) element;
if (((String) mapEnt.getKey()).equalsIgnoreCase("crf_name")) {
crfName = (String) mapEnt.getValue();
}
if (((String) mapEnt.getKey()).equalsIgnoreCase("version")) {
verNumber = (String) mapEnt.getValue();
}
}
}
// Set up the beans that DisplaySectionBean and the preview
// depend on
EventCRFBean ebean = new EventCRFBean();
CRFVersionBean crfverBean = new CRFVersionBean();
crfverBean.setName(verNumber);
CRFBean crfbean = new CRFBean();
crfbean.setId(crfid);
crfbean.setName(crfName);
ebean.setCrf(crfbean);
// This happens in ViewSectionDataEntry
// It's an assumption that it has to happen here as well
ecb = ebean;
// All the groups data, if it's present in the CRF
Map<Integer, Map<String, String>> groupsMap = null;
if (crfMap != null)
groupsMap = crfMap.get("groups");
// Find out whether this CRF involves groups
// At least one group is involved if the groups Map is not null or
// empty, and the first group entry (there may be only one) has a
// valid group label
boolean hasGroups = false;
/*
* if(groupsMap != null && (! groupsMap.isEmpty()) &&
* groupsMap.get(1).get("group_label").length() > 0) hasGroups = true;
*/
// A SortedMap containing the row number as the key, and the
// section headers/values (contained in a Map) as the value
Map<Integer, Map<String, String>> sectionsMap = null;
if (crfMap != null)
sectionsMap = crfMap.get("sections");
// The itemsMap contains the spreadsheet table items row number as a
// key,
// followed by a map of the column names/values; it contains values for
// display
// such as 'left item text'
Map<Integer, Map<String, String>> itemsMap = null;
if (crfMap != null)
itemsMap = crfMap.get("items");
// Create a list of FormGroupBeans from Maps of groups,
// items, and sections
BeanFactory beanFactory = new BeanFactory();
// FormBeanUtil formUtil = new FormBeanUtil();
// Set up sections for the preview
Map.Entry me = null;
SectionBean secbean = null;
ArrayList<SectionBean> allSectionBeans = new ArrayList<SectionBean>();
String name_str = "";
String pageNum = "";
Map secMap = null;
// SpreadsheetPreviewNw returns doubles (via the
// HSSFCell API, which parses Excel files)
// as Strings (such as "1.0") for "1" in a spreadsheet cell,
// so make sure only "1" is displayed using
// this NumberFormat object
NumberFormat numFormatter = NumberFormat.getInstance();
numFormatter.setMaximumFractionDigits(0);
if (sectionsMap != null) {
for (Object element : sectionsMap.entrySet()) {
secbean = new SectionBean();
me = (Map.Entry) element;
secMap = (Map) me.getValue();
name_str = (String) secMap.get("section_label");
secbean.setName(name_str);
secbean.setTitle((String) secMap.get("section_title"));
secbean.setInstructions((String) secMap.get("instructions"));
secbean.setSubtitle((String) secMap.get("subtitle"));
pageNum = (String) secMap.get("page_number");
// ensure pageNum is an actual number; the user is not required
// to
// type a number in that Spreadsheet cell
try {
pageNum = numFormatter.format(Double.parseDouble(pageNum));
} catch (NumberFormatException nfe) {
pageNum = "";
}
secbean.setPageNumberLabel(pageNum);
// Sift through the items to see if their section label matches
// the section's section_label column
secbean.setNumItems(this.getNumberOfItems(itemsMap, secbean.getName()));
allSectionBeans.add(secbean);
}
}
DisplayTableOfContentsBean dtocBean = new DisplayTableOfContentsBean();
// Methods should just take Lists, the interface, not
// ArrayList only!
dtocBean.setSections(allSectionBeans);
request.setAttribute("toc", dtocBean);
request.setAttribute("sectionNum", allSectionBeans.size() + "");
// Assuming that the super class' SectionBean sb variable must be
// initialized,
// since it happens in ViewSectionDataEntryServlet. TODO: verify this
sb = allSectionBeans.get(0);
// This is the StudySubjectBean
// Not sure if this is needed for a Preview, but leaving
// it in for safety/consisitency reasons
request.setAttribute(INPUT_EVENT_CRF, ecb);
request.setAttribute(SECTION_BEAN,sb);
setupStudyBean(request);
// Create a DisplaySectionBean for the SectionBean specified by the
// tab number.
tabNum = tabNum == 0 ? 1 : tabNum;
String sectionTitle = getSectionColumnBySecNum(sectionsMap, tabNum, SECTION_TITLE);
String secLabel = getSectionColumnBySecNum(sectionsMap, tabNum, SECTION_LABEL);
String secSubtitle = getSectionColumnBySecNum(sectionsMap, tabNum, SECTION_SUBTITLE);
String instructions = getSectionColumnBySecNum(sectionsMap, tabNum, INSTRUCTIONS);
int secBorders = getSectionBordersBySecNum(sectionsMap, tabNum, BORDERS);
DisplaySectionBean displaySection =
beanFactory.createDisplaySectionBean(itemsMap, sectionTitle, secLabel, secSubtitle, instructions, crfName, secBorders);
//
// the variable hasGroups should only be true if the group appears in
// this section
List<DisplayItemBean> disBeans = displaySection.getItems();
ItemFormMetadataBean metaBean;
String groupLabel;
hasGroups = false;
for (DisplayItemBean diBean : disBeans) {
metaBean = diBean.getMetadata();
groupLabel = metaBean.getGroupLabel();
if (groupLabel != null && groupLabel.length() > 0) {
hasGroups = true;
break;
}
}
// Create groups associated with this section
List<DisplayItemGroupBean> disFormGroupBeans = null;
if (hasGroups) {
disFormGroupBeans = beanFactory.createGroupBeans(itemsMap, groupsMap, secLabel, crfName);
displaySection.setDisplayFormGroups(disFormGroupBeans);
}
/*
* DisplaySectionBean displaySection =
* beanFactory.createDisplaySectionBean (itemsMap, sectionTitle,
* secLabel, secSubtitle, instructions, crfName);
*/
displaySection.setCrfVersion(crfverBean);
displaySection.setCrf(crfbean);
displaySection.setEventCRF(ebean);
// Not sure if this is needed? The JSPs pull it out
// as a request attribute
SectionBean aSecBean = new SectionBean();
request.setAttribute(BEAN_DISPLAY, displaySection);
// TODO: verify these attributes, from the original servlet, are
// necessary
request.setAttribute("sec", aSecBean);
request.setAttribute("EventCRFBean", ebean);
try {
request.setAttribute("tabId", Integer.toString(tabNum));
} catch (NumberFormatException nfe) {
request.setAttribute("tabId", new Integer("1"));
}
if (hasGroups) {
LOGGER.debug("has group, new_table is true");
request.setAttribute("new_table", true);
}
// YW 07-23-2007 << for issue 0000937
forwardPage(Page.CREATE_CRF_VERSION_CONFIRM, request, response);
// YW >>
}
// Get a Section's title by its key number in the sectionsMap; i.e., what is
// the title
// of the first section in the CRF?
private String getSectionColumnBySecNum(Map sectionsMap, int sectionNum, String sectionColumn) {
if (sectionsMap == null || sectionColumn == null || sectionColumn.length() < 1) {
return "";
}
Map innerMap = (Map) sectionsMap.get(sectionNum);
return (String) innerMap.get(sectionColumn);
}
private int getSectionBordersBySecNum(Map sectionsMap, int sectionNum, String sectionColumn) {
if (sectionsMap == null || sectionColumn == null || sectionColumn.length() < 1) {
return 0;
}
Map innerMap = (Map) sectionsMap.get(sectionNum);
String tempBorder = (String) innerMap.get(sectionColumn);
// if the section borders property in the CRF template
// is blank, return 0
if (tempBorder != null && tempBorder.length() < 1) {
return 0;
}
// if the borders property is null, return 0; otherwise return the value stored
// in the HashMap
if (tempBorder != null) {
return new Integer(tempBorder);
} else {
return 0;
}
}
/*
* private String getSectionTitleBySecNum(Map sectionsMap, int sectionNum){
* if(sectionsMap==null) return ""; Map innerMap = (Map)sectionsMap.get(new
* Integer(sectionNum)); return (String)innerMap.get("section_title"); }
* private String getSectionLabelBySecNum(Map sectionsMap, int sectionNum){
* if(sectionsMap==null) return ""; Map innerMap = (Map)sectionsMap.get(new
* Integer(sectionNum)); return (String)innerMap.get("section_label"); }
* private String getSectionSubtitleBySecNum(Map sectionsMap, int
* sectionNum){ if(sectionsMap==null) return ""; Map innerMap =
* (Map)sectionsMap.get(new Integer(sectionNum)); return
* (String)innerMap.get("subtitle"); } private String
* getInstructionsBySecNum(Map sectionsMap, int sectionNum){
* if(sectionsMap==null) return ""; Map innerMap = (Map)sectionsMap.get(new
* Integer(sectionNum)); return (String)innerMap.get("instructions"); }
*/
// Determine the number of items associated with this section
// by checking the page number value of each item, and comparing it
// with the page number of the section
private int getNumberOfItems(Map itemsMap, String sectionLabel) {
if (itemsMap == null)
return 0;
int itemCount = 0;
Map itemVals = null;
Map.Entry me = null;
Map.Entry me2 = null;
String columnName = "";
String val = "";
for (Iterator iter = itemsMap.entrySet().iterator(); iter.hasNext();) {
me = (Map.Entry) iter.next();
itemVals = (Map) me.getValue();
// each Map member is a key/value pair representing an
// item column/value
for (Iterator iter2 = itemVals.entrySet().iterator(); iter2.hasNext();) {
me2 = (Map.Entry) iter2.next();
columnName = (String) me2.getKey();
val = (String) me2.getValue();
if (columnName.equalsIgnoreCase("section_label")) {
if (val.equalsIgnoreCase(sectionLabel))
itemCount++;
}
}
}
return itemCount;
}
private void setupStudyBean(HttpServletRequest request) {
String age = "";
EventCRFBean ecb = (EventCRFBean)request.getAttribute(INPUT_EVENT_CRF);
StudySubjectDAO ssdao = new StudySubjectDAO(getDataSource());
StudySubjectBean sub = (StudySubjectBean) ssdao.findByPK(ecb.getStudySubjectId());
// This is the SubjectBean
SubjectDAO subjectDao = new SubjectDAO(getDataSource());
int subjectId = sub.getSubjectId();
int studyId = sub.getStudyId();
SubjectBean subject = (SubjectBean) subjectDao.findByPK(subjectId);
StudyBean currentStudy = (StudyBean) request.getSession().getAttribute("study");
// Let us process the age
if (currentStudy.getStudyParameterConfig().getCollectDob().equals("1")) {
StudyEventDAO sedao = new StudyEventDAO(getDataSource());
StudyEventBean se = (StudyEventBean) sedao.findByPK(ecb.getStudyEventId());
StudyEventDefinitionDAO seddao = new StudyEventDefinitionDAO(getDataSource());
StudyEventDefinitionBean sed = (StudyEventDefinitionBean) seddao.findByPK(se.getStudyEventDefinitionId());
se.setStudyEventDefinition(sed);
request.setAttribute("studyEvent", se);
// YW 11-16-2007 enrollment-date is used for calculating age
age = Utils.getInstacne().processAge(sub.getEnrollmentDate(), subject.getDateOfBirth());
}
// Get the study then the parent study
StudyDAO studydao = new StudyDAO(getDataSource());
StudyBean study = (StudyBean) studydao.findByPK(studyId);
if (study.getParentStudyId() > 0) {
// this is a site,find parent
StudyBean parentStudy = (StudyBean) studydao.findByPK(study.getParentStudyId());
request.setAttribute("studyTitle", parentStudy.getName() + " - " + study.getName());
} else {
request.setAttribute("studyTitle", study.getName());
}
request.setAttribute("studySubject", sub);
request.setAttribute("subject", subject);
request.setAttribute("age", age);
}
/*
* (non-Javadoc)
*
* @see org.akaza.openclinica.control.submit.DataEntryServlet#getBlankItemStatus()
*/
@Override
protected Status getBlankItemStatus() {
return Status.AVAILABLE;
}
/*
* (non-Javadoc)
*
* @see org.akaza.openclinica.control.submit.DataEntryServlet#getNonBlankItemStatus()
*/
@Override
protected Status getNonBlankItemStatus(HttpServletRequest request) {
EventDefinitionCRFBean edcb = (EventDefinitionCRFBean)request.getAttribute(EVENT_DEF_CRF_BEAN);
return edcb.isDoubleEntry() ? Status.PENDING : Status.UNAVAILABLE;
}
/*
* (non-Javadoc)
*
* @see org.akaza.openclinica.control.submit.DataEntryServlet#getEventCRFAnnotations()
*/
@Override
protected String getEventCRFAnnotations(HttpServletRequest request) {
EventCRFBean ecb = (EventCRFBean)request.getAttribute(INPUT_EVENT_CRF);
return ecb.getAnnotations();
}
/*
* (non-Javadoc)
*
* @see org.akaza.openclinica.control.submit.DataEntryServlet#setEventCRFAnnotations(java.lang.String)
*/
@Override
protected void setEventCRFAnnotations(String annotations, HttpServletRequest request) {
EventCRFBean ecb = (EventCRFBean)request.getAttribute(INPUT_EVENT_CRF);
ecb.setAnnotations(annotations);
}
/*
* (non-Javadoc)
*
* @see org.akaza.openclinica.control.submit.DataEntryServlet#getJSPPage()
*/
@Override
protected Page getJSPPage() {
return Page.VIEW_SECTION_DATA_ENTRY;
}
/*
* (non-Javadoc)
*
* @see org.akaza.openclinica.control.submit.DataEntryServlet#getServletPage()
*/
@Override
protected String getServletPage(HttpServletRequest request) {
return Page.VIEW_SECTION_DATA_ENTRY_SERVLET.getFileName();
}
/*
* (non-Javadoc)
*
* @see org.akaza.openclinica.control.submit.DataEntryServlet#validateInputOnFirstRound()
*/
@Override
protected boolean validateInputOnFirstRound() {
return true;
}
/*
* (non-Javadoc)
*
* @see org.akaza.openclinica.control.submit.DataEntryServlet#validateDisplayItemBean(org.akaza.openclinica.core.form.Validator,
* org.akaza.openclinica.bean.submit.DisplayItemBean)
*/
@Override
protected DisplayItemBean validateDisplayItemBean(DiscrepancyValidator v, DisplayItemBean dib, String inputName, HttpServletRequest request) {
ItemBean ib = dib.getItem();
org.akaza.openclinica.bean.core.ResponseType rt = dib.getMetadata().getResponseSet().getResponseType();
// note that this step sets us up both for
// displaying the data on the form again, in the event of an error
// and sending the data to the database, in the event of no error
dib = loadFormValue(dib, request);
// types TEL and ED are not supported yet
if (rt.equals(org.akaza.openclinica.bean.core.ResponseType.TEXT) || rt.equals(org.akaza.openclinica.bean.core.ResponseType.TEXTAREA)
|| rt.equals(org.akaza.openclinica.bean.core.ResponseType.CALCULATION) || rt.equals(org.akaza.openclinica.bean.core.ResponseType.GROUP_CALCULATION)) {
dib = validateDisplayItemBeanText(v, dib, inputName, request);
} else if (rt.equals(org.akaza.openclinica.bean.core.ResponseType.RADIO) || rt.equals(org.akaza.openclinica.bean.core.ResponseType.SELECT)) {
dib = validateDisplayItemBeanSingleCV(v, dib, inputName);
} else if (rt.equals(org.akaza.openclinica.bean.core.ResponseType.CHECKBOX) || rt.equals(org.akaza.openclinica.bean.core.ResponseType.SELECTMULTI)) {
dib = validateDisplayItemBeanMultipleCV(v, dib, inputName);
}
return dib;
}
@Override
protected List<DisplayItemGroupBean> validateDisplayItemGroupBean(DiscrepancyValidator v, DisplayItemGroupBean digb, List<DisplayItemGroupBean> digbs,
List<DisplayItemGroupBean> formGroups, HttpServletRequest request, HttpServletResponse response) {
return formGroups;
}
/*
* (non-Javadoc)
*
* @see org.akaza.openclinica.control.submit.DataEntryServlet#loadDBValues()
*/
@Override
protected boolean shouldLoadDBValues(DisplayItemBean dib) {
return true;
}
@Override
protected boolean shouldRunRules() {
return false;
}
@Override
protected boolean isAdministrativeEditing() {
return false;
}
@Override
protected boolean isAdminForcedReasonForChange(HttpServletRequest request) {
return false;
}
}