package org.codehaus.parsec.groovy;

import groovy.lang.Closure;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * This class is a general adapter to adapt a closure to any one-method Java interface.
 * <p>
 * @author Ben Yu
 * Jul 27, 2006 3:50:51 PM
 */
public class FromClosure implements InvocationHandler {
  private final Closure closure;
  
  /**
   * to create a FromClosure object.
   * @param closure the closure object.
   */
  protected FromClosure(Closure closure) {
    this.closure = closure;
  }
  public Object invoke(Object proxy, Method method, Object[] args)
      throws Throwable {
    if(isObjectMethod(method)){
      return method.invoke(this, args);
    }
    return closure.call(args);
  }
  public boolean equals(Closure other){
    return closure.equals(other);
  }
  public boolean equals(FromClosure other){
    return closure.equals(other.closure);
  }
  public boolean equals(Object obj) {
    if(obj instanceof Closure){
      return equals((Closure)obj);
    }
    else if(obj instanceof FromClosure){
      return equals((FromClosure)obj);
    }
    else return false;
  }
  public int hashCode() {
    return closure.hashCode();
  }
  public String toString() {
    return closure.toString();
  }
  private static boolean isObjectMethod(Method mtd){
    return mtd.getDeclaringClass().equals(Object.class);
  }
  /**
   * Create a dynamic proxy to adapt a closure to a set of interfaces.
   * @param cloader the class loader object.
   * @param itfs the interfaces.
   * @param closure the closure.
   * @return the proxy object.
   */
  public static Object fromClosure(Closure closure, ClassLoader cloader, Class[] itfs){
    return Proxy.newProxyInstance(cloader, itfs, new FromClosure(closure));
  }
  /**
   * Create a dynamic proxy to adapt a closure to an interface.
   * @param closure the closure object.
   * @param itf the interface.
   * @return the proxy object.
   */
  public static Object fromClosure(Closure closure, Class itf){
    return fromClosure(closure, closure.getClass().getClassLoader(), new Class[]{itf});
  }
}

