package JavaGroups;

import java.io.*;
import java.util.*;
import java.lang.reflect.*;

public class MethodCall implements Serializable {
    protected String  method_name=null;
    protected String  funclet_name=null;
    protected Vector  args=new Vector();


    public MethodCall() {
	
    }
    
    public MethodCall(String name) {
	method_name=name;
    }

    public MethodCall(String name, String funclet_name) {
	this(name);
	this.funclet_name=funclet_name;
    }


    public MethodCall(String name, Object arg1) {      	
	this(name);
	AddArg(arg1);
    }

    public MethodCall(String name, String funclet_name, Object arg1) {
	this(name, funclet_name);
	AddArg(arg1);
    }


    public MethodCall(String name, Object arg1, Object arg2) {
	this(name, arg1);
	AddArg(arg2);
    }

    public MethodCall(String name, String funclet_name, Object arg1, Object arg2) {
	this(name, funclet_name, arg1);
	AddArg(arg2);
    }


    public MethodCall(String name, Object arg1, Object arg2, Object arg3) {
	this(name, arg1, arg2);
	AddArg(arg3);
    }

    public MethodCall(String name, String funclet_name, Object arg1, Object arg2, Object arg3) {
	this(name, funclet_name, arg1, arg2);
	AddArg(arg3);
    }

    

    public String GetName()                 {return method_name;}
    public void   SetName(String n)         {method_name=n;}
    public String GetFuncletName()          {return funclet_name;}
    public void   SetFuncletName(String n)  {funclet_name=n;}    
    public Vector GetArgs()                 {return args;}



    public void AddArg(Object arg) {
	if(arg != null)
	    args.addElement(arg);
    }

    public void AddArg(byte b) {
	Byte obj=new Byte(b);
	args.addElement(obj);
    }

    public void AddArg(char c) {
	Character obj=new Character(c);
	args.addElement(obj);
    }

    public void AddArg(boolean b) {
	Boolean obj=new Boolean(b);
	args.addElement(obj);
    }

    public void AddArg(int i) {
	Integer obj=new Integer(i);
	args.addElement(obj);
    }

    public void AddArg(long l) {
	Long obj=new Long(l);
	args.addElement(obj);
    }





    
    Method FindMethod(Class target_class, String method_name, Vector args) throws Exception {
	int       len=args != null ? args.size() : 0;
	Class[]   formal_parms=new Class[len];
	Method    retval;

	for(int i=0; i < len; i++)
	    formal_parms[i]=args.elementAt(i).getClass();


	/* getDeclaredMethod() is a bit faster, but only searches for methods in the current
	   class, not in superclasses */
	retval=target_class.getMethod(method_name, formal_parms);

	return retval;
    }


    /**
     * Invokes the method with the supplied arguments against the target object.
     * If a method lookup is provided, it will be used. Otherwise, the default
     * method lookup will be used.
     */
    public Object Invoke(Object target, MethodLookup lookup) {
	Class   cl=target.getClass();
	Method  meth;
	Object  retval=null;
	Class   class_args[];
	Object  obj_args[];

	if(method_name == null) {
	    System.out.println("Method name is not provided");
	    return null;
	}
	try {
	    meth=lookup == null ? FindMethod(cl, method_name, args) : 
		                  lookup.FindMethod(cl, method_name, args);
	    obj_args=new Object[args.size()];
	    for(int i=0; i < args.size(); i++)
		obj_args[i]=args.elementAt(i);

	    if(meth != null)
		retval=meth.invoke(target, obj_args);
	    else
		System.err.println("MethodCall.Invoke(): method not found !");
	    return retval;
	}
	catch(IllegalArgumentException illegal_arg) {
	    //System.err.println("MethodCall.Invoke(): " + illegal_arg);
	    retval=illegal_arg;
	}
	catch(IllegalAccessException illegal_access) {
	    retval=illegal_access;
	    illegal_access.printStackTrace();
	    //System.exit(1);
	}
	catch(InvocationTargetException inv_ex) {
	    //System.err.println("MethodCall.Invoke(): exception encountered: " + retval);
	    retval=inv_ex.getTargetException();
	}
	catch(NoSuchMethodException no) {
	    System.out.print("MethodCall.Invoke(): found no method called " + method_name + 
			     " in class " + cl.getName() + " with [");
	    for(int i=0; i < args.size(); i++) {
		if(i > 0)
		    System.out.print(", ");
		System.out.print(args.elementAt(i).getClass());
	    }
	    System.out.println("] formal parameters");	    
	    return null;
	}
	catch(Exception e) {
	    System.err.println(e);
	}
	return retval;
    }



    public String toString() {
	StringBuffer ret=new StringBuffer();
	ret.append("MethodCall (name=" + method_name);
	if(funclet_name != null)
	    ret.append(", funclet_name=" + funclet_name);
	ret.append(", number of args=" + args.size() + ")");
	ret.append("\nArgs:");
	for(int i=0; i < args.size(); i++) {
	    ret.append("\n[" + args.elementAt(i) + " (" + 
		       args.elementAt(i).getClass().getName() + ")]");
	}
	return ret.toString();
    }


    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
	out.writeObject(method_name);
	out.writeObject(funclet_name);
	out.writeObject(args);
    }
    
    private void readObject(java.io.ObjectInputStream in) throws IOException, 
    ClassNotFoundException {
	method_name=(String)in.readObject();
	funclet_name=(String)in.readObject();
	args=(Vector)in.readObject();
    }
 


}



