package org.akaza.openclinica.control.managestudy;
import org.akaza.openclinica.bean.core.ItemDataType;
import org.akaza.openclinica.bean.core.ResponseType;
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.ItemBean;
import org.akaza.openclinica.bean.submit.ItemFormMetadataBean;
import org.akaza.openclinica.bean.submit.ItemGroupBean;
import org.akaza.openclinica.bean.submit.ItemGroupMetadataBean;
import org.akaza.openclinica.bean.submit.ResponseSetBean;
import org.akaza.openclinica.bean.submit.SectionBean;
import org.akaza.openclinica.core.form.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* BeanFactory contains methods for generating beans representing non-persistent
* data. the data derives largely from spreadsheets defining Case Report Forms.
* The code generally uses the beans for previewing a new CRF version.
*
* @see org.akaza.openclinica.control.admin.SpreadsheetPreviewNw
*/
public class BeanFactory {
public static final String UNGROUPED = "Ungrouped";
protected static final Logger logger = LoggerFactory.getLogger("org.akaza.openclinica.control.managestudy.BeanFactory");
// A thread-safe Map that, for each CRF name, contains the response_label
// name as the index to response_options_text and response_values.
// This is designed to deal with
// the Items that have a response_label value, but leave the options text
// and values
// blank and use a response set previously defined in the spreadsheet
// template.
private static Map<String, Map<String, String[]>> cachedResponseLabels = Collections.synchronizedMap(new HashMap<String, Map<String, String[]>>());
/**
* This method creates a List of DisplayItemGroupBeans. The
* DisplayItemGroupBeans are listed in the order their items are defined in
* the CRF spreadsheet. These beans include the items that are and are not
* associated with a group. If an item is defined in a spreadsheet but does
* not have a group label, that item is included in a DisplayItemGroupBean,
* but not linked to any groups (i.e., that DisplayItemGroupBean has an
* empty FormGroupBean object, with an empty String for a group label). For
* example, if the spreadsheet defines two items first, but does not assign
* them a group, then those items will make up the first
* DisplayItemGroupBean. The spreadsheet then might define a <em>group</em>
* of items followed by more items that are not part of a group. The former
* items will represent the second DisplayItemGroupBean. The third
* DisplayItemGroupBean will include the last collection of "orphaned"
* items, accompanied by an empty FormGroupBean object.
*
* @param itemsMap
* A Map containing rows of Item information from the
* spreadsheet. The items are in the order they were defined in
* the spreadsheet.
* @param sectionLabel
* A String specifying the name of the section we are displaying.
* @param groupsMap
* A Map containing rows of Group information from the
* spreadsheet.
* @param crfName
* The name of the CRF, a String.
* @see org.akaza.openclinica.bean.submit.ItemGroupBean
* @return A List of DisplayItemGroupBeans
*/
public List<DisplayItemGroupBean> createGroupBeans(Map<Integer, Map<String, String>> itemsMap, Map<Integer, Map<String, String>> groupsMap,
String sectionLabel, String crfName) {
List<DisplayItemGroupBean> groupBeans = new ArrayList<DisplayItemGroupBean>();
// We have to have data in all three Map parameters to
// properly build group beans
if (groupsMap == null || groupsMap.isEmpty() || sectionLabel == null || sectionLabel.length() < 1 || sectionLabel.equalsIgnoreCase(UNGROUPED)
|| itemsMap == null || itemsMap.isEmpty()) {
return groupBeans;
}
// First, separate the items into those only associated with this
// section
Map<String, String> innermap;
List<DisplayItemBean> displayItems;
Map.Entry<Integer, Map<String, String>> me;
// This Map will hold the DisplayitemBeans that are associated with this
// section
Map<Integer, Map<String, String>> newMap = new HashMap<Integer, Map<String, String>>();
String lab;
for (Iterator<Map.Entry<Integer, Map<String, String>>> iter = itemsMap.entrySet().iterator(); iter.hasNext();) {
me = iter.next();
innermap = me.getValue();
lab = innermap.get("section_label");
if (lab != null && lab.equalsIgnoreCase(sectionLabel)) {
newMap.put(me.getKey(), innermap);
}
}
displayItems = this.createDisplayItemBeansFromMap(newMap, crfName);
// Now, separate the DisplayItemBeans into those associated with groups,
// and any others that do not have groups
ItemGroupBean fgBean;
DisplayItemGroupBean disFgBean;
String latestGroupLabel;
boolean validGroupFlag = false;
int ordinal = 0;
// Examine each Item; if it doesn't have a group label, store the item
// as a
// DisplayItemBean in a new DisplayFormGroupBean. Once items defining a
// group begin, create a new DisplayFormGroupBean for those
// group-related
// items and place the first DisplayFormGroupBean the code created in
// the List.
for (DisplayItemBean disBean : displayItems) {
latestGroupLabel = disBean.getMetadata().getGroupLabel();
// If the group label is a valid String, then the displayItem is
// related
// to a group. Store it in a FormGroupBean.
if (latestGroupLabel != null && latestGroupLabel.length() > 0 && !latestGroupLabel.equalsIgnoreCase(UNGROUPED)) {
// set this flag to true, indicating that the items being
// processed now
// are associated with a valid group
validGroupFlag = true;
// If lastGroupLabel is not yet stored in the List of
// DisplayGroupBeans
// then the beans associated with that label (DisplayGroupBeans
// and
// FormGroupBeans) have to be initialized.
// Otherwise, just store the new displayitembean in the existing
// FormGroupBean/DisplayFormGroupBean
disFgBean = getGroupFromLabel(latestGroupLabel, groupBeans);
// If the DisplayGroupBean doesn't have a valid group label yet,
// then a new one has to be initialized for this DisplayItemBean
if (!(disFgBean.getItemGroupBean().getName().length() > 0)) {
// Get FormGroupBean from group label
fgBean = initFormGroupFromMap(latestGroupLabel, groupsMap);
ordinal++;
fgBean.getMeta().setOrdinal(ordinal);
disFgBean.setItemGroupBean(fgBean);
disFgBean.setGroupMetaBean(fgBean.getMeta());
groupBeans.add(disFgBean);
}
} else {
// if there is no group label associated with the
// DisplayItemBean, then it
// does not have a group; it is an "orphaned" item. In this
// case, create a
// DisplayFormGroup with a group label signified with an empty
// string. This
// "group" will hold the orphaned items. What if there are
// orphaned items
// in the spreadsheet that are divided by grouped items? Then
// these orphaned
// items have to be in separate DisplayFormGroups. To handle
// this case, the
// code checks the validGroupFlag boolean variable. if "true,"
// indicating that
// non-orphaned beans have just been processed, then create a
// new
// DisplayFormGroup for these orphaned items.
boolean isFirst = isFirstUngroupedItem(groupBeans);
if (validGroupFlag || isFirst) {
disFgBean = new DisplayItemGroupBean();
fgBean = new ItemGroupBean();
ordinal++;
fgBean.getMeta().setOrdinal(ordinal);
fgBean.setName(UNGROUPED);
disFgBean.setItemGroupBean(fgBean);
disFgBean.setGroupMetaBean(fgBean.getMeta());
groupBeans.add(disFgBean);
} else {
// The existing DisplayFormGroupBean for orphaned items
// is the FormGroupBean containing the highest ordinal, and
// with a group label
// containing an empty string
disFgBean = getLatestDisFormBeanForOrphanedItems(groupBeans);
}
validGroupFlag = false;
}
disFgBean.getItems().add(disBean);
}
return groupBeans;
}
private boolean isFirstUngroupedItem(List<DisplayItemGroupBean> groupBeans) {
for (DisplayItemGroupBean digBean : groupBeans) {
if (digBean.getItemGroupBean().getName().equalsIgnoreCase(UNGROUPED)) {
return false;
}
}
return true;
}
private DisplayItemGroupBean getLatestDisFormBeanForOrphanedItems(List<DisplayItemGroupBean> beans) {
if (beans == null || beans.isEmpty()) {
return new DisplayItemGroupBean();
}
// create a LinkedList then grab the tail of the list to get
// the FormGroupBean with the highest ordinal
LinkedList<DisplayItemGroupBean> list = new LinkedList<DisplayItemGroupBean>();
for (DisplayItemGroupBean dBean : beans) {
if (dBean.getItemGroupBean().getName().length() < 1 || dBean.getItemGroupBean().getName().equalsIgnoreCase(UNGROUPED)) {
list.add(dBean);
}
}
// sort the list
Collections.sort(list, new Comparator<DisplayItemGroupBean>() {
public int compare(DisplayItemGroupBean displayFormGroupBean, DisplayItemGroupBean displayFormGroupBean1) {
return displayFormGroupBean.getGroupMetaBean().getOrdinal().compareTo(displayFormGroupBean1.getGroupMetaBean().getOrdinal());
}
});
// return the DisplayFormGroupBean with the highest ordinal
return list.getLast();
}
/**
* This method places a group metadata bean into an ItemGroupBean
*
* @param groupLabel
* The String specifying a group label.
* @param groupMap
* The Map containing the data for a group.
* @return ItemGroupBean
*/
private ItemGroupBean initFormGroupFromMap(String groupLabel, Map<Integer, Map<String, String>> groupMap) {
ItemGroupBean formGroupBean = new ItemGroupBean();
ItemGroupMetadataBean igMetaBean = new ItemGroupMetadataBean();
Map<String, String> groupValues;
NumberFormat numFormatter = NumberFormat.getInstance();
numFormatter.setMaximumFractionDigits(0);
String tempValue;
for (Entry<Integer, Map<String, String>> entry : groupMap.entrySet()) {
groupValues = entry.getValue();
if (groupValues.get("group_label").equalsIgnoreCase(groupLabel)) {
formGroupBean.setName(groupLabel);
igMetaBean.setHeader(groupValues.get("group_header"));
//Hamid repeating group or not
if(groupValues.get("repeating_group") != null){
igMetaBean.setRepeatingGroup(Boolean.parseBoolean(groupValues.get("repeating_group")));
// System.out.println("=============" + groupValues.get("repeating_group"));
}
// YW 10-04-2007 <<
// BWP changed to try/catch block
tempValue = groupValues.get("group_repeat_max");
// This line is necessary because "0" will not throw an
// exception, but is still unacceptable
if(StringUtil.isBlank(tempValue)){
tempValue = "0";
} else if ("0.0".equalsIgnoreCase(tempValue)) {
tempValue = "22000";
}
try {
igMetaBean.setRepeatMax(new Integer(numFormatter.format(Double.parseDouble(tempValue))));
} catch (NumberFormatException nfe) {
// BWP >>an arbitrarily large number allows infinite
// repeats; it could also be -1
igMetaBean.setRepeatMax(22000);
}
// YW >>
// YW 10-04-2007 <<
// BWP changed to try/catch block
tempValue = groupValues.get("group_repeat_number");
// This line is necessary because "0" will not throw an
// exception, but is still unacceptable
if(igMetaBean.isRepeatingGroup() && StringUtil.isBlank(tempValue)){
tempValue = "1";
}else if(StringUtil.isBlank(tempValue)){
tempValue = "0";
}else if ("0.0".equalsIgnoreCase(tempValue)) {
tempValue = "1";
}
try {
igMetaBean.setRepeatNum(new Integer(numFormatter.format(Double.parseDouble(tempValue))));
} catch (NumberFormatException nfe) {
// BWP 10-13-07
igMetaBean.setRepeatNum(1);
}
// YW >>
}
}
formGroupBean.setMeta(igMetaBean);
return formGroupBean;
}
private DisplayItemGroupBean getGroupFromLabel(String label, List<DisplayItemGroupBean> groupBeans) {
if (groupBeans == null || groupBeans.isEmpty()) {
return new DisplayItemGroupBean();
}
for (DisplayItemGroupBean dBean : groupBeans) {
if (dBean.getItemGroupBean().getName().equalsIgnoreCase(label)) {
return dBean;
}
}
// If we didn't find the group label, return an empty bean
return new DisplayItemGroupBean();
}
public ItemGroupBean createFormGroupBeanFromMap(Map<Integer, Map<String, String>> groupMap) {
ItemGroupBean fBean = new ItemGroupBean();
Map<String, String> beanMap;
Map.Entry<Integer, Map<String, String>> me;
NumberFormat numFormatter = NumberFormat.getInstance();
numFormatter.setMaximumFractionDigits(0);
String tempValue;
for (Iterator<Map.Entry<Integer, Map<String, String>>> iter = groupMap.entrySet().iterator(); iter.hasNext();) {
me = iter.next();
beanMap = me.getValue();
fBean.setName(beanMap.get("group_label"));
tempValue = beanMap.get("group_repeat_number");
// This line is necessary because "0" will not throw an
// exception, but is still unacceptable
if ("0.0".equalsIgnoreCase(tempValue)) {
tempValue = "1";
}
try {
fBean.getMeta().setRepeatNum(new Integer(numFormatter.format(Double.parseDouble(tempValue))));
} catch (NumberFormatException nfe) {
// BWP 10-13-07
fBean.getMeta().setRepeatNum(1);
}
tempValue = beanMap.get("group_repeat_max");
// This line is necessary because "0" will not throw an
// exception, but is still unacceptable
if ("0.0".equalsIgnoreCase(tempValue)) {
tempValue = "22000";
}
try {
fBean.getMeta().setRepeatMax(new Integer(numFormatter.format(Double.parseDouble(tempValue))));
} catch (NumberFormatException nfe) {
// BWP >>an arbitrarily large number allows infinite repeats; it
// could also be -1
fBean.getMeta().setRepeatMax(22000);
}
fBean.getMeta().setHeader(beanMap.get("group_header"));
}
return fBean;
}
/*
* Generate the list of children for a DisplayItemBean. Currently, this
* method must return an ArrayList, because that is the data type for an
* ItemFormMetaDataBean's children field.
*/
public ArrayList<DisplayItemBean> createChildren(List<DisplayItemBean> childrenItems, DisplayItemBean parent) {
ArrayList<DisplayItemBean> children = new ArrayList<DisplayItemBean>();
// If the ItemBean's parent label is the same as an ItemBean's name,
// then the former ItemBean is
// a child of that paent ItemBean.
for (DisplayItemBean bean : childrenItems) {
if (bean.getMetadata().getParentLabel().equalsIgnoreCase(parent.getItem().getName())) {
children.add(bean);
}
}
// sort in ascending order based on the column number of
// the ItemFormMetadataBean. This is specified by the DisplayItemBean
// API.
Collections.sort(children, new Comparator<DisplayItemBean>() {
public int compare(DisplayItemBean displayItemBean, DisplayItemBean displayItemBean1) {
return new Integer(displayItemBean.getMetadata().getColumnNumber()).compareTo(displayItemBean1.getMetadata().getColumnNumber());
}
});
return children;
}
/*
* Create an ItemBean from a Map specifying its property values, as in
* {item_name: Item1, ...) etc.
*/
public ItemBean createItemBean(Map<String, String> itemValuesMap) {
ItemBean iBean = new ItemBean();
String itemDesc = itemValuesMap.get("description_label");
String itemDataType;
iBean.setDescription(itemDesc);
itemDesc = itemValuesMap.get("item_name");
iBean.setName(itemDesc);
itemDesc = itemValuesMap.get("units");
iBean.setUnits(itemDesc);
itemDataType = itemValuesMap.get("data_type");
// TODO: solve the problem with the getByName method
ItemDataType itemDT = ItemDataType.getByName(itemDataType);
iBean.setItemDataTypeId(itemDT.getId());
return iBean;
}
/* Create a ResponseSetBean from a Map of property/value pairs */
public ResponseSetBean createResponseSetBean(Map<String, String> itemValuesMap, String crfName) {
ResponseSetBean rBean = new ResponseSetBean();
// If an item has a response label that has already been defined (by
// previous
// item definitions) then use the response_options_text and
// response_values associated
// with that response label
String[] innerArray = new String[2];
String responseType = itemValuesMap.get("response_type");
String responseLab = itemValuesMap.get("response_label");
String optionsTxt = itemValuesMap.get("response_options_text");
String optionsVals = itemValuesMap.get("response_values");
rBean.setResponseType(ResponseType.getByName(responseType));
rBean.setLabel(itemValuesMap.get("response_label"));
// Find out if the response text and option values are already cached
// for
// this CRF. The String index is the CRF name; the String array refrs to
// the options text and options values.
Map<String, String[]> responseLabels = cachedResponseLabels.get(crfName);
if (responseLabels == null) {
responseLabels = new HashMap<String, String[]>();
cachedResponseLabels.put(crfName, responseLabels);
}
if (responseLabels.get(responseLab) == null) {
innerArray[0] = optionsTxt;
innerArray[1] = optionsVals;
responseLabels.put(responseLab, innerArray);
}
// if the item has a response label but no values for
// response_options_text
// or response_values, provide the item with the cached values for these
// properties
String[] tmpArr;
if (responseLab != null && responseLab.length() != 0 && optionsTxt != null && optionsTxt.length() == 0 && optionsVals != null
&& optionsVals.length() == 0) {
tmpArr = responseLabels.get(responseLab);
// The responseLabel is stored in the Map
if (tmpArr != null) {
rBean.setOptions(tmpArr[0], tmpArr[1]);
return rBean;
}
}
rBean.setOptions(optionsTxt, optionsVals);
return rBean;
}
/*
* Create an ItemFormMetadataBean from the values referred to by a Map.Entry
* object. The Map.Entry contains an integer pointing to a Map of Item
* values from the Sreadsheet template, as in (item_name: Item1, etc...}
*/
public ItemFormMetadataBean createItemFormMetadataBean(Map.Entry<Integer, Map<String, String>> me, String crfName) {
if (me == null)
return new ItemFormMetadataBean();
ItemFormMetadataBean metadataBean = new ItemFormMetadataBean();
// the POI library returns all numbers as doubles (2.0), we round
// off the numbers to 2, for instance
NumberFormat numFormatter = NumberFormat.getInstance();
numFormatter.setMaximumFractionDigits(0);
String itemPageNum;
String columnNum;
String questNum;
metadataBean.setOrdinal(me.getKey());
Map<String, String> map = me.getValue();
// response_layout property for checkboxes and radio buttons
metadataBean.setResponseLayout(map.get("response_layout"));
metadataBean.setDefaultValue(map.get("default_value"));
metadataBean.setParentLabel(map.get("parent_item"));
metadataBean.setLeftItemText(map.get("left_item_text"));
metadataBean.setRightItemText(map.get("right_item_text"));
metadataBean.setHeader(map.get("header"));
metadataBean.setSubHeader(map.get("subheader"));
metadataBean.setGroupLabel(map.get("group_label"));
itemPageNum = map.get("page_number");
try {
itemPageNum = numFormatter.format(Double.parseDouble(itemPageNum));
} catch (NumberFormatException nfe) {
itemPageNum = "";
}
metadataBean.setPageNumberLabel(itemPageNum);
columnNum = map.get("column_number");
try {
columnNum = numFormatter.format(Double.parseDouble(columnNum));
metadataBean.setColumnNumber(Integer.parseInt(columnNum));
} catch (NumberFormatException nfe) {
metadataBean.setColumnNumber(0);
}
questNum = map.get("question_number");
//We support any character in QUESTION_NUMBER field. So there is no need to do this number formatting.
// try {
// questNum = numFormatter.format(Double.parseDouble(questNum));
// } catch (NumberFormatException nfe) {
// questNum = "";
// }
metadataBean.setQuestionNumberLabel(questNum);
String requStr = map.get("required");
requStr = requStr.equalsIgnoreCase("") ? "0" : requStr;
double required;
try {
required = Double.parseDouble(requStr);
} catch (NumberFormatException nfe) {
required = 0;
}
if (required > 0) {
metadataBean.setRequired(true);
}
ResponseSetBean respBean = this.createResponseSetBean(map, crfName);
metadataBean.setResponseSet(respBean);
return metadataBean;
}
/**
* Create an ItemFormMetadataBean from the values referred to by a Map
* object. The Map contains the Item values from the Sreadsheet template, as
* in (item_name: Item1, etc...}
*
* @param map
* A Map involving the column names and values Of items.
* @param ordinal
* The ordinal property for the meta data bean.
* @param crfName
* The CRF name.
* @return An ItemFormMetadataBean representing the values from the Map.
*/
public ItemFormMetadataBean createMetadataBean(Map<String, String> map, int ordinal, String crfName) {
if (map == null)
return new ItemFormMetadataBean();
ItemFormMetadataBean metadataBean = new ItemFormMetadataBean();
// the POI library returns all numbers as doubles (2.0), we round
// off the numbers to 2, for instance
NumberFormat numFormatter = NumberFormat.getInstance();
numFormatter.setMaximumFractionDigits(0);
String itemPageNum;
String columnNum;
String questNum;
metadataBean.setOrdinal(ordinal);
metadataBean.setResponseLayout(map.get("response_layout"));
metadataBean.setParentLabel(map.get("parent_item"));
metadataBean.setLeftItemText(map.get("left_item_text"));
metadataBean.setRightItemText(map.get("right_item_text"));
metadataBean.setDefaultValue(map.get("default_value"));
metadataBean.setHeader(map.get("header"));
metadataBean.setSubHeader(map.get("subheader"));
itemPageNum = map.get("page_number");
try {
itemPageNum = numFormatter.format(Double.parseDouble(itemPageNum));
} catch (NumberFormatException nfe) {
itemPageNum = "";
}
metadataBean.setPageNumberLabel(itemPageNum);
columnNum = map.get("column_number");
try {
columnNum = numFormatter.format(Double.parseDouble(columnNum));
metadataBean.setColumnNumber(Integer.parseInt(columnNum));
} catch (NumberFormatException nfe) {
metadataBean.setColumnNumber(0);
}
questNum = map.get("question_number");
try {
questNum = numFormatter.format(Double.parseDouble(questNum));
} catch (NumberFormatException nfe) {
questNum = "";
}
metadataBean.setQuestionNumberLabel(questNum);
String requStr = map.get("required");
requStr = requStr.equalsIgnoreCase("") ? "0" : requStr;
double required;
try {
required = Double.parseDouble(requStr);
} catch (NumberFormatException nfe) {
required = 0;
}
if (required > 0) {
metadataBean.setRequired(true);
}
ResponseSetBean respBean = this.createResponseSetBean(map, crfName);
metadataBean.setResponseSet(respBean);
return metadataBean;
}
// Create a DisplaySectionBean using an items map, a section's title,
// the section's page number, and the CRF name/ The CRF name is needed for
// creating the ResponseSetBean.
public DisplaySectionBean createDisplaySectionBean(Map<Integer, Map<String, String>> map, String sectionTitle, String sectionLabel, String sectionSubtitle,
String instructions, String crfName, int sectionBorders) {
/*
* each map row or entry looks like this: 36: {subheader=, validation=,
* page_number=2.0, response_type=text, left_item_text=Other Body
* Sysytem/Site, response_options_text=, required=, response_values=,
* question_number=35.0, phi=0.0, validation_error_message=, header=,
* units=, data_type=ST, response_label=text, item_name=can_base36,
* column_number=2.0, section_label=Specify Other Body System/Site,
* description_label=label, parent_item=can_base34, right_item_text=}
*/
// Play defense!
if (map == null)
return new DisplaySectionBean();
// Display a section title in the JSP
SectionBean sbean = new SectionBean();
sbean.setTitle(sectionTitle);
sbean.setSubtitle(sectionSubtitle);
sbean.setInstructions(instructions);
sbean.setBorders(sectionBorders);
DisplaySectionBean displaySectionBean = new DisplaySectionBean();
displaySectionBean.setSection(sbean);
ArrayList<DisplayItemBean> allDisplayItems = new ArrayList<DisplayItemBean>();
List<DisplayItemBean> childrenItems = new ArrayList<DisplayItemBean>();
DisplayItemBean displayItem;
ItemFormMetadataBean itemMeta;
Map.Entry<Integer, Map<String, String>> me;
Map<String, String> innerMap;
for (Iterator<Map.Entry<Integer, Map<String, String>>> iter = map.entrySet().iterator(); iter.hasNext();) {
displayItem = new DisplayItemBean();
// me is one row in the list of Items, indexed by the item number
me = iter.next();
if (itemSecLabelMatchesSection(me, sectionLabel)) {
itemMeta = this.createItemFormMetadataBean(me, crfName);
displayItem.setMetadata(itemMeta);
innerMap = me.getValue();
displayItem.setItem(this.createItemBean(innerMap));
// Compensate for any items that identify themselves as parents
String parentName = displayItem.getMetadata().getParentLabel();
if (parentName.length() > 0 && !displayItem.getItem().getName().equalsIgnoreCase(parentName)) {
displayItem.getMetadata().setParentId(1);
childrenItems.add(displayItem);
} else {
allDisplayItems.add(displayItem);
}
}
}
// Set the children for each of the display items
for (DisplayItemBean parentBean : allDisplayItems) {
parentBean.setChildren(this.createChildren(childrenItems, parentBean));
}
// Sort the List of DisplayItemBeans based on their ordinal; see
// getDisplayBean() in DataEntryServlet
Collections.sort(allDisplayItems);
displaySectionBean.setItems(allDisplayItems);
return displaySectionBean;
}
// This has to return an ArrayList (not a List, as it should, if you program
// to interfaces), because the SectionBean.setitems method takes an
// ArrayList
public ArrayList createItemBeanList(Map<Integer, Map<String, String>> itemsMap, String secLabel, String crfName) {
if (itemsMap == null)
return new ArrayList();
ArrayList<ItemBean> itemList = new ArrayList<ItemBean>();
ItemBean itemBean;
ItemFormMetadataBean metaBean;
Map<String, String> innerMap;
Map.Entry<Integer, Map<String, String>> me;
// SpreadsheetPreview returns doubles 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);
for (Iterator<Map.Entry<Integer, Map<String, String>>> iter = itemsMap.entrySet().iterator(); iter.hasNext();) {
me = iter.next();
// iterate the internal Map, with all the item headers and values
innerMap = me.getValue();
// String itemPagNumber = innerMap.get("page_number");
String itemSectionLabel = innerMap.get("section_label");
if (itemSectionLabel.equalsIgnoreCase(secLabel)) {
itemBean = this.createItemBean(innerMap);
metaBean = createItemFormMetadataBean(me, crfName);
itemBean.setItemMeta(metaBean);
itemList.add(itemBean);
}
}
return itemList;
}
// Return a list of SectionBeans using Item and Section information
public List<SectionBean> createSectionBeanList(Map<Integer, Map<String, String>> sectionsMap, Map<Integer, Map<String, String>> itemsMap, String crfName,
Map<Integer, Map<String, String>> groupsMap) {
if (sectionsMap == null || itemsMap == null) {
return new ArrayList<SectionBean>();
}
List<SectionBean> secsList = new ArrayList<SectionBean>();
SectionBean secBean;
Map.Entry<Integer, Map<String, String>> me;
Map<String, String> sectionVals;
String sectionLabel;
// SpreadsheetPreview returns doubles 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);
for (Iterator<Map.Entry<Integer, Map<String, String>>> iter = sectionsMap.entrySet().iterator(); iter.hasNext();) {
secBean = new SectionBean();
me = iter.next();
sectionVals = me.getValue();
sectionLabel = sectionVals.get("section_label");
secBean.setName(sectionLabel);
int borders = 0;
// set borders property
String bordersTemp = sectionVals.get("borders");
if (bordersTemp != null) {
borders = new Integer(bordersTemp);
}
secBean.setBorders(borders);
secBean.setParent(createSectionBean(sectionVals.get("parent_section")));
secBean.setTitle(sectionVals.get("section_title"));
secBean.setSubtitle(sectionVals.get("subtitle"));
secBean.setInstructions(sectionVals.get("instructions"));
String pagNumber = sectionVals.get("page_number");
// ensure pagNumber is an actual number ; it doesn't have to be
// enterd as a numer in the Excel file
try {
pagNumber = numFormatter.format(Double.parseDouble(pagNumber));
} catch (NumberFormatException nfe) {
pagNumber = "0";
}
secBean.setItems(createItemBeanList(itemsMap, sectionLabel, crfName));
secBean.setPageNumberLabel(pagNumber);
secsList.add(secBean);
}
// Add groups data
secsList = addPreviewGroupsInfo(secsList, groupsMap);
return secsList;
}
public List<SectionBean> addPreviewGroupsInfo(List<SectionBean> secsList, Map<Integer, Map<String, String>> groupsMap) {
if (secsList == null || secsList.isEmpty()) {
return secsList;
}
ItemGroupBean groupBean = new ItemGroupBean();
Map<String, String> groupValues;
String groupLabel = "";
// Find out which groups belong with which section
for (Entry<Integer, Map<String, String>> entry : groupsMap.entrySet()) {
groupValues = entry.getValue();
groupLabel = groupValues.get("group_label");
groupBean = this.initFormGroupFromMap(groupLabel, groupsMap);
for (SectionBean secBean : secsList) {
if (sectionHasGroup(groupLabel, secBean)) {
secBean.getGroups().add(groupBean);
}
}
}
return secsList;
}
// Does a group belong in a section, based on the group label?
private boolean sectionHasGroup(String groupLabel, SectionBean secBean) {
// if an item in a section matches with the group label, then the group
// belongs to
// that section
for (Object itemObj : secBean.getItems()) {
if (((ItemBean) itemObj).getItemMeta().getGroupLabel().equalsIgnoreCase(groupLabel)) {
return true;
}
}
return false;
}
// Does an item's section label match a section's section label?
private boolean itemSecLabelMatchesSection(Map.Entry me, String sectionLabel) {
Map map = (Map) me.getValue();
String tmp = (String) map.get("section_label");
return tmp.equalsIgnoreCase(sectionLabel);
}
public List<DisplayItemBean> createDisplayItemBeansFromMap(Map<Integer, Map<String, String>> itemsMap, String crfName) {
List<DisplayItemBean> allDisplayItems = new ArrayList<DisplayItemBean>();
DisplayItemBean displayItem;
ItemFormMetadataBean itemMeta;
Map.Entry<Integer, Map<String, String>> me;
Map<String, String> innerMap;
for (Iterator<Map.Entry<Integer, Map<String, String>>> iter = itemsMap.entrySet().iterator(); iter.hasNext();) {
displayItem = new DisplayItemBean();
// me is one row in the list of Items, indexed by the item number
me = iter.next();
itemMeta = this.createItemFormMetadataBean(me, crfName);
innerMap = me.getValue();
String labeltmp = innerMap.get("group_label");
if (labeltmp.length() < 1) {
itemMeta.setGroupLabel(UNGROUPED);
} else {
itemMeta.setGroupLabel(labeltmp);
}
displayItem.setMetadata(itemMeta);
displayItem.setItem(this.createItemBean(innerMap));
allDisplayItems.add(displayItem);
}
// Sort the List of DisplayItemBeans based on their ordinal; see
// getDisplayBean() in DataEntryServlet
Collections.sort(allDisplayItems);
return allDisplayItems;
}
// TODO: Implement this method
public static SectionBean createSectionBean(String secLabel) {
return new SectionBean();
}
}