/*
 * 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.dto;

import java.io.Serializable;
import java.text.Format;
import java.util.*;

import com.jaspersoft.jasperserver.api.common.util.MapEntry;
import com.jaspersoft.jasperserver.api.engine.common.service.ReportInputControlInformation;
import com.jaspersoft.jasperserver.api.metadata.common.domain.InputControl;
import com.jaspersoft.jasperserver.api.metadata.common.domain.ListOfValues;
import com.jaspersoft.jasperserver.war.action.ReportParametersAction;

/**
 *
 */
public class RuntimeInputControlWrapper implements Serializable
{
    private InputControl inputControl;
    private Object value;
    private String errorMessage;
    private Format format;
    private Map queryResults;
    private ReportInputControlInformation controlInfo;
    private String resourceUriPrefix;

    private transient Map multiValueIndicator;
    private String displayLabel;
    private Map<String, String> listOfValuesDisplayLabels = new HashMap<String, String>();

    public RuntimeInputControlWrapper(InputControl inputControl)
    {
        this.inputControl = inputControl;
    }

    public Object getValue()
    {
        return value;
    }

    public void setValue(Object value)
    {
        this.value = value;
        this.multiValueIndicator = null;
    }

    public String getErrorMessage()
    {
        return errorMessage;
    }

    public void setErrorMessage(String errorMessage)
    {
        this.errorMessage = errorMessage;
    }

    public InputControl getInputControl()
    {
        return inputControl;
    }

    public void setInputControl(InputControl inputControl)
    {
        this.inputControl = inputControl;
    }

    public Format getFormat()
    {
        return format;
    }

    public void setFormat(Format format)
    {
        this.format = format;
    }

    public String getFormattedValue()
    {
        try {
            return format.format(value);
        } catch(Exception e) {
            return value != null ? value.toString() : null;
        }
    }

    public Map getQueryResults()
    {
        return queryResults;
    }

    public void setQueryResults(Map queryResults)
    {
        this.queryResults = queryResults;
    }

    public boolean isMulti() {
        if (inputControl == null) {
            return false;
        }

        byte type = inputControl.getType();
        return type == InputControl.TYPE_MULTI_VALUE
                || type == InputControl.TYPE_MULTI_SELECT_LIST_OF_VALUES
                || type == InputControl.TYPE_MULTI_SELECT_LIST_OF_VALUES_CHECKBOX
                || type == InputControl.TYPE_MULTI_SELECT_QUERY
                || type == InputControl.TYPE_MULTI_SELECT_QUERY_CHECKBOX;
    }

    public boolean isMultiDistinctValues() {
        if (inputControl == null) {
            return false;
        }

        byte type = inputControl.getType();
        return
                type == InputControl.TYPE_MULTI_SELECT_LIST_OF_VALUES
                || type == InputControl.TYPE_MULTI_SELECT_LIST_OF_VALUES_CHECKBOX
                || type == InputControl.TYPE_MULTI_SELECT_QUERY
                || type == InputControl.TYPE_MULTI_SELECT_QUERY_CHECKBOX;
    }

    public boolean isListOfValues() {
        byte type = inputControl.getType();
        return
            type == InputControl.TYPE_SINGLE_SELECT_LIST_OF_VALUES
            || type == InputControl.TYPE_SINGLE_SELECT_LIST_OF_VALUES_RADIO
            || type == InputControl.TYPE_MULTI_SELECT_LIST_OF_VALUES
            || type == InputControl.TYPE_MULTI_SELECT_LIST_OF_VALUES_CHECKBOX;
    }

    public boolean isQuery() {
        byte type = inputControl.getType();
        return
            type == InputControl.TYPE_SINGLE_SELECT_QUERY
            || type == InputControl.TYPE_SINGLE_SELECT_QUERY_RADIO
            || type == InputControl.TYPE_MULTI_SELECT_QUERY
            || type == InputControl.TYPE_MULTI_SELECT_QUERY_CHECKBOX;
    }

    public int getCollectionSize() {
        int size;
        if (isListOfValues()) {
            size = ((ListOfValues) getInputControl().getListOfValues().getLocalResource()).getValues().length;
        } else if (isQuery()) {
            size = getQueryResults().size();
        } else {
            throw new UnsupportedOperationException("getCollectionSize can only be called for LOV or query input controls");
        }
        return size;
    }

    public Map getCollectionValueIndicator() {
        if (multiValueIndicator == null) {
            if (isListOfValues() || isQuery()) {
                multiValueIndicator = new IndicatorMap((Collection) getValue());
            }
        }
        return multiValueIndicator;
    }

    protected static class IndicatorMap extends AbstractMap {

        private final Set entries;

        public IndicatorMap(Collection keys) {
            entries = new HashSet();
            if (keys != null) {
                for (Iterator it = keys.iterator(); it.hasNext();) {
                    Object o = (Object) it.next();
                    // Replace actual null value with null substitute string
                    Object key = (o == null) ? ReportParametersAction.NULL_SUBSTITUTE : o;
                    // Making key.toString() - #18331
                    // There are related changes in DefaultParametersForm - <c:if test="${wrapper.collectionValueIndicator[item.key]}">
                    // instead of  - <c:if test="${wrapper.collectionValueIndicator[item.value[0]]}">
                    // because of DWR converts all types to String
                    Map.Entry entry = new MapEntry(key.toString(), Boolean.TRUE);
                    entries.add(entry);
                }
            }
        }

        public Set entrySet() {
            return entries;
        }

    }

    public ReportInputControlInformation getControlInfo() {
        return controlInfo;
    }

    public void setControlInfo(ReportInputControlInformation controlInfo) {
        this.controlInfo = controlInfo;
    }

    public String getResourceUriPrefix() {
        return resourceUriPrefix;
    }

    public void setResourceUriPrefix(String resourceUriPrefix) {
        this.resourceUriPrefix = resourceUriPrefix;
    }

    public String getDisplayLabel() {
        return displayLabel;
    }

    public void setDisplayLabel(String displayLabel) {
        this.displayLabel = displayLabel;
    }

    public Map<String, String> getListOfValuesDisplayLabels() {
        return listOfValuesDisplayLabels;
    }

    public void setListOfValuesDisplayLabels(Map<String, String> listOfValuesDisplayLabels) {
        this.listOfValuesDisplayLabels = listOfValuesDisplayLabels;
    }
}
