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

import java.util.*;
import com.silverwrist.dynamo.iface.*;

class MultiCallDispatcher implements XmlRpcDispatcher, XmlRpcTypeNames
{
  /*--------------------------------------------------------------------------------
   * Static data members
   *--------------------------------------------------------------------------------
   */

  private static final List SUPPORTED_METHODS;
  private static final List SIGNATURES;

  /*--------------------------------------------------------------------------------
   * Attributes
   *--------------------------------------------------------------------------------
   */

  private XmlRpcSubSystem m_subsystem;

  /*--------------------------------------------------------------------------------
   * Constructor
   *--------------------------------------------------------------------------------
   */

  MultiCallDispatcher(XmlRpcSubSystem subsystem)
  {
    m_subsystem = subsystem;

  } // end constructor

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

  private static final Map translateFaultCode(FaultCode fc)
  {
    HashMap rc = new HashMap();
    rc.put("faultCode",new Integer(fc.getCode()));
    rc.put("faultString",fc.getMessage());
    return Collections.unmodifiableMap(rc);

  } // end translateFaultCode

  private final Object callViaStructure(Request r, Application app, Object struc) throws FaultCode
  {
    // Validate that this is a structure of the right type, and get the method name and the
    // parameters.
    if (!(struc instanceof Map))
      throw new XmlRpcParameterError("system.multicall: expected struct");
    Map my_map = (Map)struc;
    Object foo = my_map.get("methodName");
    if (foo==null)
      throw new XmlRpcParameterError("system.multicall: missing methodName");
    if (!(foo instanceof String))
      throw new XmlRpcParameterError("system.multicall: methodName not string");
    String method_name = (String)foo;
    foo = my_map.get("params");
    if (foo==null)
      throw new XmlRpcParameterError("system.multicall: missing params");
    if (!(foo instanceof List))
      throw new XmlRpcParameterError("system.multicall: params not array");
    List params = (List)foo;

    // Build our "nested" request and dispatch it.
    MultiCallRequest new_r = new MultiCallRequest(r,method_name,params);
    try
    { // run this through the dispatcher!
      return m_subsystem.dispatch(new_r,app);

    } // end try
    catch (Exception e)
    { // translate exception to FaultCode before we return
      return m_subsystem.translateException(new_r,e);

    } // end catch

  } // end callViaStructure

  /*--------------------------------------------------------------------------------
   * Implementations from interface XmlRpcDispatcher
   *--------------------------------------------------------------------------------
   */

  public String getSessionIDParamValue(Request r, Application app)
  {
    return null;  // dummy value

  } // end getSessionIDParamValue

  public Object dispatchXmlRpcCall(Request r, Application app) throws FaultCode
  {
    Map pm = r.getParameters();
    if (pm.size()!=1)
      throw new XmlRpcParameterError("system.multicall: wrong parameter count");
    Object parm = pm.get("0");
    if (!(parm instanceof List))
      throw new XmlRpcParameterError("system.multicall: parameter not array");

    List call_strucs = (List)parm;
    List return_strucs = new ArrayList(call_strucs.size());
    Iterator it = call_strucs.iterator();
    while (it.hasNext())
    { // get each call structure in turn and make sure it's OK
      Object call = it.next();
      Object rc = null;
      try
      { // execute this call!
	rc = callViaStructure(r,app,call);
	if (rc instanceof FaultCode)
	  rc = translateFaultCode((FaultCode)rc);
	else  // encapsulate in a 1-element array
	  rc = Collections.singletonList(rc);

      } // end try
      catch (FaultCode fc)
      { // translate a fault code if it gets thrown
	rc = translateFaultCode(fc);

      } // end catch

      return_strucs.add(rc);  // add return value to list

    } // end while

    return new XmlRpcResult(return_strucs);  // return list of return structures

  } // end dispatchXmlRpcCall

  public Collection getSupportedMethods(Request r)
  {
    return SUPPORTED_METHODS;

  } // end getSupportedMethods

  public List getMethodSignature(Request r, String method)
  {
    return SIGNATURES;

  } // end getMethodSignatures

  public String getMethodHelp(Request r, String method)
  {
    ResourceBundle b = ResourceBundle.getBundle("com.silverwrist.dynamo.xmlrpc.XmlRpcMessages",
						Locale.getDefault());
    return b.getString("help.multicall");

  } // end getMethodHelp

  /*--------------------------------------------------------------------------------
   * Static initializer
   *--------------------------------------------------------------------------------
   */

  static
  { // Initialize the supported methods list.
    SUPPORTED_METHODS = Collections.singletonList("system.multicall");

    // Initialize the signatures list.
    ArrayList tmp = new ArrayList(2);
    tmp.add(TYPE_ARRAY);
    tmp.add(TYPE_ARRAY);
    List l = Collections.unmodifiableList(tmp);
    tmp = new ArrayList(1);
    tmp.add(l);
    SIGNATURES = Collections.unmodifiableList(tmp);

  } // end static initializer

} // end class MultiCallDispatcher
