/*
 * Copyright (C) 2005 - 2011 Jaspersoft Corporation. All rights reserved.
 * http://www.jaspersoft.com.
 *
 * Unless you have purchased  a commercial license agreement from Jaspersoft,
 * the following license terms  apply:
 *
 * This program is free software: you can redistribute it and/or  modify
 * it under the terms of the GNU Affero 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 Affero  General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public  License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package com.jaspersoft.jasperserver.war.action;


import static com.jaspersoft.jasperserver.war.action.ReportParametersUtils.getDatatype;
import static com.jaspersoft.jasperserver.war.action.ReportParametersUtils.setInputControlParameterValue;
import static com.jaspersoft.jasperserver.war.action.ReportParametersUtils.toInputControlNumber;

import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.*;
import java.util.*;
import java.util.regex.Pattern;

import javax.servlet.ServletRequest;

import com.jaspersoft.jasperserver.api.metadata.common.domain.*;
import com.jaspersoft.jasperserver.war.common.InputControlLabelResolver;
import org.apache.commons.collections.OrderedMap;
import org.apache.commons.collections.map.LinkedMap;
import org.apache.commons.collections.set.ListOrderedSet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONObject;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.webflow.action.FormAction;
import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.RequestContext;

import com.jaspersoft.jasperserver.api.JSException;
import com.jaspersoft.jasperserver.api.common.domain.ExecutionContext;
import com.jaspersoft.jasperserver.api.common.domain.impl.ExecutionContextImpl;
import com.jaspersoft.jasperserver.api.engine.common.service.EngineService;
import com.jaspersoft.jasperserver.api.engine.common.service.ReportInputControlInformation;
import com.jaspersoft.jasperserver.api.engine.common.service.ReportInputControlsInformation;
import com.jaspersoft.jasperserver.api.engine.jasperreports.service.impl.EngineServiceImpl;
import com.jaspersoft.jasperserver.api.engine.jasperreports.util.RepositoryContext;
import com.jaspersoft.jasperserver.api.engine.jasperreports.util.RepositoryResourceClassLoader;
import com.jaspersoft.jasperserver.api.engine.jasperreports.util.RepositoryResourceKey;
import com.jaspersoft.jasperserver.api.engine.jasperreports.util.RepositoryUtil;
import com.jaspersoft.jasperserver.api.metadata.common.service.RepositoryService;
import com.jaspersoft.jasperserver.api.metadata.jasperreports.domain.ReportUnit;
import com.jaspersoft.jasperserver.war.common.JasperServerUtil;
import com.jaspersoft.jasperserver.war.common.ResourceBundleHelper;
import com.jaspersoft.jasperserver.war.dto.RuntimeInputControlWrapper;
import com.jaspersoft.jasperserver.war.util.CalendarFormatProvider;

/**
 * @author Ionut Nedelcu (ionutned@users.sourceforge.net)	
 * @version $Id: ReportParametersAction.java 20427 2011-05-01 19:48:38Z yuriy.plakosh $
 */
public abstract class ReportParametersAction extends FormAction implements ReportInputControlsAction
{

    private static final Log log = LogFactory.getLog(ReportParametersAction.class);
    protected static final String AJAX_RESPONSE_MODEL = "ajaxResponseModel";
    public static final String INPUTWRAPPERS_ATTR = "wrappers";
    // Null substitute value
    public static final String NULL_SUBSTITUTE = "~NULL~";
    public static final String NULL_SUBSTITUTE_LABEL = "[Null]";
    public static final String NOTHING_SUBSTITUTE = "~NOTHING~";
    public static final String NOTHING_SUBSTITUTE_LABEL = "---";
    public static final String WRAPPERS_FLOW_SCOPE_UUID = "wrappersUUID";
    public static final String VIEW_AS_DASHBOARD_FRAME = "viewAsDashboardFrame"; 	
	public static final String IS_DASHBOARD = "isDashboard";

    private static final String COLUMN_VALUE_SEPARATOR = " | ";
    private static final int COLUMN_VALUE_SEPARATOR_LENGTH = COLUMN_VALUE_SEPARATOR.length();

    private String reportUnitAttrName;
    private String reportUnitObjectAttrName;
    private String messageSourceObjectAttrName;
    private String controlsDisplayFormAttrName;
    private String controlsDisplayViewAttrName;
    private String reportDisplayFormAttrName;
    private String calendarDatePatternAttrName;
    private String calendarDatetimePatternAttrName;
    private EngineService engine;
    private RepositoryService repository;
    private MessageSource messages;
    private String hasInputControlsAttrName;
    private String staticDatePattern;
    private CalendarFormatProvider calendarFormatProvider;
    private String inputNamePrefix;
    private String attributeInputControlsInformation;
    private String markerParameterPrefix;

    protected void createWrappers(RequestContext context)
    {
        ReportUnit reportUnit = loadReportUnit(context);
        MutableAttributeMap flowScope = context.getFlowScope();

        if (reportUnit == null) {
            throw new JSException("jsexception.view.report.could.not.load");
        }

        flowScope.put(getReportUnitObjectAttrName(), reportUnit);

        setReportUnitAttributes(context, reportUnit);

        flowScope.put(getCalendarDatePatternAttrName(), getCalendarDatePattern());
        flowScope.put(getCalendarDatetimePatternAttrName(), getCalendarDatetimePattern());
        ExecutionContext exContext = getExecutionContext(context);
        Map reportParameters = engine.getReportInputControlDefaultValues(exContext, getReportURI(context), null);

        List wrappers = createWrappers(context, reportUnit, reportParameters);
        flowScope.put(INPUTWRAPPERS_ATTR, wrappers);
        putWrappersToSession(context, wrappers);

        MessageSource messageSource = loadMessageSource(exContext, reportUnit);
        if (messageSource != null) {
            context.getExternalContext().getSessionMap().put(getMessageSourceObjectAttrName(), messageSource);
        } else {
            context.getExternalContext().getSessionMap().remove(getMessageSourceObjectAttrName());
        }

        flowScope.put(getHasInputControlsAttrName(), hasUserInputControls(wrappers));

//        boolean needsInput = needsInput(context, wrappers);
//        return needsInput ? yes() : no();
    }

	protected boolean hasUserInputControls(List wrappers) {
		boolean hasVisibleControls = false;
		for (Iterator it = wrappers.iterator(); it.hasNext();) {
			RuntimeInputControlWrapper control = (RuntimeInputControlWrapper) it.next();
			if (control.getInputControl().isVisible()) {
				hasVisibleControls = true;
				break;
			}
		}
		return hasVisibleControls;
	}

	protected boolean hasUserInputControls(RequestContext context) {
        List wrappers = getInputControlWrappers(context);
        return hasUserInputControls(wrappers);
	}

    /**
     * Input Control wrappers should be accessible even
     * out of Web Flow context so they should be saved into
     * regular session. But they are saved with unique identifier
     * so there could be many instances of wrappers storen into same session
     */
    protected void putWrappersToSession(RequestContext context, List wrappers) {
        Map wrappersMap = (Map)context.getExternalContext().getSessionMap().get(INPUTWRAPPERS_ATTR);
        if (wrappersMap == null) {
            wrappersMap = new HashMap();
            context.getExternalContext().getSessionMap().put(INPUTWRAPPERS_ATTR, wrappersMap);
        }

        Object wrappersFlowScopeUUID = context.getFlowScope().get(WRAPPERS_FLOW_SCOPE_UUID);
        if (wrappersFlowScopeUUID == null) {
            wrappersFlowScopeUUID = String.valueOf(System.currentTimeMillis());
        }
        context.getFlowScope().put(WRAPPERS_FLOW_SCOPE_UUID, wrappersFlowScopeUUID);
        wrappersMap.put(wrappersFlowScopeUUID, wrappers);
    }

