/*
 * JBoss, Home of Professional Open Source
 * Copyright 2010, Red Hat, Inc. and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This 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 software 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.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.richfaces.cdk.templatecompiler.statements;

import static com.google.common.collect.Iterators.forArray;
import static com.google.common.collect.Iterators.toArray;
import static com.google.common.collect.Iterators.transform;
import static org.richfaces.cdk.templatecompiler.el.ELNodeConstants.CONVERT_TO_BOOLEAN_FUNCTION;
import static org.richfaces.cdk.templatecompiler.el.ELNodeConstants.CONVERT_TO_BYTE_FUNCTION;
import static org.richfaces.cdk.templatecompiler.el.ELNodeConstants.CONVERT_TO_CHAR_FUNCTION;
import static org.richfaces.cdk.templatecompiler.el.ELNodeConstants.CONVERT_TO_DOUBLE_FUNCTION;
import static org.richfaces.cdk.templatecompiler.el.ELNodeConstants.CONVERT_TO_FLOAT_FUNCTION;
import static org.richfaces.cdk.templatecompiler.el.ELNodeConstants.CONVERT_TO_INTEGER_FUNCTION;
import static org.richfaces.cdk.templatecompiler.el.ELNodeConstants.CONVERT_TO_LONG_FUNCTION;
import static org.richfaces.cdk.templatecompiler.el.ELNodeConstants.CONVERT_TO_SHORT_FUNCTION;
import static org.richfaces.cdk.templatecompiler.el.ELNodeConstants.CONVERT_TO_STRING_FUNCTION;
import static org.richfaces.cdk.templatecompiler.el.ELNodeConstants.IS_EMPTY_FUNCTION;
import static org.richfaces.cdk.templatecompiler.el.ELNodeConstants.IS_EQUAL_FUNCTION;
import static org.richfaces.cdk.util.JavaUtils.CLASS_TO_CLASS_NAME;

import java.util.Collection;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;

import com.google.common.collect.Maps;

/**
 * @author Nick Belaevski
 *
 */
public enum HelperMethod {

    TO_STRING_CONVERSION(CONVERT_TO_STRING_FUNCTION, String.class, Object.class),
    TO_BOOLEAN_CONVERSION(CONVERT_TO_BOOLEAN_FUNCTION, Boolean.TYPE, Object.class),
    TO_INTEGER_CONVERSION(CONVERT_TO_INTEGER_FUNCTION, Integer.class, Object.class),
    TO_BYTE_CONVERSION(CONVERT_TO_BYTE_FUNCTION, Byte.class, Object.class),
    TO_SHORT_CONVERSION(CONVERT_TO_SHORT_FUNCTION, Short.class, Object.class),
    TO_LONG_CONVERSION(CONVERT_TO_LONG_FUNCTION, Long.class, Object.class),
    TO_FLOAT_CONVERSION(CONVERT_TO_FLOAT_FUNCTION, Float.class, Object.class),
    TO_DOUBLE_CONVERSION(CONVERT_TO_DOUBLE_FUNCTION, Double.class, Object.class),
    TO_CHAR_CONVERSION(CONVERT_TO_CHAR_FUNCTION, Character.class, Object.class),
    EMPTINESS_CHECK(IS_EMPTY_FUNCTION, Boolean.TYPE, Object.class),
    EQUALS_CHECK(IS_EQUAL_FUNCTION, Boolean.TYPE, Object.class, Object.class),
    SHOULD_RENDER_ATTRIBUTE("shouldRenderAttribute", Boolean.TYPE, Object.class),
    CREATE_ATTRIBUTES("attributes", "Attributes"),
    RENDER_ATTRIBUTES_SET("renderPassThroughAttributes", Void.TYPE, FacesContext.class, UIComponent.class, Collection.class),
    RENDER_ATTRIBUTE("renderAttribute", Void.TYPE, FacesContext.class, String.class, Object.class),
    ADD_TO_SCRIPT_HASH("addToScriptHash", Void.TYPE.getName(), Map.class.getName(), String.class.getName(), Object.class
            .getName(), Object.class.getName(), "ScriptHashVariableWrapper"),
    ADD_TO_SCRIPT_HASH_ATTRIBUTES("addToScriptHash", Void.TYPE.getName(), Map.class.getName(), FacesContext.class.getName(),
            UIComponent.class.getName(), "Attributes", "ScriptHashVariableWrapper"),
    TO_SCRIPT_ARGS("toScriptArgs", String.class, Object[].class),
    CONCAT("concat", String.class, String[].class),
    HAS_FACET("hasFacet", Boolean.TYPE, UIComponent.class, String.class);

    public static final EnumMap<HelperMethod, String> METHOD_NAMES = Maps.newEnumMap(HelperMethod.class);
    private static final Set<HelperMethod> CONVERSION_METHODS = EnumSet.of(TO_STRING_CONVERSION, TO_BOOLEAN_CONVERSION,
            TO_INTEGER_CONVERSION, TO_BYTE_CONVERSION, TO_SHORT_CONVERSION, TO_LONG_CONVERSION, TO_FLOAT_CONVERSION,
            TO_DOUBLE_CONVERSION, TO_CHAR_CONVERSION);
    private final String name;
    private final String returnType;
    private final String[] argumentTypes;

    static {
        for (HelperMethod method : HelperMethod.values()) {
            METHOD_NAMES.put(method, method.getName());
        }
    }

    private HelperMethod(String name, String returnType, String... argumentTypes) {
        this.name = name;
        this.returnType = returnType;
        this.argumentTypes = argumentTypes;
    }

    private HelperMethod(String name, Class<?> returnType, Class<?>... argumentTypes) {
        this(name, CLASS_TO_CLASS_NAME.apply(returnType), transformClassesToClassNames(argumentTypes));
    }

    private static String[] transformClassesToClassNames(Class<?>[] s) {
        Iterator<String> transformed = transform(forArray(s), CLASS_TO_CLASS_NAME);
        return toArray(transformed, String.class);
    }

    public String getName() {
        return name;
    }

    public String getReturnType() {
        return returnType;
    }

    public String[] getArgumentTypes() {
        return argumentTypes;
    }

    public static Set<HelperMethod> getConversionMethods() {
        return CONVERSION_METHODS;
    }
}
