/*
 * The contents of this file are subject to the Mozilla Public License Version 1.1
 * (the "License"); you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
 * 
 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
 * language governing rights and limitations under the License.
 * 
 * The Original Code is the Venice Web Communities System.
 * 
 * The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
 * for Silverwrist Design Studios.  Portions created by Eric J. Bowersox are
 * Copyright (C) 2002 Eric J. Bowersox/Silverwrist Design Studios.  All Rights Reserved.
 * 
 * Contributor(s): 
 */
package com.silverwrist.venice.ui.rpc;

import java.util.*;
import com.silverwrist.venice.ui.*;

public class XmlRpcMulticall implements XmlRpcDispatch
{
  /*--------------------------------------------------------------------------------
   * Constructor
   *--------------------------------------------------------------------------------
   */

  public XmlRpcMulticall()
  { // do nothing
  } // end constructor

  /*--------------------------------------------------------------------------------
   * Internal operations
   *--------------------------------------------------------------------------------
   */

  private static final XmlRpcRequest parseRequest(RequestInput req, Object obj) throws XmlRpcFault
  {
    try
    { // this object should be a struct with two elements, methodName (string) and params (array).
      // Parse those out.
      Map map = (Map)obj;
      String method_name = (String)(map.get("methodName"));
      List params = (List)(map.get("params"));
      if ((method_name==null) || (params==null))
	throw new XmlRpcFault(XmlRpcFault.INVALID_PARAMS,"missing multicall struct elements");
      return new XmlRpcRequest(req,method_name,params);

    } // end try
    catch (ClassCastException cce)
    { // parameter is not right
      throw new XmlRpcFault(XmlRpcFault.INVALID_PARAMS,"array parameter type mismatch");

    } // end catch

  } // end parseRequest

  private static final Map faultToStruct(XmlRpcFault f)
  {
    Map rc = new TreeMap();
    rc.put("faultCode",new Integer(f.getFaultCode()));
    rc.put("faultString",f.getMessage());
    return rc;

  } // end faultToStruct

  /*--------------------------------------------------------------------------------
   * Implementations from interface XmlRpcDispatch
   *--------------------------------------------------------------------------------
   */

  public Object dispatch(RequestInput req, XmlRpcRequest xreq, Map environment) throws Exception, XmlRpcFault
  {
    if (!(xreq.getMethod().equals("system.multicall")))
      throw new XmlRpcFault(XmlRpcFault.METHOD_NOT_FOUND,"invalid method name: " + xreq.getMethod());
    if (xreq.getParamCount()!=1)
      throw new XmlRpcFault(XmlRpcFault.INVALID_PARAMS,"parameter count mismatch");

    List raw_calls;
    try
    { // array output
      raw_calls = (List)(xreq.getParam(0));

    } // end try
    catch (ClassCastException cce)
    { // type mismatch
      throw new XmlRpcFault(XmlRpcFault.INVALID_PARAMS,"parameter type mismatch");

    } // end catch

    if (raw_calls.isEmpty())
      return Collections.EMPTY_LIST;  // no calls here - this is good as a presence check

    // parse out subrequests, call them, and return them
    ArrayList rc = new ArrayList(raw_calls.size());
    Iterator it = raw_calls.iterator();
    while (it.hasNext())
    { // parse out a request and dispatch it
      try
      { // parse the request, execute it, and add its result to the return array
	XmlRpcRequest sub_xreq = parseRequest(req,it.next());
	Object sub_rc = XmlRpcServlet.dispatchMethodCall(req,sub_xreq);
	if (sub_rc instanceof XmlRpcFault)
	  sub_rc = faultToStruct((XmlRpcFault)sub_rc);
	rc.add(sub_rc);

      } // end try
      catch (XmlRpcFault f)
      { // save the fault code for the operation
	rc.add(faultToStruct(f));

      } // end catch

    } // end while

    return rc;  // return all the results at once to be serialized

  } // end dispatch

} // end class XmlRpcMulticall