    protected void setReportUnitAttributes(RequestContext context, ReportUnit reportUnit) {
        MutableAttributeMap flowScope = context.getFlowScope();
        String controlsView = reportUnit.getInputControlRenderingView();
        if (controlsView != null && controlsView.endsWith(".jsp")) {
            String controlsFlowView = controlsView.substring(0, controlsView.length() - ".jsp".length());
            flowScope.put(getControlsDisplayViewAttrName(), controlsFlowView);
        }
        flowScope.put(getControlsDisplayFormAttrName(), controlsView);
        flowScope.put(getReportDisplayFormAttrName(), reportUnit.getReportRenderingView());
    }

    public String getReportURI(RequestContext context) {
        String reportURI = context.getFlowScope().getString(getReportUnitAttrName());
        return reportURI;
    }

    protected ReportUnit loadReportUnit(RequestContext context)
    {
        String reportUnitUri = (String) context.getFlowScope().get(getReportUnitAttrName());

        if (reportUnitUri == null) {
            reportUnitUri = context.getRequestParameters().get(getReportUnitAttrName());
            if (reportUnitUri != null) {
                context.getFlowScope().put(getReportUnitAttrName(), reportUnitUri);
            }
        }

        ReportUnit reportUnit;
        if (reportUnitUri == null || reportUnitUri.trim().length() == 0) {
            reportUnit = null;
        } else {
            reportUnit = (ReportUnit) repository.getResource(getExecutionContext(context), reportUnitUri);
        }

        return reportUnit;
    }

    /**
     * create an ExecutionContext to use for repo access
     * If the viewAsDashboardFrame request param is true, then allow exec-only perms for resources
     * @param reqContext
     * @return
     */
    protected static ExecutionContext getExecutionContext(RequestContext reqContext) {
    	return getExecutionContext(JasperServerUtil.getExecutionContext(reqContext), reqContext);
    }
    
    /**
     * create an ExecutionContext to use for repo access
     * If the viewAsDashboardFrame request param is true, then allow exec-only perms for resources
     * @param exContext
     * @param reqContext
     * @return
     */
    protected static ExecutionContext getExecutionContext(ExecutionContext exContext, RequestContext reqContext) {
    	String dashFrameParam = reqContext.getRequestParameters().get(VIEW_AS_DASHBOARD_FRAME);
    	Boolean dashFlowParam = (Boolean) reqContext.getFlowScope().get(IS_DASHBOARD);
    	if (Boolean.valueOf(dashFrameParam) || (dashFlowParam != null && dashFlowParam)) {
    		exContext = EngineServiceImpl.getRuntimeExecutionContext(exContext);
    	}
    	return exContext;
    }
    protected boolean needsInput(RequestContext context, List wrappers)
    {
        return !wrappers.isEmpty();
    }

    public Map getReportParameters(RequestContext context) {
        return getParameterValues(context);
    }

    protected Map getRequestParameterValues(RequestContext context) {
        List wrappers = getInputControlWrappers(context);
        if (!wrappers.isEmpty()) {
        	boolean valid = parseRequest(context, wrappers, true);
        	if (!valid) {
        		return null;
        	}
        }

        return getParameterValues(context);
    }

    protected Map getParameterValues(RequestContext context) {
        List wrappers = getInputControlWrappers(context);
        String reportUnitUri = getReportURI(context);
        Map parameterValues = bindParameterValues(reportUnitUri, wrappers);
        addCustomParameters(context, parameterValues);
        return parameterValues;
    }
    
    public List getInputControlWrappers(RequestContext context)
    {
        String wrappersFlowScopeUUID = (String)context.getFlowScope().get(WRAPPERS_FLOW_SCOPE_UUID);
        return (List) ((Map)context.getExternalContext().getSessionMap().asMap().get(INPUTWRAPPERS_ATTR)).get(wrappersFlowScopeUUID);
    }

    protected boolean hasInputs(RequestContext context)
    {
        List wrappers = getInputControlWrappers(context);
        return wrappers != null && !wrappers.isEmpty();
    }

    public void setParameterValues(RequestContext context, Map values) {
        List inputControls = getInputControlWrappers(context);
        MapValueProvider valueProvider = new MapValueProvider(values, defaultValuesProvider(context));
        setInputParameterValues(inputControls, valueProvider);
    }

    public void resetValuesToDefaults(RequestContext context) {
        createWrappers(context);
    }

    public static int getDSTSavings(TimeZone tz) {

        if (tz.useDaylightTime()) {
            return 3600000;
        }
        return 0;
    }

    protected void addCustomParameters(RequestContext context, Map parameterValues) {
        //nothing
    }


    protected InputValueProvider initialValueProvider(RequestContext context) {
        return defaultValuesProvider(context);
    }

    protected static abstract class InputValueProvider {
        private final InputValueProvider parent;

        protected InputValueProvider() {
            this(null);
        }

        protected InputValueProvider(InputValueProvider parent) {
            this.parent = parent;
        }

        public Object getValue(String inputName) {
            Object value;
            if (hasOwnValue(inputName)) {
                value = getOwnValue(inputName);
            } else if (parent != null) {
                value = parent.getValue(inputName);
            } else {
                value = null;
            }
            return value;
        }

        protected abstract boolean hasOwnValue(String inputName);

        protected abstract Object getOwnValue(String inputName);
    }

    protected static class MapValueProvider extends InputValueProvider {
        private final Map values;

        public MapValueProvider(Map values) {
            this.values = values;
        }

        public MapValueProvider(Map values, InputValueProvider parent) {
            super(parent);
            this.values = values;
        }

        protected boolean hasOwnValue(String inputName) {
            return values.containsKey(inputName);
        }

        protected Object getOwnValue(String inputName) {
            return values.get(inputName);
        }
    }

    protected InputValueProvider defaultValuesProvider(RequestContext context) {
        ReportInputControlsInformation controlsInfo = getControlsInformation(context);
        Map defaults = new HashMap();
        for (Iterator it = controlsInfo.getControlNames().iterator(); it.hasNext();) {
            String name = (String) it.next();
            ReportInputControlInformation info = controlsInfo.getInputControlInformation(name);
            if (info != null) {
                defaults.put(name, info.getDefaultValue());
            }
        }
        return new MapValueProvider(defaults);
    }

    protected ReportInputControlsInformation getControlsInformation(
            RequestContext context) {
        return (ReportInputControlsInformation)
                context.getFlowScope().getRequired(getAttributeInputControlsInformation(),
                        ReportInputControlsInformation.class);
    }

    protected void setInputParameterValues(List wrappers, InputValueProvider valueProvider) {
        for (Iterator it = wrappers.iterator(); it.hasNext();) {
            RuntimeInputControlWrapper inputControl = (RuntimeInputControlWrapper) it.next();
            String inputName = inputControl.getInputControl().getName();
            Object paramValue = valueProvider.getValue(inputName);
            setInputControlParameterValue(inputControl, paramValue, repository);
        }
    }

