/*
 * Copyright (C) 2004 TiongHiang Lee
 *
 * This library 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 library 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 library; if not,  write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Email: thlee@onemindsoft.org
 */

package org.onemind.commons.invoke;

import java.lang.reflect.Method;
import org.onemind.commons.java.lang.reflect.ReflectUtils;
/**
 * An wrapper invocable that will use reflection
 * to optionally use reflection for invocation 
 * if possible  
 * @author TiongHiang Lee (thlee@onemindsoft.org)
 * @version $Id: ReflectionWrapperInvocable.java,v 1.4 2005/01/24 05:52:21 thlee Exp $ $Name:  $
 */
public class ReflectionWrapperInvocable extends AbstractInvocable
{

    /**
     * InvocableFunction which wrap a method
     * @author TiongHiang Lee (thlee@onemindsoft.org)
     * @version $Id: ReflectionWrapperInvocable.java,v 1.4 2005/01/24 05:52:21 thlee Exp $ $Name:  $
     */
    private class ReflectMethodFunction extends AbstractInvocableFunction
    {

        /** the method **/
        private Method _method;

        /**
         * Constructor
         * @param method the method
         */
        public ReflectMethodFunction(Method method)
        {
            super(method.getName(), method.getParameterTypes());
            _method = method;
        }

        /** 
         * {@inheritDoc}
         */
        public Object invoke(Object target, Object[] args) throws Exception
        {
            return _method.invoke(target, args);
        }
    }

    /** the wrappee object **/
    private Object _obj;

    /** whether use reflection **/
    private boolean _reflect;

    /**
     * Constructor
     * @param obj the wrappee
     */
    public ReflectionWrapperInvocable(Object obj)
    {
        this(obj, true);
    }

    /**
     * Constructor
     * @param obj the wrappee
     * @param useReflect whether to use reflection 
     */
    public ReflectionWrapperInvocable(Object obj, boolean useReflect)
    {
        _obj = obj;
        _reflect = useReflect;
    }

    /** 
     * {@inheritDoc}
     */
    public boolean canInvoke(String functionName, Object[] args)
    {
        boolean result = super.canInvoke(functionName, args);
        if (!result && _reflect)
        {
            try
            {
                ReflectUtils.getMethod(_obj.getClass(), functionName, args);
            } catch (NoSuchMethodException e)
            {
                //do nothing
            }
        }
        return result;
    }

    /** 
     * {@inheritDoc}
     */
    public InvocableFunction getFunction(String functionName, Object[] args)
    {
        InvocableFunction f = super.getFunction(functionName, args);
        if (f == null && _reflect)
        {
            try
            {
                Method m = ReflectUtils.getMethod(_obj.getClass(), functionName, args);
                f = new ReflectMethodFunction(m);
                addFunction(f);
            } catch (Exception e)
            {
                //do nothing                
            }
        }
        return f;
    }

    /** 
     * {@inheritDoc}
     */
    public Object invoke(String functionName, Object[] args) throws Exception
    {
        InvocableFunction f = getFunction(functionName, args);
        if (f != null)
        { //good, this is optimized.
            return f.invoke(_obj, args);
        } else
        {
            throw new NoSuchMethodError("Method " + ReflectUtils.toMethodString(functionName, args) + " not found");
        }
    }
}