import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import util.annotation.ConsoleParam;

public class ConsoleServer {
  
  private Object service;
  private Class klass;
  private Method[] methods;
  private Map<String, Method> serviceMethods;
  
  public ConsoleServer() { }
  
  public void load(Object o) {
    
    this.service = o;
    klass = o.getClass();
    
    Annotation a = 
      klass.getAnnotation(util.annotation.ConsoleService.class);
    if (a == null) {
      System.out.println("Cannot find service");
      return;
    }

    methods = klass.getMethods();
    serviceMethods = new TreeMap<String, Method>();
    
    for (Method m : methods) {
      if (m.getAnnotation(util.annotation.ConsoleMethod.class) != null) {
        serviceMethods.put(m.getName(), m);
      }
    }
    
  }
 
  public List<String> listMethods() {   
    ArrayList<String> methodNames = new ArrayList<String>();
    for (String m : serviceMethods.keySet()) methodNames.add(m);
    return methodNames;
  }
  
  public Object run(String method) {
    try {
      return serviceMethods.get(method).invoke(service);
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }
  
  public Object run(String method, String param) {
    try {
      return serviceMethods.get(method).invoke(service, param);
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }


  public String getParamForMethod(String methodToRun) {
    Method serviceMethod = serviceMethods.get(methodToRun);
    Class[] types = serviceMethod.getParameterTypes();
    if (types == null || types.length == 0) return null;
    if (types.length == 1 && (types[0].equals(String.class))) {
      Annotation[][] params = serviceMethod.getParameterAnnotations();
      if (params[0][0] instanceof util.annotation.ConsoleParam) {
        return ((ConsoleParam) params[0][0]).name();
      }
      return "arg0";
    }
    return null;
  }
}