/*
 * 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 com.jaspersoft.jasperserver.api.JSException;
import com.jaspersoft.jasperserver.api.common.domain.impl.ExecutionContextImpl;
import com.jaspersoft.jasperserver.api.metadata.common.domain.DataType;
import com.jaspersoft.jasperserver.api.metadata.common.domain.InputControl;
import com.jaspersoft.jasperserver.api.metadata.common.domain.ResourceReference;
import com.jaspersoft.jasperserver.api.metadata.common.service.RepositoryService;
import com.jaspersoft.jasperserver.war.dto.RuntimeInputControlWrapper;
import org.apache.commons.collections.set.ListOrderedSet;

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

public class ReportParametersUtils {

    public static void setInputControlParameterValue(RuntimeInputControlWrapper wrapper, Object paramValue, RepositoryService repository) {
        wrapper.setErrorMessage(null); // clear any existing error
        Object inputValue = toInputControlValue(wrapper, paramValue, repository);
        wrapper.setValue(inputValue);
    }

    public static Object toInputControlValue(RuntimeInputControlWrapper wrapper, Object paramValue, RepositoryService repository) {
        if (paramValue == null) {
            return null;
        }

        Object value;
        if (wrapper.isMulti()) {
            Set values = toMultiInputControlValue(paramValue);
            value = values;
        } else {
            DataType datatype = getDatatype(wrapper.getInputControl(), repository);
            if (datatype != null) {
                switch (datatype.getType()) {
                case DataType.TYPE_NUMBER:
                    value = toInputControlNumber(paramValue);
                    break;
                case DataType.TYPE_TEXT:
                    value = paramValue.toString();
                    break;
                case DataType.TYPE_DATE:
                case DataType.TYPE_DATE_TIME:
                    value = toInputControlDate(paramValue);
                    break;
                default:
                    value = paramValue;
                    break;
                }
            } else {
                value = paramValue;
            }
        }
        return value;
    }

    public static Set toMultiInputControlValue(Object paramValue) {
        Set values = new ListOrderedSet();
        if (paramValue != null) {
            if (paramValue instanceof Collection) {
                values.addAll((Collection) paramValue);
            } else if (paramValue.getClass().isArray()) {
                int length = Array.getLength(paramValue);
                for (int idx = 0; idx < length; ++idx) {
                    Object val = Array.get(paramValue, idx);
                    values.add(val);
                }
            }
        }
        return values;
    }

    public static DataType getDatatype(InputControl control, RepositoryService repository) {
        ResourceReference dataTypeRef = control.getDataType();
        DataType dataType;
        if (dataTypeRef == null) {
            dataType = null;
        } else if (dataTypeRef.isLocal()) {
            dataType = (DataType) dataTypeRef.getLocalResource();
        } else {
            dataType = (DataType) repository.getResource(new ExecutionContextImpl(), dataTypeRef.getReferenceURI());
        }
        return dataType;
    }

    public static Object toInputControlDate(Object paramValue) {
        Date inputValue;
        if (paramValue instanceof Date) {
            Date dateValue = (Date) paramValue;
            inputValue = new Date(dateValue.getTime());
        } else {
            throw new JSException("exception.report.unrecognized.date.type", new Object[]{paramValue.getClass().getName()});
        }
        return inputValue;
    }

    public static BigDecimal toInputControlNumber(Object paramValue) {
        BigDecimal inputValue;
        if (paramValue instanceof Byte
                || paramValue instanceof Short
                || paramValue instanceof Integer
                || paramValue instanceof Long) {
            inputValue = BigDecimal.valueOf(((Number) paramValue).longValue());
        } else if (paramValue instanceof Float
                || paramValue instanceof Double) {
            inputValue = BigDecimal.valueOf(((Number) paramValue).doubleValue());
        } else if (paramValue instanceof BigDecimal) {
            inputValue = (BigDecimal) paramValue;
        } else if (paramValue instanceof BigInteger) {
            inputValue = new BigDecimal((BigInteger) paramValue);
        } else if (paramValue instanceof String) {
            inputValue = new BigDecimal((String) paramValue);
        } else {
            throw new JSException("exception.report.unrecognized.number.type", new Object[]{paramValue.getClass().getName()});
        }
        return inputValue;
    }
}