    protected ReportInputControlsInformation loadInputControlsInformation(ExecutionContext exContext, RequestContext context, ReportUnit report) {
        String reportURI = report.getURIString();
        Map params = new HashMap();
        addCustomParameters(context, params);
        return getEngine().getReportInputControlsInformation(exContext, reportURI, params);
    }

    protected List createWrappers(RequestContext context, ReportUnit reportUnit, Map reportParameters) {
    	ExecutionContext exContext = getExecutionContext(JasperServerUtil.getExecutionContext(context), context);
        return createWrappers(exContext, context, reportUnit, reportParameters);
    }

    /**
     * New signature takes ExecutionContext because we may not be coming from webflow
     * @param exContext
     * @param context
     * @param reportUnit
     * @return
     */
    protected List createWrappers(ExecutionContext exContext, RequestContext context, ReportUnit reportUnit, Map reportParameters)
    {
        List wrappers = new ArrayList();

        //webflow requests only
        ReportInputControlsInformation controlsInfo = null;
        if (context != null) {
            controlsInfo = loadInputControlsInformation(exContext, context, reportUnit);
            context.getFlowScope().put(getAttributeInputControlsInformation(), controlsInfo);
        }

        //TODO use other repository control that brings the required data
        List inputControls = reportUnit.getInputControls();
        Map<String, Object> wrapperValueFromRequest = getWrapperValueFromRequest(exContext, inputControls, context);
        boolean hasRequestValues = !wrapperValueFromRequest.isEmpty();
        
        if (!inputControls.isEmpty())
        {
            for (int i = 0; i < inputControls.size(); i++)
            {
                InputControl control = getInputControl(exContext, (ResourceReference) inputControls.get(i));

                Format format = getWrapperFormat(exContext, control);

                ResourceReference listOfValuesRef = control.getListOfValues();
                if (listOfValuesRef != null && !listOfValuesRef.isLocal()) {
                    ListOfValues listOfValues = (ListOfValues) repository.getResource(new ExecutionContextImpl(), listOfValuesRef.getReferenceURI());
                    control.setListOfValues(listOfValues);
                }

                RuntimeInputControlWrapper wrapper = new RuntimeInputControlWrapper(control);
//                String uriString = control.getURIString().replace("/", "\\/"); //escape slashes for javascript.
                String uriString = control.getURIString();
                wrapper.setResourceUriPrefix(uriString);
                wrapper.setFormat(format);

                Map executionParams = new HashMap();
                InputValueProvider valueProvider = null;
                if (controlsInfo != null) {
                    valueProvider = initialValueProvider(context);
                    for (Object paramName : reportParameters.keySet()) {
                        executionParams.put(paramName, valueProvider.getValue((String) paramName));
                    }

                    for (String paramName: wrapperValueFromRequest.keySet()) {
                        //params with null values can be presented in wrapperValueFromRequest
                        //so we should not skip them
                        //if (wrapperValueFromRequest.get(paramName) != null) {
                            executionParams.put(paramName, wrapperValueFromRequest.get(paramName));
                        //}
                    }
                } else {
                    executionParams = reportParameters;
                }

                ResourceReference queryRef = control.getQuery();
                if (queryRef != null) {
                    /* TODO: executeQuery can throw any sql exceptions which is not caught. */
                    OrderedMap results = executeQuery(control.getQuery(), reportUnit.getDataSource(), wrapper,
                            executionParams);
                    wrapper.setQueryResults(results);
                }

                wrappers.add(wrapper);

                String pName = wrapper.getInputControl().getName();
                
                // update reportParameters
                if (controlsInfo != null) {
                    ReportInputControlInformation rici = controlsInfo.getInputControlInformation(pName);
                    wrapper.setControlInfo(rici);

                    Object paramValue;
                    if (wrapperValueFromRequest.containsKey(pName)) {
                        paramValue = wrapperValueFromRequest.get(pName);
                    } else {
                        paramValue = valueProvider.getValue(pName);
                    }

//                    Object paramValue = valueProvider.getValue(pName);
                    if (paramValue == null) {
                        if (rici != null && rici.getDefaultValue() != null) {
                            setInputControlParameterValue(wrapper, rici.getDefaultValue(), repository);
                        } else {
                            // set first available value as default if isMandatory
                            if (wrapper.getQueryResults() != null && !wrapper.getQueryResults().isEmpty() && wrapper.getInputControl().isMandatory()) {
                                Object newDefaultValue = createDefaultValueAsFirstListResult(wrapper);
                                if (newDefaultValue != null) {
                                    setInputControlParameterValue(wrapper, newDefaultValue, repository);
                                }
                            }
                        }
                    } else {
                        paramValue = processParamValue(paramValue, wrapper);
                        if (paramValue != null) {
                            setInputControlParameterValue(wrapper, paramValue, repository);
                        }
                    }

                    //Update value in map so query result for next control will contains correct values
                    if (wrapper.getValue() != null && hasRequestValues) {
                        wrapperValueFromRequest.put(pName, wrapper.getValue());
                    }
//                    reportParameters.put(pName, wrapper.getValue());
                }

                String displayLabel = InputControlLabelResolver.resolve(wrapper.getInputControl().getLabel(),
                        loadMessageSource(exContext, reportUnit), messages);
                wrapper.setDisplayLabel(displayLabel);

                if (wrapper.isListOfValues()) {
                    ResourceReference rr = wrapper.getInputControl().getListOfValues();

                    ListOfValues lov;
                    if (rr.isLocal()) {
                        lov = (ListOfValues) rr.getLocalResource();
                    } else {
                        lov = (ListOfValues) repository.getResource(
                                JasperServerUtil.getExecutionContext(LocaleContextHolder.getLocale()),
                                rr.getReferenceURI());
                    }

                    if (lov != null) {
                        ListOfValuesItem[] items = lov.getValues();
                        if (items != null) {
                            for (ListOfValuesItem item : items) {
                                wrapper.getListOfValuesDisplayLabels().put(item.getLabel(),
                                        InputControlLabelResolver.resolve(item.getLabel(),
                                                loadMessageSource(exContext, reportUnit), messages));
                            }
                        }
                    }
                }
            }
        }

        return wrappers;
    }

    protected Object createDefaultValueAsFirstListResult(RuntimeInputControlWrapper wrapper) {
        if (wrapper == null) {
            return null;
        }

        Object newDefaultValue = null;
        if (wrapper.isMulti()) {
            if (wrapper.isQuery()) {
                if (wrapper.getQueryResults() != null && !wrapper.getQueryResults().isEmpty()) {
                    newDefaultValue = new ArrayList();
                    ((List) newDefaultValue).add(wrapper.getQueryResults().keySet().toArray()[0]);                                    
                }
            } else if (wrapper.isListOfValues()) {
                //TODO
            }
        } else {
            if (wrapper.isQuery()) {
                if (wrapper.getQueryResults() != null && !wrapper.getQueryResults().isEmpty()) {
                    newDefaultValue = wrapper.getQueryResults().keySet().toArray()[0];
                }
            } else if (wrapper.isListOfValues()) {
                //TODO
            }
        }

        return newDefaultValue;
    }

