package cutils.delegate;

import javax.swing.*;
import java.lang.reflect.*;
import java.util.Vector;

/**
 ReflectUtil class
 @author: D. Lyon
 This class is provided by instructor to get class information

 */

public class ReflectUtil {
  protected Class c;
  private Object o;

  public ReflectUtil(Object _o) {
    o = _o;
    c = o.getClass();
  }

  public Constructor[] getConstructors() {
    return
        c.getDeclaredConstructors();
  }

  public Field[] getFields() {
    return c.getDeclaredFields();
  }

  public Method[] getMethods() {
    return c.getDeclaredMethods();
  }

  public Method[] getAllMethods() {
    Vector v = new Vector();
    Method ma[] = c.getMethods();
    for (int i = 0; i < ma.length; i++) {
      if (ma[i].getDeclaringClass() != Object.class)
        v.addElement(ma[i]);
    }

    ma = new Method[v.size()];
    for (int i = 0; i < v.size(); i++)
      ma[i] = ((Method) v.elementAt(i));
    return ma;
  }

  /**
   getClasses is not implemented in the cutils.reflection API, yet.
   @author D. Lyon
   @version 0.1
   @date 3/6/01
   */
  public Class[] getClasses() {
    return c.getClasses();
  }

  public String[] getReadMethodNames() {
    Method m[] = getMethods();
    Vector v = new Vector();
    for (int i = 0; i < m.length; i++) {
      String s = getName(m[i]);
      if (s.startsWith("get") || s.startsWith("is")) {
        v.addElement(s);
        System.out.println(s);
      }
    }
    String getterArray[] = new String[v.size()];
    for (int i = 0; i < getterArray.length; i++)
      getterArray[i] = (String) v.elementAt(i);
    return getterArray;
  }

  public String[] getReadMethodNames(int n) {
    Method m[] = getMethodsWithNArgs(n);
    Vector v = new Vector();
    for (int i = 0; i < m.length; i++) {
      String s = getName(m[i]);
      if (s.startsWith("get") || s.startsWith("is"))
        v.addElement(s);
    }
    String getterArray[] = new String[v.size()];
    for (int i = 0; i < getterArray.length; i++)
      getterArray[i] = (String) v.elementAt(i);
    return getterArray;
  }

  public String[] getWriteMethodNames() {
    Method m[] = getMethods();
    Vector v = new Vector();
    for (int i = 0; i < m.length; i++) {
      String s = getName(m[i]);
      if (s.startsWith("set")) {
        v.addElement(s);
        System.out.println(s);
      }
    }
    String setterArray[] = new String[v.size()];
    for (int i = 0; i < setterArray.length; i++)
      setterArray[i] = (String) v.elementAt(i);
    return setterArray;
  }

  /**
   getMethod takes a string and returns a corresponding method.
   */
  public Method getMethod(String s) {
    Method m = null;
    try {
      m = c.getMethod(s, new Class[]{});
    } catch (NoSuchMethodException e) {
      System.out.println(e);
    }
    return m;
  }

  /**
   invoke a methodName string with no arguments.
   */
  public Object invoke(String methodName) {
    Method m = getMethod(methodName);
    Object ret = null;
    try {
      ret = m.invoke(o, null);
    } catch (InvocationTargetException e) {
      e.printStackTrace();
    } catch (IllegalAccessException e) {
      e.printStackTrace();
    }

    return ret;
  }

  public int getModifiers(Method m) {
    return m.getModifiers();
  }

  public String getModifierString(Method m) {
    return Modifier.toString(
        getModifiers(m));
  }

  /**
   Print an array of objects
   @author Douglas Lyon
   @version 1.0
   */
  public static void println(Object o[]) {
    for (int i = 0; i < o.length; i++)
      System.out.println(o[i]);
  }

  /**
   convert an array of string into a big string with new lines
   */
  public static String toString(Object o[]) {
    String s = "";
    for (int i = 0; i < o.length; i++)
      s = s + o[i] + "\n";
    return s;
  }

  public void printInfo() {
    System.out.println("Info on class " + getClassName());
    System.out.println("Constructors:");
    println(getConstructors());
    System.out.println("Fields:");
    println(getFields());
    System.out.println("Methods:");
    println(getMethods());
    System.out.println("Methods with 0 arguments");
    println(getMethodsWithNArgs(0));
    System.out.println("read methods");
    println(getReadMethodNames());
    System.out.println("write methods");
    println(getWriteMethodNames());
    System.out.println("Classes");
    println(getClasses());
  }

  public String getClassName() {
    return c.getName();
  }

  Method[] getMethodsWithNArgs(int n) {
    Method m[] = getMethods();
    Vector v = new Vector();
    for (int i = 0; i < m.length; i++) {
      Class ca[] = m[i].getParameterTypes();
      if (ca.length == n)
        v.addElement(m[i]);
    }
    Method ma[] = new Method[v.size()];
    for (int i = 0; i < v.size(); i++)
      ma[i] = (Method) v.elementAt(i);
    return ma;
  }

  public String getName(Method m) {
    return m.getName();
  }

  public String getInfoString(Method m) {
    return
        "for method " + m.getName() +
        "\nThe modifier = " +
        getModifierString(m) +
        "\nThe return type =" +
        m.getReturnType().getName() +
        "\n The arguments for this method are " +
        toString(m.getParameterTypes());
  }

  public void printInfo(Method m) {
    System.out.println(getInfoString(m));
  }

  public static void main(String args[]) {

    ReflectUtil ru = new ReflectUtil(new java.util.Date());
    ru.startCommandLineInterpreter();
    //ru.printInfo();
  }

  public void startCommandLineInterpreter() {
    String s = null;
    String prompt = "enter command:";
    while (!(s = getString(prompt)).startsWith("quit"))
      try {
        prompt = s + "=" + invoke(s);
      } catch (Exception e) {
        prompt = e.toString();
      }
    ;
  }

  public static String getString(String prompt) {
    return JOptionPane.showInputDialog(prompt);
  }
}