/* JFox, the OpenSource J2EE Application Server
 *
 * Copyright (C) 2002 huihoo.com
 * Distributable under GNU LGPL license
 * See the GNU Lesser General Public License for more details.
 */

package org.jfox.mx.loading;

import java.net.URL;
import java.net.MalformedURLException;
import java.io.File;
import java.io.InputStream;
import java.util.List;
import java.util.ArrayList;
import java.util.Properties;

import org.jfox.mx.util.PrimitiveHelper;
import org.jfox.mx.Mxable;
import org.jfox.mx.MxRegistration;
import org.jfox.mx.MxServer;
import org.jfox.mx.ObjectName;

/**
 * 
 * @author <a href="mailto:young_yy@hotmail.com">Young Yang</a>
 */

public class MxLoading implements Mxable, MxRegistration {
  private static MxLoading me;

  private MxServer server = null;
  private MxClassLoader clzLoader = null;

  public MxLoading() {
    URL currentURL = null;
    try {
      currentURL = new File("./").toURL();
    }
    catch(MalformedURLException e){
      e.printStackTrace();
    }
    clzLoader = new MxClassLoader(new URL[]{currentURL});
    me = this;
  }

  public static synchronized MxLoading getInstance(){
    if(me == null) {
      me = new MxLoading();
    }
    return me;
  }

  public ClassLoader getClassLoader() {
    return clzLoader;
  }

  public void mx_addLibrary(String path) {
    try {
      clzLoader.addURL(new File(path).toURL());
    }
    catch(MalformedURLException e){
      e.printStackTrace();
    }
  }

  public void addLiberary(URL url){
    clzLoader.addURL(url);
  }

  public URL[] mx_getURLs(){
    return clzLoader.getURLs();
  }

  public List mx_loadMx(String url) throws Exception {
    return createMxes(MxParser.getMxElements(clzLoader.getResourceAsStream(url)));
//    return createMxes(MxParser.getMxElements(url));
  }

  public List loadMx(File file) throws Exception {
    return createMxes(MxParser.getMxElements(file));
  }

  public List loadMx(URL url) throws Exception {
    return createMxes(mx_loadMx(url.toString()));
  }

  public List loadMx(InputStream in) throws Exception {
    return createMxes(MxParser.getMxElements(in));
  }

  private List createMxes(List mxMetas) throws Exception {
    List mxes = new ArrayList(mxMetas.size());
    for(int i=0; i<mxMetas.size(); i++){
      MxMeta meta = (MxMeta)mxMetas.get(i);
      mxes.add(createMx(meta));
    }
    return mxes;
  }

  private Mxable createMx(MxMeta meta) throws Exception {
    MxMeta.Arg[] constArgs = meta.getConstructor().getArgs();
    ObjectName on = new ObjectName(meta.getObjectName());
    Mxable mx = null;
    if(constArgs == null || constArgs.length == 0){
      mx = server.createMX(meta.getClassName(),on);
    }
    else {
      Object[] params = new Object[constArgs.length];
      String[] signs = new String[constArgs.length];
      for(int i=0; i<constArgs.length; i++){
        signs[i] = constArgs[i].getType();
        params[i] = loadParam(constArgs[i].getType(),constArgs[i].getValue());
      }
      mx = server.createMX(meta.getClassName(),on,params,signs);
    }

    MxMeta.Method[] methods = meta.getMethods();
    for(int i=0; i<methods.length; i++){
      MxMeta.Arg[] methodArgs = methods[i].getArgs();
      Object[] params = new Object[methodArgs.length];
      String[] signs = new String[methodArgs.length];
      for(int j=0; j<methodArgs.length; j++){
        signs[j] = methodArgs[j].getType();
        params[j] = loadParam(methodArgs[j].getType(),methodArgs[j].getValue());
      }
      server.invoke(on,methods[i].getName(),params,signs);
    }
    return mx;
  }

  public Properties getOperationDescriptions() {
    Properties prop = new Properties();
    prop.setProperty("mx_addLibrary","add new directory for searching class");
    prop.setProperty("mx_getURLs","get the urls that in the ClassLoader's search path");
    prop.setProperty("mx_loadMx","load Mx components from the specified url");
    return prop;
  }

  public Object getSource() {
    return me;
  }

  public String getMxDescription() {
    return "mx loading utility";
  }

  public void preRegister(MxServer server, ObjectName name) throws Exception {
    this.server = server;
  }

  public void postRegister(Boolean registrationDone) {
  }

  public void preDeregister() throws Exception {
  }

  public void postDeregister() {
  }

  public static void main(String[] args) {

  }

  private Object loadParam(String type, String value) throws Exception{
    if(type.equals("java.lang.String")) {
      return value;
    }
    else {
      Object obj = PrimitiveHelper.createObject(value,type);
      if(obj == value) { // not primitive type
        obj = clzLoader.loadClass(type)
                .getConstructor(new Class[]{String.class})
                .newInstance(new Object[]{value});
      }
      return obj;
    }
  }

}