    //
    protected Object processParamValue(Object paramValue, RuntimeInputControlWrapper wrapper) {
        if (paramValue == null || wrapper == null) {
            return null;
        }

        if (wrapper.isMulti()) {
            int size = ((Collection) paramValue).size();
            int notPresentedValuesSize = 0;

            for (Object value : ((Collection) paramValue)) {
                if (!isValuePresentInList(wrapper, value)) {
                    notPresentedValuesSize++;
                }
            }

            if (size == notPresentedValuesSize && wrapper.getInputControl().isMandatory()) {
                return createDefaultValueAsFirstListResult(wrapper);
            } else if (size > 0) {
                return paramValue;
            }
        } else {
            if (isValuePresentInList(wrapper, paramValue)) {
                return paramValue;
            } else if (wrapper.getInputControl().isMandatory()) {
                return createDefaultValueAsFirstListResult(wrapper);
            }
        }

        return null;
    }

    private boolean isValuePresentInList(RuntimeInputControlWrapper wrapper, Object value) {
        boolean present = false;

        if (wrapper.isQuery()) {
            if (wrapper.getQueryResults() != null && !wrapper.getQueryResults().isEmpty()) {
                for (Object queryResult: wrapper.getQueryResults().values()) {
                    Object[] valueArray = (Object [])queryResult;
                    if ((value == null && valueArray[0] == null)
                            || (value != null && valueArray[0] != null && value.toString().equals(valueArray[0].toString()))) {
                        present = true;
                        break;
                    }
                }
            }
        } else if (wrapper.isListOfValues()){
            //TODO: handle list of values
            present = true;
        } else {
            //IC doesnt contains any list, so consider any value
            present = true;
        }

        return present;
    }
    
    private InputControl getInputControl(ExecutionContext exContext, ResourceReference inputControlRef) {
        InputControl control;
        if (inputControlRef.isLocal()) {
            control = (InputControl) inputControlRef.getLocalResource();
        } else {
            control = (InputControl) repository.getResource(exContext, inputControlRef.getReferenceURI());
        }
        return control;
    }

    private Format getWrapperFormat(ExecutionContext exContext, InputControl control) {
        Format format = null;
        ResourceReference dataTypeRef = control.getDataType();
        if (dataTypeRef != null) {
            DataType dataType;
            if (!dataTypeRef.isLocal()) {
                //can be accessible with execute-only perms
		        exContext = ExecutionContextImpl.getRuntimeExecutionContext(exContext);
                dataType = (DataType) repository.getResource(exContext, dataTypeRef.getReferenceURI());
                control.setDataType(dataType);
            }
            else
                dataType = (DataType) dataTypeRef.getLocalResource();

            switch (dataType.getType()) {
                case DataType.TYPE_DATE:
                    format = getDateFormat(true);
                    break;
                case DataType.TYPE_DATE_TIME:
                    format = getDatetimeFormat(true);
                    ((DateFormat)format).setTimeZone(JasperServerUtil.getTimezone(exContext));
                    break;
                case DataType.TYPE_NUMBER:
                    if (dataType.getRegularExpr() != null && dataType.getRegularExpr().length() > 0){
                        format = new DecimalFormat(dataType.getRegularExpr());
                    } else {
                        DecimalFormat df = (DecimalFormat) NumberFormat.getNumberInstance(LocaleContextHolder.getLocale());
                        String separator = Character.toString(df.getDecimalFormatSymbols().getDecimalSeparator());

                        if (separator.equals(".")) {
                            df.applyLocalizedPattern("###.###");
                            format = df;
                        } else if (separator.equals(",")) {
                            df.applyLocalizedPattern("###,###");
                            format = df;
                        }
                    }
            }
        }
        return format;
    }

    private Map<String, Object> getWrapperValueFromRequest(ExecutionContext exContext, List inputControls, RequestContext context) {
        Map<String, Object> controlValues = new HashMap<String, Object>();

        if (context == null || exContext == null || inputControls == null) {
            return controlValues;
        }
        
        List<RuntimeInputControlWrapper> wrappersList = new ArrayList<RuntimeInputControlWrapper>();

        for (Object controlObj: inputControls) {
            InputControl control = getInputControl(exContext, (ResourceReference)controlObj);
            RuntimeInputControlWrapper wrapper = new RuntimeInputControlWrapper(control);
            String uriString = control.getURIString().replace("/", "\\/"); //escape slashes for javascript.
            wrapper.setResourceUriPrefix(uriString);
            wrapper.setFormat(getWrapperFormat(exContext, control));

            wrappersList.add(wrapper);
        }

        ServletRequest request = JasperServerUtil.getServletRequestFromRequestContext(context);
        Map requestParametersMap = request.getParameterMap();

        for (Iterator i = wrappersList.iterator(); i.hasNext(); ) {
            RuntimeInputControlWrapper wrapper = (RuntimeInputControlWrapper)i.next();
            String parameterName = getParameterName(wrapper);

            String markerParamName = getMarkerParameterPrefix() + parameterName;
            if (!requestParametersMap.containsKey(parameterName) && !requestParametersMap.containsKey(markerParamName)) {
                i.remove();
            }
        }

        parseRequest(request.getParameterMap(), wrappersList, false);

        for (RuntimeInputControlWrapper wrapper: wrappersList) {
            controlValues.put(wrapper.getInputControl().getName(), wrapper.getValue());            
        }

        return controlValues;
    }


    protected MessageSource loadMessageSource(ExecutionContext exContext, ReportUnit reportUnit) {
        List resources = reportUnit.getResources();

        Map<String, RepositoryResourceKey> map = new LinkedHashMap<String, RepositoryResourceKey>();
        Set<String> baseNames = new LinkedHashSet<String>();

        for (int i = 0; i < resources.size(); ++i) {
            ResourceReference resRef = (ResourceReference) resources.get(i);

            Resource genericResource;
            if (resRef.isLocal()) {
                genericResource = resRef.getLocalResource();
            } else {
                genericResource = repository.getResource(exContext, resRef.getReferenceURI());
            }

            if (!(genericResource instanceof FileResource)) {
                continue;
            }

            FileResource resource = (FileResource) genericResource;
            String fileName = resource.getName();
            String fileType = resource.getFileType();
            boolean isBundle = (fileType != null) ?
                    fileType.equals(FileResource.TYPE_RESOURCE_BUNDLE) : ResourceBundleHelper.isBundle(fileName);

            if (!isBundle) {
                continue;
            }

            map.put(fileName, new RepositoryResourceKey(resource));

            String baseName = ResourceBundleHelper.getBaseName(fileName);

            if (baseName != null && baseName.length() != 0) {
                baseNames.add(baseName);
            }
        }

        if (map.isEmpty()) {
            return null;
        } else {
            setupThreadRepositoryContext(exContext);

            ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
            messageSource.setBundleClassLoader(
                    new RepositoryResourceClassLoader(Thread.currentThread().getContextClassLoader(), map, false));
            messageSource.setBasenames(baseNames.toArray(new String[baseNames.size()]));

            return messageSource;
        }
    }

    protected void setupThreadRepositoryContext(ExecutionContext exContext) {
        if (RepositoryUtil.getThreadRepositoryContext() == null) {
            RepositoryContext rc = new RepositoryContext();
            rc.setRepository(repository);
            rc.setExecutionContext(exContext);
            RepositoryUtil.setThreadRepositoryContext(rc);
        }
    }

