package org.codehaus.xfire.client;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.xfire.service.OperationInfo;

/**
 * Proxy implementation for XFire SOAP clients.  Applications will generally use <code>XFireProxyFactory</code> to
 * create proxy clients.
 *
 * @author <a href="mailto:poutsma@mac.com">Arjen Poutsma</a>
 * @see XFireProxyFactory#create
 */
public class XFireProxy
        implements InvocationHandler
{
    private static final Log log = LogFactory.getLog(XFireProxy.class);
    private Client client;

    XFireProxy(Client client)
    {
        this.client = client;
    }

    /**
     * Handles the object invocation.
     *
     * @param proxy  the proxy object to invoke
     * @param method the method to call
     * @param args   the arguments to the proxy object
     */
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable
    {
        String methodName = method.getName();
        Class[] parameterTypes = method.getParameterTypes();
        if (log.isDebugEnabled())
        {
            log.debug("Method [" + methodName + "] " + ((args == null) ? "" : Arrays.asList(args).toString()));
        }
        
        Object result = handleCanonicalMethods(methodName, parameterTypes, args);
        
        if (result == null)
        {
            result = handleRequest(method, args);
        }
        if (log.isDebugEnabled())
        {
            log.debug("Result [" + String.valueOf(result) + "]");
        }
        return result;
    }

    private Object handleRequest(Method m, Object[] args)
            throws Exception
    {
        OperationInfo op = client.getService().getServiceInfo().getOperation(m);
        
        Object[] response = (Object[]) client.invoke(op, args);

        if (response != null && response.length > 0) 
            return response[0];
        else
            return null;
    }

    /**
     * Handles canonical method calls such as <code>equals</code>, <code>hashCode</code>, and <code>toString</code>.
     *
     * @param methodName the method name.
     * @param params     the parameter types.
     * @param args       the arguments
     * @return the result, if <code>methodName</code> is a canonical method; or <code>null</code> if not.
     */
    private Object handleCanonicalMethods(String methodName, Class[] params, Object[] args)
    {
        if (methodName.equals("equals") &&
                params.length == 1
                && params[0].equals(Object.class))
        {
            Object other = args[0];
            if (other == null ||
                    !Proxy.isProxyClass(other.getClass()) ||
                    !(Proxy.getInvocationHandler(other) instanceof XFireProxy))
            {
                return Boolean.FALSE;
            }
            
            XFireProxy otherClient = (XFireProxy) Proxy.getInvocationHandler(other);
            
            return new Boolean(otherClient == this);
        }
        else if (methodName.equals("hashCode") && params.length == 0)
        {
            return new Integer(hashCode());
        }
        else if (methodName.equals("toString") && params.length == 0)
        {
            return "XFireProxy[" + client.getUrl() + "]";
        }
        return null;
    }
}


@@ -773,32 +773,98 @@
  client;%0A    %7D%0A%0A
+    public Client getClient()%0A    %7B%0A        return client;%0A    %7D%0A%0A
     /**%0A     * H
@@ -1428,24 +1428,16 @@
       %7D%0A
-        
 %0A       
@@ -1511,24 +1511,16 @@
  args);%0A
-        
 %0A       
@@ -1934,24 +1934,16 @@
 ion(m);%0A
-        
 %0A       
@@ -1966,19 +1966,8 @@
 se =
- (Object%5B%5D)
  cli
@@ -2041,17 +2041,16 @@
 gth %3E 0)
- 
 %0A       
@@ -2645,20 +2645,16 @@
         
-    
 params.l
@@ -2664,20 +2664,16 @@
 th == 1%0A
-    
         
@@ -2806,20 +2806,16 @@
         
-    
 !Proxy.i
@@ -2843,28 +2843,24 @@
 Class()) %7C%7C%0A
-    
             
@@ -2989,28 +2989,16 @@
       %7D%0A
-            
 %0A       
@@ -3075,28 +3075,16 @@
 other);%0A
-            
 %0A       

Add method to get Client instance