/* 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.util.List;
import java.util.ArrayList;
import java.io.InputStream;
import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

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

public class MxParser {
  private static DocumentBuilder db = null;
  static {
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    try {
      db = dbf.newDocumentBuilder();
    }
    catch(Exception e){
      throw new RuntimeException(e);
    }
  }

  public static List getMxElements(InputStream in) throws Exception {
    Document doc = db.parse(in);
    return buildMxMetas(doc);
  }

  public static List getMxElements(File file) throws Exception {
    Document doc = db.parse(file);
    return buildMxMetas(doc);
  }

  public static List getMxElements(String url) throws Exception {
    Document doc = db.parse(url);
    return buildMxMetas(doc);
  }

  private static List buildMxMetas(Document doc){
    NodeList nl = doc.getElementsByTagName("MX");
    List list = new ArrayList(nl.getLength());
    for(int i=0;i<nl.getLength();i++){
      Element elm = (Element)nl.item(i);
      MxMeta mxMeta = buildMxMeta(elm);
      list.add(mxMeta);
    }
    return list;
  }

  private static MxMeta buildMxMeta(Element elm){
    String className = elm.getAttribute("CLASSNAME");
    String objectName = elm.getAttribute("OBJECTNAME");

    NodeList construcNL = elm.getElementsByTagName("CONSTRUCTOR");
    MxMeta.Constructor constructor = getMxConstructorMeta(construcNL);

    NodeList methodNL = elm.getElementsByTagName("METHOD");
    MxMeta.Method[] methods = getMxMethodsMeta(methodNL);

    return new MxMeta(className,objectName,constructor,methods);
  }

  private static MxMeta.Constructor getMxConstructorMeta(NodeList nl){
    if(nl.getLength() ==0 ) {
      return new MxMeta.Constructor(null);
    }
    else {
      // 只要第一个 Constructor
      Element elm = (Element)nl.item(0);
      NodeList argNL = elm.getElementsByTagName("ARG");
      MxMeta.Arg[] args = getArgs(argNL);
      return new MxMeta.Constructor(args);
    }
  }

  private static MxMeta.Method[] getMxMethodsMeta(NodeList nl){
    int length = nl.getLength();
    MxMeta.Method[] methods = new MxMeta.Method[length];
    for(int i=0; i<length; i++){
      Element _method = (Element)nl.item(i);
      MxMeta.Method method = getMxMethodMeta(_method);
      methods[i] = method;
    }
    return methods;
  }

  private static MxMeta.Method getMxMethodMeta(Element elm){
    String name = elm.getAttribute("NAME");
    NodeList argNL = elm.getElementsByTagName("ARG");
    MxMeta.Arg[] args = getArgs(argNL);
    return new MxMeta.Method(name,args);

  }

  private static MxMeta.Arg[] getArgs(NodeList nl) {
    int length = nl.getLength();
    MxMeta.Arg[] args = new MxMeta.Arg[length];
    for(int i=0; i<length; i++){
      Element _arg = (Element)nl.item(i);
      String type = _arg.getAttribute("TYPE");
      String value = "";
      Node valueNode = _arg.getFirstChild();
      if(valueNode !=null){
        value = valueNode.getNodeValue().trim();
      }
      MxMeta.Arg arg = new MxMeta.Arg(type,value);
      args[i] = arg;
    }
    return args;
  }
}