    /**
     *
     */
    protected OrderedMap executeQuery(ResourceReference queryReference, ResourceReference dataSourceReference, RuntimeInputControlWrapper wrapper,
            Map parameters)
    {
        InputControl control = wrapper.getInputControl();
        String valueColumn = control.getQueryValueColumn();
        String[] visibleColumns = control.getQueryVisibleColumns();

        OrderedMap results = engine.executeQuery(null, queryReference, valueColumn, visibleColumns, dataSourceReference, parameters);

        if (results == null) {
            return null;
        }

        OrderedMap inputData = new LinkedMap();
        for (Iterator it = results.entrySet().iterator(); it.hasNext();) {
            Map.Entry entry = (Map.Entry) it.next();
            Object keyValue = entry.getKey();
            String[] columnValues = (String[]) entry.getValue();

            String columnValuesString = "";
            if (columnValues != null && columnValues.length > 0) {
                StringBuffer visibleColumnBuffer = new StringBuffer();
                for (int i = 0; i < columnValues.length; i++) {
                    visibleColumnBuffer.append(COLUMN_VALUE_SEPARATOR);
                    visibleColumnBuffer.append(columnValues[i] != null ? columnValues[i] : "");
                }
                columnValuesString = visibleColumnBuffer.substring(COLUMN_VALUE_SEPARATOR_LENGTH);
            }

            inputData.put( (keyValue == null ? null : keyValue.toString()), new Object[] {keyValue, columnValuesString});
        }

        return inputData;
    }

    public Event setInputValues(RequestContext context)
    {
        List<RuntimeInputControlWrapper> wrappers = getInputControlWrappers(context);
        boolean valid = parseRequest(context, wrappers, true);

        if (log.isDebugEnabled())
        {
            log.debug("Input values valid: " + valid);
        }

        if (!valid) {
            StringBuffer sb = new StringBuffer();
            sb.append("<div id=\"wrappersErrors\" class=\"hidden\">");
            sb.append(getWrappersErrorsAsJSON(wrappers).toString());
            sb.append("</div>");
            context.getFlashScope().put(AJAX_RESPONSE_MODEL, sb.toString());
                                                                  
            return error();
        }

        return success();
    }

    protected JSONObject getWrappersErrorsAsJSON(List wrappers) {
        Map<String, String> wrappersErrorMessages = new HashMap<String, String>();
        for (Object icw : wrappers) {
            RuntimeInputControlWrapper wrapper = (RuntimeInputControlWrapper)icw;
            if (wrapper.getErrorMessage() != null) {
                wrappersErrorMessages.put(wrapper.getInputControl().getName(), wrapper.getErrorMessage());
            }
        }

        return new JSONObject(wrappersErrorMessages);
    }

    /**
     * @deprecated Use parseRequest(Map requestParameters, List wrappers, boolean interactiveParameters)
     * to allow wider usage
     */
    protected boolean parseRequest(RequestContext context, List wrappers, boolean interactiveParameters) {
        ServletRequest request = JasperServerUtil.getServletRequestFromRequestContext(context);
        if (request != null) {
            return parseRequest(request.getParameterMap(), wrappers, interactiveParameters);
        } else {
            return false;
        }
    }


    protected boolean parseRequest(Map requestParameters, List wrappers, boolean interactiveParameters)
    {
        boolean isValid = true;

        for (int i = 0; i < wrappers.size(); i++)
        {
            RuntimeInputControlWrapper wrapper = (RuntimeInputControlWrapper) wrappers.get(i);
            boolean parsed = parseRequestInput(requestParameters, interactiveParameters, wrapper);
            boolean valueValid = parsed && validateValue(wrapper, interactiveParameters);
            isValid = isValid && valueValid;
        }

        return isValid;
    }

    /**
     * @deprecated Use parseRequestInput(Map requestParameters, boolean interactiveParameters, RuntimeInputControlWrapper wrapper)
     * to allow wider usage
     */
    protected boolean parseRequestInput(RequestContext context, boolean interactiveParameters, RuntimeInputControlWrapper wrapper) {
        ServletRequest request = JasperServerUtil.getServletRequestFromRequestContext(context);
        if (request != null) {
            return parseRequestInput(request.getParameterMap(), interactiveParameters, wrapper);
        } else {
            return false;
        }
    }

    protected boolean parseRequestInput(Map requestParameters, boolean interactiveParameters, RuntimeInputControlWrapper wrapper) {
        wrapper.setErrorMessage(null);

        boolean parsed;
        if (wrapper.isMulti()) {
            parsed = parseRequestValues(requestParameters, wrapper, interactiveParameters);
        } else {
            parsed = parseRequestValue(requestParameters, wrapper, interactiveParameters);
        }
        return parsed;
    }

    protected String getParameterName(RuntimeInputControlWrapper wrapper)
    {
        InputControl control = wrapper.getInputControl();
        String paramName;
        if (getInputNamePrefix() == null)
        {
            paramName = control.getName();
        }
        else
        {
            paramName = getInputNamePrefix() + control.getName();
        }
        return paramName;
    }

    /**
     * @deprecated Use parseRequestValue(Map requestParameters, RuntimeInputControlWrapper wrapper, boolean interactiveParameters)
     * to allow wider usage
     */
    protected boolean parseRequestValue(RequestContext context, RuntimeInputControlWrapper wrapper, boolean interactiveParameters)
    {
        ServletRequest request = JasperServerUtil.getServletRequestFromRequestContext(context);
        if (request != null) {
            return parseRequestValue(request.getParameterMap(), wrapper, interactiveParameters);
        } else {
            return false;
        }
    }

