/*
* File : $Source: /alkacon/cvs/alkacon/com.alkacon.opencms.v8.survey/src/com/alkacon/opencms/v8/survey/CmsFormWorkBean.java,v $
* Date : $Date: 2010/03/19 15:31:15 $
* Version: $Revision: 1.6 $
*
* This library is part of OpenCms -
* the Open Source Content Mananagement System
*
* Copyright (C) 2010 Alkacon Software GmbH (http://www.alkacon.com)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* For further information about Alkacon Software GmbH, please see the
* company website: http://www.alkacon.com
*
* For further information about OpenCms, please see the
* project website: http://www.opencms.org
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.alkacon.opencms.v8.survey;
import com.alkacon.opencms.v8.formgenerator.CmsCheckboxField;
import com.alkacon.opencms.v8.formgenerator.CmsFieldFactory;
import com.alkacon.opencms.v8.formgenerator.CmsForm;
import com.alkacon.opencms.v8.formgenerator.CmsFormContentUtil;
import com.alkacon.opencms.v8.formgenerator.I_CmsField;
import com.alkacon.opencms.v8.formgenerator.database.CmsFormDataAccess;
import com.alkacon.opencms.v8.formgenerator.database.CmsFormDataBean;
import com.alkacon.opencms.v8.formgenerator.database.CmsFormDatabaseFilter;
import org.opencms.file.CmsFile;
import org.opencms.file.CmsObject;
import org.opencms.file.CmsResource;
import org.opencms.jsp.CmsJspActionElement;
import org.opencms.main.CmsLog;
import org.opencms.util.CmsStringUtil;
import org.opencms.util.CmsUUID;
import org.opencms.xml.content.CmsXmlContent;
import org.opencms.xml.content.CmsXmlContentFactory;
import org.opencms.xml.types.I_CmsXmlContentValue;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.logging.Log;
/**
* Contains the list with all results from the database.<p>
*
* @author Anja Roettgers
*
* @version $Revision: 1.6 $
*
* @since 7.0.4
*/
public class CmsFormWorkBean {
/**
* A comparator for the created date of two resources.<p>
*
*/
private static final Comparator<CmsFormDataBean> COMPARE_DATE_CREATED = new Comparator<CmsFormDataBean>() {
/**
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
*/
public int compare(CmsFormDataBean o1, CmsFormDataBean o2) {
long date1 = o1.getDateCreated();
long date2 = o2.getDateCreated();
return (date1 > date2) ? -1 : (date1 < date2) ? 1 : 0;
}
};
/** The log object for this class. */
private static final Log LOG = CmsLog.getLog(CmsFormWorkBean.class);
/** Lazy map with single answers. */
private Map m_answer;
/** Lazy map with the answers. */
private Map m_answers;
/** the list with the filtered data. */
private List m_list;
/** contains the current detail page. **/
private int m_page;
/** Mapping from String dbfieldname to I_CmsField class. */
private Map<String, I_CmsField> m_fieldTypes = new HashMap<String, I_CmsField>();
/**
* default constructor.<p>
*/
public CmsFormWorkBean() {
super();
}
/**
* Returns a lazy initialized map that provides the answer for each field
* used as a key in the Map.<p>
*
* @return a lazy initialized map
*/
public Map getAnswerByField() {
if (m_answer == null) {
m_answer = LazyMap.decorate(new HashMap(), new Transformer() {
/**
* @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
*/
public Object transform(Object input) {
String value = String.valueOf(input);
return getAnswerByField(value);
}
});
}
return m_answer;
}
/**
* Returns the value of the field of the selected data.<p>
*
* The parameter must contain three values separated with
* {@link CmsFormReportingBean#PARAM_SEPARATOR}:<p>
*
* <ul>
* <li>the field name</li>
* <li>the current page (the selected data)</li>
* <li>the current type of the field</li>
* </ul>
*
* @param parameters a string value with three parameters
*
* @return a List of {@link String} contains the values
*/
public List getAnswerByField(String parameters) {
// split the parameter with the separator
List result = new ArrayList();
String[] param = CmsStringUtil.splitAsArray(parameters, CmsFormReportingBean.PARAM_SEPARATOR);
if ((param.length <= 2) || (m_list == null)) {
return result;
}
// first look if the page parameter is set correct
m_page = Integer.parseInt(param[1]);
if (m_page <= 0) {
m_page = 1;
} else if (m_page >= m_list.size()) {
m_page = m_list.size();
}
// get the form bean and get the value
CmsFormDataBean data = (CmsFormDataBean)getList().get(m_page - 1);
String value = data.getFieldValue(param[0]);
if (CmsStringUtil.isEmpty(value)) {
value = "";
}
// only the correct types can be splitted
I_CmsField formField = this.m_fieldTypes.get(param[2]);
if (CmsFormReportingBean.isFieldTypeCorrect(param[2])) {
if (isMultiSelectField(formField)) {
result = CmsStringUtil.splitAsList(value, ',');
} else {
result.add(value);
}
} else {
result.add(value);
}
return result;
}
/**
* Returns a lazy initialized map that provides the answers with the count
* for each field used as a key in the Map.<p>
*
* @return a lazy initialized map
*/
public Map getAnswers() {
if (m_answers == null) {
m_answers = LazyMap.decorate(new HashMap(), new Transformer() {
/**
* @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
*/
public Object transform(Object input) {
String value = String.valueOf(input);
return getAnswersWithCount(value);
}
});
}
return m_answers;
}
/**
* Look in the list how much entries have selected this answer.<p>
*
* @param field the answer looking for
*
* @return the count of all answers
*/
public Map getAnswersWithCount(String field) {
Map result = new HashMap();
CmsFormDataBean data;
String value, answer;
List answers;
Integer count;
I_CmsField formField;
for (int i = 0; i < m_list.size(); i++) {
data = (CmsFormDataBean)m_list.get(i);
value = data.getFieldValue(field);
// a value can be null if its not a mandatory field
if (value != null) {
formField = this.m_fieldTypes.get(field);
if (isMultiSelectField(formField)) {
answers = CmsStringUtil.splitAsList(value, ',');
} else {
answers = new ArrayList(1);
answers.add(value);
}
for (int j = 0; j < answers.size(); j++) {
answer = (String)answers.get(j);
answer = answer.trim();
if (result.containsKey(answer)) {
count = (Integer)result.get(answer);
result.remove(answer);
result.put(answer, new Integer(count.intValue() + 1));
} else {
result.put(answer, new Integer(1));
}
}
}
}
return result;
}
/**
* Returns the average of the numeric entries for this field, or null if there are no numeric
* entries.
*
* @param field The name of the field for which averages should be calculated.
* @return the average of the field values, or null if there were no non-numeric field values
*/
public Double getAverageForField(String field) {
long count = 0;
double sum = 0;
for (int i = 0; i < m_list.size(); i++) {
CmsFormDataBean data = (CmsFormDataBean)m_list.get(i);
String valueAsString = data.getFieldValue(field);
double value = 0;
try {
value = Double.parseDouble(valueAsString);
count += 1;
sum += value;
} catch (Exception e) {
// don't count non-numeric strings or nulls
}
}
if (count == 0) {
return null;
}
return new Double(sum / count);
}
/**
* Returns a lazy map that maps fields to the average value produced by {@link CmsFormWorkBean#getAverageForField(String)}
* @return a lazy map that maps fields to the average value produced by {@link CmsFormWorkBean#getAverageForField(String)}
*
*/
public Map getAveragesForFields() {
return LazyMap.decorate(new HashMap(), new Transformer() {
public Object transform(Object o) {
return getAverageForField((String)o);
}
});
}
/**
* Returns the list.<p>
*
* @return the list
*/
public List getList() {
return m_list;
}
/**
* Returns the page.<p>
*
* @return the page
*/
public int getPage() {
return m_page;
}
/**
* Initialize this work bean and filter the data with the form id and if
* exists the resource path.<p>
*
* @param formId the form id
* @param resourceId the resource id if null then nothing is filtered
* @param formPath the form path of the web form
*/
public void init(String formId, String resourceId, String formPath, CmsJspActionElement jsp) {
CmsObject cms = jsp.getCmsObject();
Locale locale = jsp.getRequestContext().getLocale();
m_list = new ArrayList();
m_page = 1;
try {
if (formId != null) {
CmsFormDatabaseFilter filter = CmsFormDatabaseFilter.DEFAULT;
filter = filter.filterFormId(formId);
if (resourceId != null) {
filter = filter.filterResourceId(new CmsUUID(resourceId));
}
m_list = CmsFormDataAccess.getInstance().readForms(filter);
Collections.sort(m_list, COMPARE_DATE_CREATED);
// get the field types from the form xml content
CmsResource resource = cms.readResource(formPath);
CmsFile file = cms.readFile(resource);
CmsXmlContent xmlContent = CmsXmlContentFactory.unmarshal(cms, file);
List fieldValues = CmsFormContentUtil.getContentValues(xmlContent, CmsForm.NODE_INPUTFIELD, locale);
int fieldValueSize = fieldValues.size();
CmsFieldFactory fieldFactory = CmsFieldFactory.getSharedInstance();
String dbFieldName;
for (int i = 0; i < fieldValueSize; i++) {
I_CmsXmlContentValue inputField = (I_CmsXmlContentValue)fieldValues.get(i);
String inputFieldPath = inputField.getPath() + "/";
I_CmsField field = null;
// get the field from the factory for the specified type
String stringValue = xmlContent.getStringValue(cms, inputFieldPath + CmsForm.NODE_FIELDTYPE, locale);
field = fieldFactory.getField(stringValue);
// get the field label
stringValue = xmlContent.getStringValue(cms, inputFieldPath + CmsForm.NODE_FIELDLABEL, locale);
dbFieldName = CmsForm.getConfigurationValue(stringValue, "");
m_fieldTypes.put(dbFieldName, field);
}
}
} catch (Exception e) {
if (LOG.isErrorEnabled()) {
LOG.error(Messages.get().getBundle().key(Messages.ERR_INIT_WORK_BEAN_2, formId, resourceId), e);
}
}
}
/**
* Returns true if the given field (type) allows multi selection.
* <p>
*
* @param field
* the field to check
* @return true if the given field (type) allows multi selection.
*/
private boolean isMultiSelectField(I_CmsField field) {
boolean result = false;
result = (field instanceof CmsCheckboxField);
return result;
}
/**
* Sets the list.
* <p>
*
* @param list
* the list to set
*/
public void setList(List list) {
m_list = list;
}
/**
* Sets the page.
* <p>
*
* @param page
* the page to set
*/
public void setPage(int page) {
m_page = page;
}
}