package org.jboss.resteasy.client.jaxrs.internal.proxy.extractors;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;

import org.jboss.resteasy.client.jaxrs.i18n.Messages;

/**
 * Implement a client proxy for ProxyFactory. This class implements each method
 * using an EntityExtractor
 *
 * @author <a href="mailto:sduskis@gmail.com">Solomon Duskis</a>
 * @version $Revision: 1 $
 * @see EntityExtractor
 * @see org.jboss.resteasy.client.jaxrs.internal.proxy.extractors.EntityExtractorFactory
 * @see org.jboss.resteasy.client.jaxrs.internal.proxy.extractors.ResponseObjectEntityExtractorFactory
 */
@SuppressWarnings("unchecked")
public class ClientResponseProxy implements InvocationHandler
{
   private ClientContext context;
   private Map<Method, EntityExtractor<?>> methodMap;
   private Class<?> clazz;

   public ClientResponseProxy(final ClientContext context, final Map<Method, EntityExtractor<?>> methodMap, final Class<?> clazz)
   {
      super();
      this.methodMap = methodMap;
      this.clazz = clazz;
      this.context = context;
   }

   public Object invoke(Object o, Method method, Object[] args) throws Throwable
   {
      // equals and hashCode were added for cases where the proxy is added to
      // collections. The Spring transaction management, for example, adds
      // transactional Resources to a Collection, and it calls equals and
      // hashCode.
      if (method.getName().equals("equals"))
      {
         return this.equals(o);
      }
      else if (method.getName().equals("hashCode"))
      {
         return this.hashCode();
      }

      EntityExtractor entityExtractor = methodMap.get(method);
      if (entityExtractor == null)
         throw new RuntimeException(Messages.MESSAGES.couldNotProcessMethod(method));

      return entityExtractor.extractEntity(context, entityExtractor, args);
   }

   @Override
   public boolean equals(Object obj)
   {
      if (obj == null || !(obj instanceof ClientResponseProxy))
         return false;
      ClientResponseProxy other = (ClientResponseProxy) obj;
      if (other == this)
         return true;
      if (other.clazz != this.clazz)
         return false;
      return super.equals(obj);
   }

   @Override
   public int hashCode()
   {
      return clazz.hashCode();
   }

   public String toString()
   {
      return Messages.MESSAGES.clientProxyFor(clazz.getName());
   }
}