    protected boolean parseRequestValue(Map requestParameters, RuntimeInputControlWrapper wrapper, boolean interactiveParameters)
    {
        wrapper.setErrorMessage(null);//resetting error message

        String parameterName = getParameterName(wrapper);

        if (!interactiveParameters && !requestParameters.containsKey(parameterName))
        {
            return true;
        }

        String[] strValues = ((String[])requestParameters.get(parameterName));
        String strValue;
        if (strValues==null) {
            strValue = null;
        } else {
            strValue = strValues[0];
            // Replace null substitute string with actual null value
            if (NULL_SUBSTITUTE.equals(strValue)) {
                strValue = null;
            } else if (NOTHING_SUBSTITUTE.equals(strValue)) {
                wrapper.setValue(wrapper.getControlInfo().getDefaultValue());
                return true;
            }
        }

        InputControl control = wrapper.getInputControl();
        DataType dataType = getDatatype(control, repository);

        if (control.getType() == InputControl.TYPE_BOOLEAN)
        {
            if (interactiveParameters)
            {
                wrapper.setValue(Boolean.valueOf(strValue != null));
            }
            else
            {
                wrapper.setValue(Boolean.valueOf(strValue == null || !strValue.equals("false")));
            }
            return true;
        }

        // comment this out due to #17016 additional fix, let's allow to pass an empty string as a value
//        if (strValue != null && strValue.trim().length() == 0)
//        {
//            strValue = null;
//        }

        if (control.getType() == InputControl.TYPE_SINGLE_SELECT_LIST_OF_VALUES
                || control.getType() == InputControl.TYPE_SINGLE_SELECT_LIST_OF_VALUES_RADIO) {
            wrapper.setValue(getLovValue(wrapper, strValue));
            return true;
        }

        if (control.getType() == InputControl.TYPE_SINGLE_SELECT_QUERY
                || control.getType() == InputControl.TYPE_SINGLE_SELECT_QUERY_RADIO) {
            wrapper.setValue(getQueryValue(wrapper, strValue));
            return true;
        }

        if (dataType == null || strValue == null)
        {
            wrapper.setValue(null);
            return true;
        }

        switch(dataType.getType())
        {
            case DataType.TYPE_TEXT :
            {
                wrapper.setValue(strValue);
                break;
            }
            case DataType.TYPE_NUMBER :
            {
                //FIXME take care of input mask
                try
                {
                    // Convert empty string value to null for number type
                    if (strValue == null || strValue.trim().length() == 0) {
                        wrapper.setValue(null);
                    } else {
                        // Getting the right decimal value according to current locale
                        DecimalFormat df = (DecimalFormat) NumberFormat.getNumberInstance(LocaleContextHolder.getLocale());
                        df.setGroupingUsed(false);
                        String separator = Character.toString(df.getDecimalFormatSymbols().getDecimalSeparator());

                        if (separator.equals(".") && strValue.lastIndexOf(".") > 0) {
                            wrapper.setValue(df.format(new BigDecimal(strValue)));
                        } else if (separator.equals(",") && strValue.lastIndexOf(",") > 0) {
                            wrapper.setValue(df.format(new BigDecimal(strValue.replace(",","."))));
                        } else if (strValue.lastIndexOf(".") < 0 && strValue.lastIndexOf(",") < 0) {
                            wrapper.setValue(new BigDecimal(strValue));
                        } else {
                            throw (new NumberFormatException());
                        }

                    }
                }
                catch(NumberFormatException e)
                {
                    wrapper.setErrorMessage(messages.getMessage("fillParameters.error.invalidFloat", null, LocaleContextHolder.getLocale()));
                    wrapper.setValue(strValue);
                }
                break;
            }
            case DataType.TYPE_DATE :
            {
                DateFormat format = getDateFormat(interactiveParameters);

                try
                {
                	ReportInputControlInformation rici = wrapper.getControlInfo();
                	Class paramClass = (rici == null) ? null : rici.getValueType();
                    // Convert empty string value to null for date type
                    if (strValue == null || strValue.trim().length() == 0) {
                        wrapper.setValue(null);
                    } else {
                        wrapper.setValue(convertToProperSubclass(format.parse(strValue), paramClass));
                    }
                }
                catch (ParseException e)
                {
                    wrapper.setErrorMessage(messages.getMessage("fillParameters.error.invalidDate", null, LocaleContextHolder.getLocale()));
                    wrapper.setValue(strValue);
                }
                break;
            }
            case DataType.TYPE_DATE_TIME :
            {
                DateFormat format = getDatetimeFormat(interactiveParameters);
                format.setTimeZone(((DateFormat) wrapper.getFormat()).getTimeZone());
                try
                {
                	ReportInputControlInformation rici = wrapper.getControlInfo();
                	Class paramClass = (rici == null) ? null : rici.getValueType();
                    // Convert empty string value to null for date type
                    if (strValue == null || strValue.trim().length() == 0) {
                        wrapper.setValue(null);
                    } else {
                        wrapper.setValue(convertToProperSubclass(format.parse(strValue), paramClass));
                    }
                }
                catch (ParseException e)
                {
                    wrapper.setErrorMessage(messages.getMessage("fillParameters.error.invalidDateTime", null, LocaleContextHolder.getLocale()));
                    wrapper.setValue(strValue);
                }
                break;
            }
        }

        return wrapper.getErrorMessage() == null;
    }

    protected Date convertToProperSubclass(Date value, Class parameterClass) {
        if (java.sql.Timestamp.class.equals(parameterClass)) {
            return new java.sql.Timestamp(value.getTime());
        }
        if (java.sql.Date.class.equals(parameterClass)) {
            return new java.sql.Date(value.getTime());
        }
        if (java.sql.Time.class.equals(parameterClass)) {
            // strip off date part
            java.util.GregorianCalendar cal = new java.util.GregorianCalendar();
            cal.setTime(value);
            cal.clear(Calendar.YEAR);
            cal.clear(Calendar.MONTH);
            cal.clear(Calendar.DATE);
            return new java.sql.Date(cal.getTimeInMillis());
        }
        return value;
    }

    /**
     * @deprecated Use parseRequestValues(Map requestParameters, RuntimeInputControlWrapper wrapper, boolean interactiveParameters)
     * to allow wider usage
     */
    protected boolean parseRequestValues(RequestContext context, RuntimeInputControlWrapper wrapper, boolean interactiveParameters) {
        ServletRequest request = JasperServerUtil.getServletRequestFromRequestContext(context);
        if (request != null) {
            return parseRequestValues(request.getParameterMap(), wrapper, interactiveParameters);
        } else {
            return false;
        }
    }

    protected boolean parseRequestValues(Map requestParameters, RuntimeInputControlWrapper wrapper, boolean interactiveParameters) {
        InputControl control = wrapper.getInputControl();

        String parameterName = getParameterName(wrapper);

        if (!interactiveParameters)
        {
            //for direct URL, if no value on the request and no marker parameter found, don't set any value
            String markerParamName = getMarkerParameterPrefix() + parameterName;
            if (!requestParameters.containsKey(parameterName) && !requestParameters.containsKey(markerParamName))
            {
                return true;
            }
        }

        String[] strValues = (String[])requestParameters.get(parameterName);
        if (strValues == null) {
            strValues = new String[0];
        }

        // if values is provided in string format: "[1, 2, 3]"
        // (for example using drill through link)
        // needs to parse them.
        if (strValues.length == 1 && strValues[0] != null && strValues[0].startsWith("[") && strValues[0].endsWith("]")) {
            strValues = strValues[0].substring(1, strValues[0].length() - 1).split(",\\s");
        }

        for (int i = 0; i < strValues.length; i++) {
            // Replace null substitute string with actual null value
            if (NULL_SUBSTITUTE.equals(strValues[i])) {
                strValues[i] = null;
            }
        }

        if (control.getType() == InputControl.TYPE_MULTI_SELECT_LIST_OF_VALUES
            || control.getType() == InputControl.TYPE_MULTI_SELECT_LIST_OF_VALUES_CHECKBOX) {
            Set values = new ListOrderedSet();
            for (int i = 0; i < strValues.length; i++) {
                values.add(getLovValue(wrapper, strValues[i]));
            }
            wrapper.setValue(values);
            return true;
        }

        if (control.getType() == InputControl.TYPE_MULTI_SELECT_QUERY
            || control.getType() == InputControl.TYPE_MULTI_SELECT_QUERY_CHECKBOX) {
            Set values = new ListOrderedSet();
            for (int i = 0; i < strValues.length; i++) {
                values.add(getQueryValue(wrapper, strValues[i]));
            }
            wrapper.setValue(values);
            return true;
        }

        return true;
    }

    protected boolean validateValues(List wrappers, boolean setMissingMessage) {
        boolean valid = true;
        for (Iterator it = wrappers.iterator(); it.hasNext();) {
            RuntimeInputControlWrapper inputWrapper = (RuntimeInputControlWrapper) it.next();
            valid &= validateValue(inputWrapper, setMissingMessage);
        }
        return valid;
    }

