/**
 * Class Reflector gets class members (methods,fields,etc) from a class instance
 * @author Roman Yedokov
 */

package rmi.rmiSynth.lex;

import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class Reflector {
  private Class c;
  private Object o;

  /**
   * Constructor
   */
  public Reflector(Object _o) {
    o = _o;
    c = o.getClass();
  }

  //********************* Class ***************
  /**
   * Gets class visibility
   * @param cls Class
   * @return v Visibility
   */
  public int getVisibility(Class cls) {
    int v = 0;                  //Default
    int m = cls.getModifiers();
    if (Modifier.isPublic(m)) {
      v = 1;
    }
    if (Modifier.isPrivate(m)) {
      v = 2;
    }
    if (Modifier.isProtected(m)) {
      v = 3;
    }
    return v;
  }

  /**
   * Gets class modifiers
   * @return lmd modifiers
   */
  public LexModif getModifiers() {
    LexModif lmd = new LexModif();
    lmd.setVisibility(getVisibility(c));
    return lmd;
  }

  /**
   * Gets class name
   * @return c.getName() Class name
   */
  public String getName() {
    return c.getName();
  }

  //**** Modifiers and name for fields and methods *********
  /**
   * Gets member visibility
   * @param mem Member
   * @return v Visibility
   */
  public int getVisibility(Member mem) {
    int v = 0;                  //Default
    int m = mem.getModifiers();
    if (Modifier.isPublic(m)) {
      v = 1;
    }
    if (Modifier.isPrivate(m)) {
      v = 2;
    }
    if (Modifier.isProtected(m)) {
      v = 3;
    }
    return v;
  }

  /**
   * Gets member modifiers
   * @param mem Member
   * @return lmd modifiers
   */
  public LexModif getModifiers(Member mem) {
    LexModif lmd = new LexModif();
    lmd.setVisibility(getVisibility(mem));
    return lmd;
  }

  /**
   * Gets member name
   * @return mem.getName() Member name
   */
  public String getName(Member mem) {
    return mem.getName();
  }

  //***************** Fields *******************
  /**
   * Gets field type
   * @param fld Field
   * @return ltp Field type
   */
  public LexType getType(Field fld) {
    Class cls = fld.getType();
    LexType ltp = new LexType();
    ltp.setName(removeGarbage(cls.getName()));
    ltp.setArray(cls.isArray());
    return ltp;
  }

  /**
   * Gets all fields
   * @return lfd Fields
   */
  public LexField[] getFields() {
    Field[] fld = c.getDeclaredFields();
    LexField[] lfd = new LexField[fld.length];
    String name;
    for (int i = 0; i < lfd.length; i++) {
      lfd[i] = new LexField();
      lfd[i].setModif(getModifiers(fld[i]));
      lfd[i].setType(getType(fld[i]));
      lfd[i].setName(getName(fld[i]));
    }
    return lfd;
  }

  //********************* Methods ********************
  /**
   * Gets method return type
   * @param mtd Method
   * @return ltp Method return type
   */
  public LexType getType(Method mtd) {
    Class cls = mtd.getReturnType();
    LexType ltp = new LexType();
    ltp.setName(removeGarbage(cls.getName()));
    ltp.setArray(cls.isArray());
    return ltp;
  }

  /**
   * Gets all methods
   * @return lmd Methods
   */
  public LexMethod[] getMethods() {
    Method[] mtd = c.getDeclaredMethods();
    LexMethod[] lmd = new LexMethod[mtd.length];
    for (int i = 0; i < lmd.length; i++) {
      lmd[i] = new LexMethod();
      lmd[i].setModif(getModifiers(mtd[i]));
      lmd[i].setType(getType(mtd[i]));
      lmd[i].setName(getName(mtd[i]));
      lmd[i].setParams(getParams(mtd[i]));
      lmd[i].getBody().setDelegObj("v");
      lmd[i].getBody().setName(lmd[i].getName());
      lmd[i].getBody().setRet(!lmd[i].getType().isVoid());
    }
    return lmd;
  }

  //****************** Parameters *****************
  /**
   * Gets parameter type
   * @param prm Parameter
   * @return ltp Parameter type
   */
  public LexType getType(Class prm) {
    LexType ltp = new LexType();
    ltp.setName(removeGarbage(prm.getName()));
    ltp.setArray(prm.isArray());
    return ltp;
  }

  /**
   * Gets all parameters
   * @param mtd Method
   * @return lpm Parameters
   */
  public LexParam[] getParams(Method mtd) {
    Class pmt[] = mtd.getParameterTypes();
    LexParam[] lpm = new LexParam[pmt.length];
    for (int i = 0; i < lpm.length; i++) {
      lpm[i] = new LexParam();
      lpm[i].setType(getType(pmt[i]));
      lpm[i].setName("p" + i);
    }
    return lpm;
  }

  /**
   * Removes garabage from name
   * @param _s String to process
   * @return s
   */
  public String removeGarbage(String _s) {
    String s = _s;
    if (s.charAt(0) == '[' && s.charAt(s.length() - 1) == ';') {
      s = s.substring(2, s.length() - 1) + "[]";
    }
    return s;
  }
}