package org.jboss.resteasy.links.test;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import jakarta.el.FunctionMapper;

import org.jboss.logging.Logger;

/**
 * Resolves Seam Security EL functions, s:hasRole() and s:hasPermission()
 * by decorating a delegate Unified EL FunctionMapper
 *
 * @author Shane Bryzak
 */
public class SeamFunctionMapper extends FunctionMapper {
    private static Map<String, List<Method>> methodCache = new HashMap<String, List<Method>>();

    private FunctionMapper functionMapper;
    private static final Logger LOG = Logger.getLogger(SeamFunctionMapper.class);

    public SeamFunctionMapper(final FunctionMapper functionMapper) {
        this.functionMapper = functionMapper;
    }

    static {
        cacheMethod("hasPermission", SecurityFunctions.class, "hasPermission",
                new Class[] { Object.class, String.class });
        cacheMethod("hasRole", SecurityFunctions.class, "hasRole",
                new Class[] { String.class });
    }

    @Override
    public Method resolveFunction(String prefix, String localName) {
        if ("s".equals(prefix)) {
            List<Method> methods = methodCache.get(localName);
            return methods != null ? methods.get(0) : null;
        } else if (functionMapper != null) {
            return functionMapper.resolveFunction(prefix, localName);
        } else {
            return null;
        }
    }

    @Override
    public void mapFunction(String prefix, String localName, Method meth) {
        super.mapFunction(prefix, localName, meth);
    }

    /*
     * @Override
     * public Method resolveFunction(String prefix, String localName, int paramCount)
     * {
     * if ( "s".equals(prefix) )
     * {
     * List<Method> methods = methodCache.get(localName);
     * if (methods != null)
     * {
     * for (Method m : methods)
     * {
     * if (m.getParameterCount() == paramCount) return m;
     * }
     * }
     *
     * return null;
     * }
     * else if (functionMapper != null)
     * {
     * return functionMapper.resolveFunction(prefix, localName);
     * }
     * else
     * {
     * return null;
     * }
     * }
     */

    private static void cacheMethod(String localName, Class<?> cls, String name, Class<?>[] params) {
        try {
            Method m = cls.getMethod(name, params);

            List<Method> methods;
            if (methodCache.containsKey(localName)) {
                methods = methodCache.get(localName);
            } else {
                methods = new ArrayList<Method>();
                methodCache.put(localName, methods);
            }

            methods.add(m);
        } catch (NoSuchMethodException ex) {
            LOG.error(String.format("Method %s.%s could not be cached", cls.getName(), name));
        }
    }

}