    protected boolean validateValue(RuntimeInputControlWrapper wrapper, boolean setMissingMessage) {
        Object value = wrapper.getValue();

        boolean empty;
        if (wrapper.isMulti()) {
            empty = value == null || ((Collection) value).isEmpty();
        } else {
            empty = value == null;
        }

        if (empty) {
            if (wrapper.getInputControl().isMandatory()) {
                if (setMissingMessage) {
                    wrapper.setErrorMessage(messages.getMessage("fillParameters.error.mandatoryField", null, LocaleContextHolder.getLocale()));
                }
                return false;
            }

            return true;
        }

        DataType dataType = getDatatype(wrapper.getInputControl(), repository);
        if (dataType == null) {
            return true;
        }

        if (dataType.getType() == DataType.TYPE_TEXT) {
            String strValue = (String) value;
            if (dataType.getMaxLength() != null
                    && dataType.getMaxLength().intValue() < strValue.length()) {
                wrapper.setErrorMessage(messages.getMessage("fillParameters.error.invalidType", null, LocaleContextHolder.getLocale()));
                return false;
            } else if (dataType.getRegularExpr() != null
                    && dataType.getRegularExpr().trim().length() > 0
                    && strValue.length() > 0
                    && !Pattern.matches(dataType.getRegularExpr(), strValue)) {
                wrapper.setErrorMessage(messages.getMessage("fillParameters.error.invalidPattern", null, LocaleContextHolder.getLocale()));
                return false;
            }
        }

        Comparable compValue = (Comparable) value;

        final Comparable minValue = realDatatypeValue(dataType, dataType.getMinValue());
        if (minValue != null) {
            if (dataType.isStrictMin()) {
                if (minValue.compareTo(compValue) >= 0) {
                    wrapper.setErrorMessage(messages.getMessage(
                            "fillParameters.error.smallerThan", null, LocaleContextHolder.getLocale()));
                }
            } else if (minValue.compareTo(compValue) > 0) {
                wrapper.setErrorMessage(messages.getMessage(
                        "fillParameters.error.smallerOrEqual", null, LocaleContextHolder.getLocale()));
            }
        }

        final Comparable maxValue = realDatatypeValue(dataType, dataType.getMaxValue());
        if (maxValue != null) {
            if (dataType.isStrictMax()) {
                if (maxValue.compareTo(compValue) <= 0) {
                    wrapper.setErrorMessage(messages.getMessage(
                            "fillParameters.error.greaterThan", null, LocaleContextHolder.getLocale()));
                }
            } else if (maxValue.compareTo(compValue) < 0) {
                wrapper.setErrorMessage(messages.getMessage(
                        "fillParameters.error.greaterOrEqual", null, LocaleContextHolder.getLocale()));
            }
        }

        return wrapper.getErrorMessage() == null;
    }


    protected Comparable realDatatypeValue(DataType dataType, Comparable value) {
        Comparable rValue = value;
        if (rValue != null) {
            if (rValue instanceof String && ((String) rValue).length() == 0) {
                rValue = null;
            } else if (dataType.getType() == DataType.TYPE_NUMBER) {
                rValue = toInputControlNumber(value);
            }
        }
        return rValue;
    }

    protected Object getLovValue(RuntimeInputControlWrapper wrapper, String strValue) {
        return strValue;
    }


    protected Object getQueryValue(RuntimeInputControlWrapper wrapper, String strValue) {
        return strValue;
    }

    protected DateFormat getDateFormat(boolean interactiveParameters) {
        DateFormat format;

        if (interactiveParameters) {
            format = getCalendarFormatProvider().getDateFormat();
        } else {
            format = new SimpleDateFormat(getStaticDatePattern());
        }
        return format;
    }

    protected DateFormat getDatetimeFormat(boolean interactiveParameters) {
        DateFormat format;
        if (interactiveParameters) {
            format = getCalendarFormatProvider().getDatetimeFormat();
        } else {
            format = new SimpleDateFormat(getStaticDatePattern());
        }
        return format;
    }


    /**
     * Converts BigDecimal numbers to the the type they should be based on
     * what the JRParameters say.
     *
     * @todo add float and dobule
     * @todo move this routine to a shared static location so others can use it
     *
     * @param reportName the name of the report
     * @param wrappers Wrappers around InputControls which allow it to store values and error messages
     */
    protected Map bindParameterValues(String reportName, List wrappers)
    {
        Map parameterValues = new HashMap();

        for (Iterator it = wrappers.iterator(); it.hasNext();)
        {
            RuntimeInputControlWrapper wrapper  = (RuntimeInputControlWrapper)it.next();
            String parameterName = wrapper.getInputControl().getName();//FIXME naming convention to replace when adding mapping
            ReportInputControlInformation controlInfo = wrapper.getControlInfo();
            if (controlInfo != null)
            {
                Object value = wrapper.getValue();

                if (value != null) {
                    Class parameterType = controlInfo.getValueType();

                    if (wrapper.isMulti()) {
                        if (value instanceof List) {
                            value = new HashSet((List)value);
                        }
                        value = getParameterMultiValue(controlInfo, (Set) value);
                    } else {
                        value = toParameterSingleValue(parameterType, value);
                    }
                }

                parameterValues.put(parameterName, value);
            }
        }

        return parameterValues;
    }

    protected Object toParameterSingleValue(Class parameterType, Object value) {
        if (Number.class.isAssignableFrom(parameterType)) {
            value = getParameterNumberValue(parameterType, value);
        } else if (Date.class.isAssignableFrom(parameterType)) {
            value = getParameterDateValue(parameterType, value);
        } else if (String.class.equals(parameterType)) {
            value = value.toString();
        }
        return value;
    }

    protected Object getParameterNumberValue(Class type, Object value) {
        if (value instanceof String)
        {
            // Getting the right decimal value according to current locale
            DecimalFormat df = (DecimalFormat) NumberFormat.getNumberInstance(LocaleContextHolder.getLocale());
            df.setGroupingUsed(false);
            String separator = Character.toString(df.getDecimalFormatSymbols().getDecimalSeparator());

            if (separator.equals(".") && ((String)value).lastIndexOf(".") > 0) {
                value = new BigDecimal((String)value);
            } else if (separator.equals(",") && ((String)value).lastIndexOf(",") > 0) {
                value = new BigDecimal(((String)value).replace(",","."));
            } else if (((String)value).lastIndexOf(".") < 0 && ((String)value).lastIndexOf(",") < 0) {
                value = new BigDecimal((String)value);
            } else {
                throw (new NumberFormatException());
            }
        }
        else if (!(value instanceof Number))
        {
            throw new JSException("Cannot convert input value \"" + value + "\" of type " + value.getClass().getName() + " to a numerical parameter");
        }

        String className = type.getName();
        if (Byte.class.getName().equals(className))
        {
            value = new Byte(((Number)value).byteValue());
        }
        else if (Short.class.getName().equals(className))
        {
            value = new Short(((Number)value).shortValue());
        }
        else if (Integer.class.getName().equals(className))
        {
            value = new Integer(((Number)value).intValue());
        }
        else if (Long.class.getName().equals(className))
        {
            value = new Long(((Number)value).longValue());
        }
        else if (Float.class.getName().equals(className))
        {
            value = new Float(((Number)value).floatValue());
        }
        else if (Double.class.getName().equals(className))
        {
            value = new Double(((Number)value).doubleValue());
        }
        else if (BigInteger.class.getName().equals(className))
        {
            if (value instanceof BigDecimal)
            {
                value = ((BigDecimal) value).toBigInteger();
            }
            else if (!(value instanceof BigInteger))
            {
                value = BigInteger.valueOf(((Number) value).longValue());
            }
        }
        return value;
    }

