/*
 * 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.lang.ref.*;
import java.util.*;
import com.silverwrist.dynamo.iface.*;

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

  private static final int DISP_LISTMETHODS = 0;
  private static final int DISP_METHODSIGNATURE = 1;
  private static final int DISP_METHODHELP = 2;

  private static final Map DISPATCH_MAP;
  private static final List[] SIGNATURES;
  private static final String[] HELP_RESOURCES = {
    "help.listMeth", "help.methSig", "help.methHelp"
  };

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

  private XmlRpcSubSystem m_subsys;
  private SoftReference m_methodlist = null;

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

  IntrospectionDispatcher(XmlRpcSubSystem subsys)
  {
    m_subsys = subsys;

  } // end constructor

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

  private static final void test0Param(Request r) throws XmlRpcParameterError
  {
    if (r.getParameters().size()!=0)
      throw new XmlRpcParameterError(r.getQueryString() + ": parameter count mismatch");

  } // end test0Param

  private static final String test1Param(Request r) throws XmlRpcParameterError
  {
    if (r.getParameters().size()!=1)
      throw new XmlRpcParameterError(r.getQueryString() + ": parameter count mismatch");
    Object rc = r.getParameters().get("0");
    if (rc instanceof String)
      return rc.toString();
    throw new XmlRpcParameterError(r.getQueryString() + ": parameter type mismatch");

  } // end test1Param

  private final List listMethods(Request r)
  {
    List rc = null;
    if (m_methodlist!=null)
      rc = (List)(m_methodlist.get());
    if (rc==null)
    { // recompute the list of methods
      Set disps = m_subsys.getAllDispatchers();
      ArrayList output = new ArrayList();
      Iterator it = disps.iterator();
      while (it.hasNext())
      { // get each dispatcher's available methods and add them to the list
	XmlRpcDispatcher xd = (XmlRpcDispatcher)(it.next());
	output.addAll(xd.getSupportedMethods(r));

      } // end while

      // sort the output, keep a reference to it
      Collections.sort(output);
      rc = Collections.unmodifiableList(output);
      m_methodlist = new SoftReference(rc);

    } // end if

    return rc;

  } // end listMethods

  private final Object methodSignature(Request r, String method) throws FaultCode
  {
    // Get the dispatcher for this method.
    XmlRpcDispatcher xd = m_subsys.getDispatcher(method);
    if (xd==null)
      throw new XmlRpcMethodNotFound(method);

    // Ask it what the signatures are.
    List l = xd.getMethodSignature(r,method);
    if ((l==null) || l.isEmpty())
      return Boolean.FALSE;
    else
      return l;

  } // end methodSignature

  private final String methodHelp(Request r, String method) throws FaultCode
  {
    // Get the dispatcher for this method.
    XmlRpcDispatcher xd = m_subsys.getDispatcher(method);
    if (xd==null)
      throw new XmlRpcMethodNotFound(method);

    // Return the doc string.
    return xd.getMethodHelp(r,method);

  } // end methodHelp

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

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

  } // end getSessionIDParamValue

  public Object dispatchXmlRpcCall(Request r, Application app) throws Exception, FaultCode
  {
    Integer index = (Integer)(DISPATCH_MAP.get(r.getQueryString()));
    if (index==null)
      throw new XmlRpcMethodNotFound(r.getQueryString());

    switch (index.intValue())
    {
      case DISP_LISTMETHODS:
	test0Param(r);
	return listMethods(r);

      case DISP_METHODSIGNATURE:
	return methodSignature(r,test1Param(r));

      case DISP_METHODHELP:
	return methodHelp(r,test1Param(r));

      default:
	throw new XmlRpcMethodNotFound(r.getQueryString());

    } // end switch

  } // end dispatchXmlRpcCall

  public Collection getSupportedMethods(Request r)
  {
    return DISPATCH_MAP.keySet();

  } // end getSupportedMethods

  public List getMethodSignature(Request r, String method) throws FaultCode
  {
    Integer index = (Integer)(DISPATCH_MAP.get(r.getQueryString()));
    if (index==null)
      throw new XmlRpcMethodNotFound(r.getQueryString());
    return SIGNATURES[index.intValue()];

  } // end getMethodSignature

  public String getMethodHelp(Request r, String method) throws FaultCode
  {
    Integer index = (Integer)(DISPATCH_MAP.get(r.getQueryString()));
    if (index==null)
      throw new XmlRpcMethodNotFound(r.getQueryString());
    ResourceBundle b = ResourceBundle.getBundle("com.silverwrist.dynamo.xmlrpc.XmlRpcMessages",
						Locale.getDefault());
    return b.getString(HELP_RESOURCES[index.intValue()]);

  } // end getMethodHelp

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

  static
  { // Initialize the dispatch map.
    HashMap map = new HashMap();
    map.put("system.listMethods",new Integer(DISP_LISTMETHODS));
    map.put("system.methodSignature",new Integer(DISP_METHODSIGNATURE));
    map.put("system.methodHelp",new Integer(DISP_METHODHELP));
    DISPATCH_MAP = Collections.unmodifiableMap(map);

    // Initialize the signatures list.
    List[] arr = new List[3];
    ArrayList tmp = new ArrayList(1);
    tmp.add(TYPE_ARRAY);
    List l = Collections.unmodifiableList(tmp);
    arr[DISP_LISTMETHODS] = Collections.singletonList(l);
    tmp = new ArrayList(2);
    tmp.add(TYPE_ARRAY);
    tmp.add(TYPE_STRING);
    l = Collections.unmodifiableList(tmp);
    arr[DISP_METHODSIGNATURE] = Collections.singletonList(l);
    tmp = new ArrayList(2);
    tmp.add(TYPE_STRING);
    tmp.add(TYPE_STRING);
    l = Collections.unmodifiableList(tmp);
    arr[DISP_METHODHELP] = Collections.singletonList(l);
    SIGNATURES = arr;

  } // end static initializer

} // end class IntrospectionDispatcher
