/* 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.http;

import java.util.Properties;
import java.util.List;
import java.util.Map;
import java.util.Iterator;
import java.io.PrintWriter;
import java.io.CharArrayWriter;

import org.jfox.mx.MxServer;
import org.jfox.mx.ObjectName;
import org.jfox.mx.MxOperationInfo;
import org.jfox.mx.MxInfo;
import org.jfox.mx.MxParameterInfo;
import org.jfox.mx.util.PrimitiveHelper;

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

public class InvokeMXCommand implements Command {

  public String doGet(MxServer mx, Properties queryMap) throws Exception {
    String operationName = queryMap.getProperty("operName");
    String objectName = queryMap.getProperty("objectname");
    String operReturnType = queryMap.getProperty("operReturnType");
    String operParamString = queryMap.getProperty("operParamString");
    ObjectName on = new ObjectName(objectName);

    MxInfo mxInfo = mx.getMxInfo(on);
    MxOperationInfo mxOperInfo = getOperationInfo(mxInfo,operationName,operReturnType,operParamString);
    String[] signatures = getSignature(mxOperInfo);

    String[] _values = new String[signatures.length];
    for(int i=0; i<signatures.length; i++){
      String _value = queryMap.getProperty(mxOperInfo.getName() + "_" + i);
      if(_value == null) _value="";
      _values[i] = _value;
    }

    Object result = null;
    try {
      Object[] values = createObjects(_values,signatures);
      result = mx.invoke(on,operationName,values,signatures);
    }
    catch(Exception e){
      e.printStackTrace();
      result = e;
    }

    StringBuffer sb = new StringBuffer();
    sb.append(PageUtil.head("result view",mx.getDomains()));
    sb.append(PageUtil.banner("Result View"));
    sb.append(mxOperInfoTable(mxOperInfo,result));
    sb.append(linkTable(on));
    sb.append(PageUtil.foot());
    return sb.toString();

  }

  private static String mxOperInfoTable(MxOperationInfo mxOperInfo,Object result) {
    MxParameterInfo[] paramInfo = mxOperInfo.getSignature();
    String paramString = "";
    for(int j=0; j<paramInfo.length; j++){
      paramString += paramInfo[j].getType();
      if(j<paramInfo.length-1) {
        paramString += ",";
      }
    }

    StringBuffer sb = new StringBuffer();
    sb.append("<table width=\"780\" align=\"center\">\n" +
            "  <tr>\n" +
            "    <td width=\"180\"><b>Operation Name: </b></td><td>")
            .append(mxOperInfo.getName())
            .append("</td>\n" +
            "  </tr>\n" +

            "  <tr>\n" +
            "    <td width=\"180\"><b>Operation Description: </b></td><td>")
            .append(mxOperInfo.getDescription())
            .append("</td>\n" +
            "  </tr>\n" +
            "  <tr>\n" +
            "    <td width=\"180\"><b>Operation ReturnType: </b></td><td>")
            .append(mxOperInfo.getReturnType())
            .append("</td>\n" +
            "  <tr>\n" +
            "    <td width=\"180\"><b>Operation Signature: </b></td><td>")
            .append(paramString)
            .append("</td>\n" +
            "  </tr>\n" +
            "  <tr>\n" +
            "    <td width=\"180\" valign=\"top\"><b>Operation Result: </b></td><td>")
            .append(dump(result))
            .append("</td>\n" +
            "  </tr>\n" +

            "  </tr>\n" +
            "\n" +
            "</table><br>\n" +
            "");
    return sb.toString();

  }

  private MxOperationInfo getOperationInfo(MxInfo info,String operation,String returnType,String operParamString){
    MxOperationInfo[] operInfos = info.getOperations();
    for(int i=0; i<operInfos.length; i++){
      if(operInfos[i].getName().equals(operation) && operInfos[i].getReturnType().equals(returnType)) {
        MxParameterInfo[] paramInfo = operInfos[i].getSignature();
        String paramString = "";
        for(int j=0; j<paramInfo.length; j++){
          paramString += paramInfo[j].getType();
          if(j<paramInfo.length-1) {
            paramString += ",";
          }
        }
        if(paramString.equals(operParamString)) {
          return operInfos[i];
        }
      }
    }
    return null;
  }

  private String[] getSignature(MxOperationInfo operationInfo){
    MxParameterInfo[] paramInfos = operationInfo.getSignature();
    String[] sigatures = new String[paramInfos.length];
    for(int i=0;i<sigatures.length;i++){
      sigatures[i] = paramInfos[i].getType();
    }
    return sigatures;
  }

  private Object[] createObjects(String[] values, String[] signatures){
    Object[] objects = new Object[values.length];
    for(int i=0; i<objects.length; i++){
      Object obj = PrimitiveHelper.createObject(values[i],signatures[i]);
      if(obj == null) obj = values[i];
      objects[i] = obj;
    }
    return objects;
  }

  private static String dump(Object obj){
    String result = "null";
    if(obj == null) return result;
    if(obj instanceof Exception) {
      result = dumpException((Exception)obj);
    }
    else if(obj.getClass().isArray()) {
      Object[] array = (Object[])obj;
      result = dumpArray(array);
    }
    else if(obj instanceof List){
      result = dump(((List)obj).toArray());
    }
    else if(obj instanceof Map){
      result = dumpMap((Map)obj);
    }
    else {
      result = obj.toString();
    }
    return result;
  }

  private static String dumpException(Exception e) {
    CharArrayWriter caw = new CharArrayWriter();
    e.printStackTrace(new PrintWriter(caw));
    char[] charArray = caw.toCharArray();
    StringBuffer sb = new StringBuffer();
    for(int i=0; i<charArray.length; i++){
      if(charArray[i] == '\n') {
        sb.append("<br>");
      }
      else if(charArray[i] == ' '){
        sb.append("&nbsp;");
      }
      else if(charArray[i] == '\t'){
        sb.append("&nbsp;&nbsp;&nbsp;&nbsp;");
      }
      else {
        sb.append(charArray[i]);
      }
    }
    return sb.toString();
  }

  private static String dumpArray(Object[] array){
    StringBuffer sb = new StringBuffer();
    for(int i=0; i<array.length; i++){
      sb.append(array[i].toString()).append("<br>\n");
    }
    return sb.toString();
  }

  private static String dumpMap(Map map){
    StringBuffer sb = new StringBuffer();
    for(Iterator it=map.entrySet().iterator(); it.hasNext();){
      Map.Entry entry = (Map.Entry)it.next();
      sb.append(entry.getKey().toString())
              .append(" => ")
              .append(entry.getValue().toString())
              .append("<br>\n");
    }
    return sb.toString();
  }

  private static String linkTable(ObjectName objectName){
    StringBuffer sb = new StringBuffer();
    sb.append("<table width=\"780\" align=\"center\">\n" +
            "  <tr>\n" +
            "    <td>")
            .append("<a href=\"?action=ViewMX&objectname=")
            .append(objectName).append("\"> &lt;&lt;Return To MX View</a>")
            .append("</td>\n" +
            "  </tr>\n" +
            "</table>\n");
    return sb.toString();
  }

  public static void main(String[] args) {

  }
}