    protected Object getParameterDateValue(Class type, Object value) {
        if (!(value instanceof Date)) {
            throw new JSException("exception.report.unsupported.date.input.value",
                    new Object[]{value, value.getClass().getName()});
        }
        Date dateValue = (Date) value;

        Date parameterValue;
        String parameterClassName = type.getName();
        if (Date.class.getName().equals(parameterClassName)) {
            parameterValue = dateValue;
        } else if (java.sql.Date.class.getName().equals(parameterClassName)) {
            parameterValue = new java.sql.Date(dateValue.getTime());
        } else if (java.sql.Timestamp.class.getName().equals(parameterClassName)) {
            parameterValue = new java.sql.Timestamp(dateValue.getTime());
        } else {
            throw new JSException("exception.report.unsupported.date.parameter.type",
                    new Object[]{parameterClassName});
        }
        return parameterValue;
    }

    protected Object getParameterMultiValue(ReportInputControlInformation controlInfo,
            Set values) {
        Object value;
        Class paramType = controlInfo.getValueType();
        if (paramType.equals(Object.class)
            || paramType.equals(Collection.class)
            || paramType.equals(Set.class)
            || paramType.equals(List.class)) {
            Collection paramValues;
            if (paramType.equals(List.class)) {
                //if the parameter type is list, use a list
                paramValues = new ArrayList(values.size());
            } else {
                //else use an ordered set
                paramValues = new ListOrderedSet();
            }

            Class componentType = controlInfo.getNestedType();
            for (Iterator it = values.iterator(); it.hasNext();) {
                Object val = (Object) it.next();
                Object paramValue;
                if (componentType == null) {
                    //no conversion if no nested type set for the parameter
                    paramValue = val;
                } else {
                    paramValue = toParameterSingleValue(componentType, val);
                }
                paramValues.add(paramValue);
            }
            value = paramValues;
        } else if (paramType.isArray()) {
            Class componentType = paramType.getComponentType();
            value = Array.newInstance(componentType, values.size());
            int idx = 0;
            for (Iterator iter = values.iterator(); iter.hasNext(); ++idx) {
                Object val = iter.next();
                Object paramValue = toParameterSingleValue(componentType, val);
                Array.set(value, idx, paramValue);
            }
        } else {
            throw new JSException("jsexception.unknown.parameter.type.for.multiple.value.input", new Object[] {paramType.getName()});
        }
        return value;
    }


    protected String getCalendarDatePattern()
    {
        return getCalendarFormatProvider().getCalendarDatePattern();
    }


    protected String getCalendarDatetimePattern()
    {
        return getCalendarFormatProvider().getCalendarDatetimePattern();
    }

    /*
         * method to get the reposervice object arguments: none returns:
         * RepositoryService
         */
    public RepositoryService getRepository() {
        return repository;
    }

    /*
     * method to set the reposervice object arguments: RepositoryService
     * returns: void
     */
    public void setRepository(RepositoryService repository) {
        this.repository = repository;
    }


    public MessageSource getMessages()
    {
        return messages;
    }

    public void setMessages(MessageSource messages)
    {
        this.messages = messages;
    }

    public EngineService getEngine() {
        return engine;
    }

    public void setEngine(EngineService engine) {
        this.engine = engine;
    }

    public String getReportUnitAttrName() {
        return reportUnitAttrName;
    }

    public void setReportUnitAttrName(String reportUnitAttrName) {
        this.reportUnitAttrName = reportUnitAttrName;
    }

    public String getHasInputControlsAttrName() {
        return hasInputControlsAttrName;
    }

    public void setHasInputControlsAttrName(String hasInputControlsAttrName) {
        this.hasInputControlsAttrName = hasInputControlsAttrName;
    }

    public String getStaticDatePattern() {
        return staticDatePattern;
    }

    public void setStaticDatePattern(String staticDatePattern) {
        this.staticDatePattern = staticDatePattern;
    }

    /**
     * @return Returns the reportUnitObjectAttrName.
     */
    public String getReportUnitObjectAttrName() {
        return reportUnitObjectAttrName;
    }

    /**
     * @param reportUnitObjectAttrName The reportUnitObjectAttrName to set.
     */
    public void setReportUnitObjectAttrName(String reportUnitObjectAttrName) {
        this.reportUnitObjectAttrName = reportUnitObjectAttrName;
    }

    /**
     * @return Returns the controlsDisplayFormAttrName.
     */
    public String getControlsDisplayFormAttrName() {
        return controlsDisplayFormAttrName;
    }

    public String getMessageSourceObjectAttrName() {
        return messageSourceObjectAttrName;
    }

    public void setMessageSourceObjectAttrName(String messageSourceObjectAttrName) {
        this.messageSourceObjectAttrName = messageSourceObjectAttrName;
    }

    /**
     * @param controlsDisplayFormAttrName The controlsDisplayFormAttrName to set.
     */
    public void setControlsDisplayFormAttrName(String controlsDisplayFormAttrName) {
        this.controlsDisplayFormAttrName = controlsDisplayFormAttrName;
    }

    /**
     * @return Returns the reportDisplayFormAttrName.
     */
    public String getReportDisplayFormAttrName() {
        return reportDisplayFormAttrName;
    }

    /**
     * @param reportDisplayFormAttrName The reportDisplayFormAttrName to set.
     */
    public void setReportDisplayFormAttrName(String reportDisplayFormAttrName) {
        this.reportDisplayFormAttrName = reportDisplayFormAttrName;
    }

    /**
     * @return Returns the calendarDatePatternAttrName.
     */
    public String getCalendarDatePatternAttrName()
    {
        return calendarDatePatternAttrName;
    }

    /**
     * @param calendarDatePatternAttrName The calendarDatePatternAttrName to set.
     */
    public void setCalendarDatePatternAttrName(String calendarDatePatternAttrName)
    {
        this.calendarDatePatternAttrName = calendarDatePatternAttrName;
    }

    public CalendarFormatProvider getCalendarFormatProvider() {
        return calendarFormatProvider;
    }

    public void setCalendarFormatProvider(
            CalendarFormatProvider calendarFormatProvider) {
        this.calendarFormatProvider = calendarFormatProvider;
    }

    public String getCalendarDatetimePatternAttrName() {
        return calendarDatetimePatternAttrName;
    }

    public void setCalendarDatetimePatternAttrName(
            String calendarDatetimePatternAttrName) {
        this.calendarDatetimePatternAttrName = calendarDatetimePatternAttrName;
    }

    public String getInputNamePrefix() {
        return inputNamePrefix;
    }

    public void setInputNamePrefix(String inputNamePrefix) {
        this.inputNamePrefix = inputNamePrefix;
    }

    public String getMarkerParameterPrefix() {
        return markerParameterPrefix;
    }

    public void setMarkerParameterPrefix(String markerParameterPrefix) {
        this.markerParameterPrefix = markerParameterPrefix;
    }

    public String getControlsDisplayViewAttrName() {
        return controlsDisplayViewAttrName;
    }

    public void setControlsDisplayViewAttrName(String controlsDisplayViewAttrName) {
        this.controlsDisplayViewAttrName = controlsDisplayViewAttrName;
    }

    public String getAttributeInputControlsInformation() {
        return attributeInputControlsInformation;
    }

    public void setAttributeInputControlsInformation(
            String attributeInputControlsInformation) {
        this.attributeInputControlsInformation = attributeInputControlsInformation;
    }
}
