/*
 * 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-03 Eric J. Bowersox/Silverwrist Design Studios.  All Rights Reserved.
 * 
 * Contributor(s): 
 */
package com.silverwrist.dynamo.util;

import java.util.*;
import com.silverwrist.dynamo.RequestType;
import com.silverwrist.dynamo.Verb;
import com.silverwrist.dynamo.except.*;
import com.silverwrist.dynamo.iface.*;

/**
 * A class which "wraps around" a {@link com.silverwrist.dynamo.iface.Request Request} object, providing some
 * shortcuts for other code, especially scripting code, to use.
 *
 * @author Eric J. Bowersox &lt;erbo@silcom.com&gt;
 * @version X
 */
public class RequestHelper
{
  /*--------------------------------------------------------------------------------
   * Attributes
   *--------------------------------------------------------------------------------
   */

  private Request m_req;                    // wrapped request
  private Map m_parameters;                 // parameter map
  private Map m_dataitems;                  // data item map
  private Class m_param_class;              // class of parameter entries
  private SessionInfo m_session = null;     // session information from the request
  private boolean m_need_session = true;    // do we need to get the session information?

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

  /**
   * Constructs a new <CODE>RequestHelper</CODE> object.
   *
   * @param req The {@link com.silverwrist.dynamo.iface.Request Request} object to wrap around.
   */
  public RequestHelper(Request req)
  {
    m_req = req;
    m_parameters = req.getParameters();
    m_dataitems = req.getDataItems();
    m_param_class = req.getParametersEntryClass();

  } // end constructor

  /*--------------------------------------------------------------------------------
   * External operations
   *--------------------------------------------------------------------------------
   */

  /**
   * Tests to see if the request type of the wrapped request is a specified type.
   *
   * @param type The request type to test against.
   * @return <CODE>true</CODE> if the wrapped request's type is equal to <CODE>type</CODE>, <CODE>false</CODE> if not.
   */
  public boolean isRequestType(RequestType type)
  {
    return type.equals(m_req.getType());

  } // end isRequestType

  /**
   * Tests to see if the request type of the wrapped request is a specified type.
   *
   * @param type The request type to test against.
   * @return <CODE>true</CODE> if the wrapped request's type is equal to <CODE>type</CODE>, <CODE>false</CODE> if not.
   */
  public boolean isRequestType(String type)
  {
    return isRequestType(RequestType.getEnum(type.toUpperCase()));

  } // end isRequestType

  /**
   * Tests to see if the verb associated with the wrapped request is a specified value.
   *
   * @param verb The verb to test against.
   * @return <CODE>true</CODE> if the wrapped request's verb is equal to <CODE>verb</CODE>, <CODE>false</CODE> if not.
   */
  public boolean isVerb(Verb verb)
  {
    return verb.equals(m_req.getVerb());

  } // end isVerb

  /**
   * Tests to see if the verb associated with the wrapped request is a specified value.
   *
   * @param verb The verb to test against.
   * @return <CODE>true</CODE> if the wrapped request's verb is equal to <CODE>verb</CODE>, <CODE>false</CODE> if not.
   */
  public boolean isVerb(String verb)
  {
    return isVerb(Verb.getEnum(verb.toUpperCase()));

  } // end isVerb

  /**
   * Returns an iterator over all parameter names supplied to the request.
   *
   * @return An iterator over all the parameter names.
   */
  public Iterator getParameterNames()
  {
    TreeSet tmp = new TreeSet(m_parameters.keySet());
    tmp.addAll(m_dataitems.keySet());
    return Collections.unmodifiableSet(tmp).iterator();

  } // end getParameterNames

  /**
   * Returns an array of all values supplied for the given named parameter in the request.
   *
   * @param name The name of the parameter to retrieve.
   * @return An array of all parameter values for that name.  If the parameter does not exist in the request,
   *         the return value is <CODE>null</CODE>.
   */
  public Object[] getParameterValues(String name)
  {
    Object rc = m_parameters.get(name);
    if (rc!=null)
    { // retrieve parameter value...
      if (m_param_class.isArray())
	return (Object[])rc;
      Object[] real_rc = new Object[1];
      real_rc[0] = rc;
      return real_rc;

    } // end if

    return (Object[])(m_dataitems.get(name));

  } // end getParameterValues

  /**
   * Returns an array of all values supplied for the given named parameter in the request, as strings.
   *
   * @param name The name of the parameter to retrieve.
   * @return An array of all parameter values for that name.  If the parameter does not exist in the request,
   *         the return value is <CODE>null</CODE>.
   */
  public String[] getStringParameterValues(String name)
  {
    Object rc = m_parameters.get(name);
    if (rc!=null)
    { // get the parameter values
      if (m_param_class.isArray())
      { // this is an array - maybe String[]
	if (m_param_class.getComponentType()==String.class)
	  return (String[])rc;
	Object[] tmp = (Object[])rc;
	String[] real_rc = new String[tmp.length];
	for (int i=0; i<tmp.length; i++)
	  real_rc[i] = tmp[i].toString();
	return real_rc;

      } // end if

      String[] real_rc = new String[1];
      real_rc[0] = rc.toString();
      return real_rc;

    } // end if

    // look for data items, get file names
    DataItem[] dia = (DataItem[])(m_dataitems.get(name));
    if (dia==null)
      return null;
    String[] fnames = new String[dia.length];
    for (int i=0; i<dia.length; i++)
      fnames[i] = dia[i].getName();
    return fnames;

  } // end getStringParameterValues

  /**
   * Returns the value of a given parameter in the request.  If the parameter has multiple values, only the first
   * value is returned.
   *
   * @param name The name of the parameter to retrieve.
   * @return The value of the parameter in the request.  If the parameter does not exist in the request, the return
   *         value is <CODE>null</CODE>.
   */
  public Object getParameter(String name)
  {
    Object rc = m_parameters.get(name);
    if (rc!=null)
    { // retrieve parameter value...
      if (m_param_class.isArray())
      { // grab element 0 out of the array and return it
	Object[] arr = (Object[])rc;
	return arr[0];

      } // end if
      else
	return rc;

    } // end if

    // get data item and return it
    DataItem[] dia = (DataItem[])(m_dataitems.get(name));
    if (dia==null)
      return null;
    else
      return dia[0];

  } // end getParameter

  /**
   * Returns the value of a given parameter in the request, as a string.  If the parameter has multiple values,
   * only the first value is returned.
   *
   * @param name The name of the parameter to retrieve.
   * @return The value of the parameter in the request.  If the parameter does not exist in the request, the return
   *         value is <CODE>null</CODE>.
   */
  public String getParameterString(String name)
  {
    Object rc = m_parameters.get(name);
    if (rc!=null)
    { // retrieve parameter value...
      if (m_param_class.isArray())
      { // grab element 0 out of the array and return it
	Object[] arr = (Object[])rc;
	return arr[0].toString();

      } // end if
      else
	return rc.toString();

    } // end if

    // get data item and return filename
    DataItem[] dia = (DataItem[])(m_dataitems.get(name));
    if (dia==null)
      return null;
    else
      return dia[0].getName();

  } // end getParameterString

  /**
   * Returns the value of a given parameter in the request, converted to an integer.  If the parameter has multiple
   * values, only the first value is returned.
   *
   * @param name The name of the parameter to retrieve.
   * @param defval Default value for the parameter.
   * @return The value of the parameter in the request.  If the parameter does not exist in the request, or is not
   *         parseable as an integer, the return value is <CODE>defval</CODE>.
   */
  public int getParameterInt(String name, int defval)
  {
    String s = getParameterString(name);
    if (s==null)
      return defval;
    try
    { // parse the integer value
      return Integer.parseInt(s);

    } // end try
    catch (NumberFormatException nfe)
    { // return the default value
      return defval;

    } // end catch

  } // end getParameterInt

  /**
   * Returns all {@link com.silverwrist.dynamo.iface.DataItem DataItem}s associated with a given parameter name
   * in the request.  <CODE>DataItem</CODE>s are usually associated with "file parameters."
   *
   * @param name The name of the parameter to retrieve.
   * @return An array of all <CODE>DataItem</CODE> values for that name.  If the parameter does not exist in the
   *         request, the return value is <CODE>null</CODE>.
   */
  public DataItem[] getDataItems(String name)
  {
    return (DataItem[])(m_dataitems.get(name));

  } // end getDataItems

  /**
   * Returns the {@link com.silverwrist.dynamo.iface.DataItem DataItem} associated with a given parameter name
   * in the request.  If there is more than one <CODE>DataItem</CODE> associated with that parameter name, only
   * the first one is returned.  <CODE>DataItem</CODE>s are usually associated with "file parameters."
   *
   * @param name The name of the parameter to retrieve.
   * @return The <CODE>DataItem</CODE> value associated with that name.  If the parameter does not exist in the
   *         request, the return value is <CODE>null</CODE>.
   */
  public DataItem getDataItem(String name)
  {
    DataItem[] dia = (DataItem[])(m_dataitems.get(name));
    if (dia==null)
      return null;
    else
      return dia[0];

  } // end getDataItem

  /**
   * Returns whether or not a specific parameter is present in the request.
   *
   * @param name The name of the parameter to test.
   * @return <CODE>true</CODE> if the request contains a parameter by this name, <CODE>false</CODE> if not.
   */
  public boolean hasParameter(String name)
  {
    return (m_parameters.containsKey(name) || m_dataitems.containsKey(name));

  } // end hasParameter

  /**
   * Tests to see whether an "image button" was clicked as the result of an HTTP POST request.  This is associated
   * with an &lt;INPUT TYPE="image"&gt; HTML tag, and results in two parameters added to the request, representing
   * the X-Y coordinates within the image that the mouse was clicked on, the names of which are constructed by
   * appending ".x" and ".y" to the "name" attribute of the tag.
   *
   * @param name The button name to test.
   * @return <CODE>true</CODE> if the button by that name was clicked, <CODE>false</CODE> if not.
   */
  public boolean isImageButtonClicked(String name)
  {
    if (RequestType.HTTP.equals(m_req.getType()))
      return (m_parameters.containsKey(name + ".x") && m_parameters.containsKey(name + ".y"));
    else
      return false;

  } // end isImageButtonClicked

  /**
   * Locates the {@link com.silverwrist.dynamo.iface.SessionInfo SessionInfo} associated with the given request.
   * A <CODE>SessionInfo</CODE> is tied to a given request by means of HTTP cookies or a similar method.
   *
   * @return The <CODE>SessionInfo</CODE> associated with the request, or <CODE>null</CODE> if there is none.
   */
  public SessionInfo getSession()
  {
    if (m_need_session)
    { // need to get the session from the request!
      try
      { // query SessionInfoProvider and get the session
	SessionInfoProvider prov = (SessionInfoProvider)(m_req.queryService(SessionInfoProvider.class));
	m_session = prov.getSessionInfo();

      } // end try
      catch (NoSuchServiceException e)
      { // do nothing
      } // end if

      m_need_session = false;

    } // end if

    return m_session;

  } // end getSession

  /**
   * Tests to see if the request type of the wrapped request's associated session is a specified type.
   *
   * @param type The request type to test against.
   * @return <CODE>true</CODE> if the wrapped request's associated session's type is equal to <CODE>type</CODE>,
   *         <CODE>false</CODE> if not.
   */
  public boolean isSessionType(RequestType type)
  {
    SessionInfo s = getSession();
    if (s!=null)
      return type.equals(s.getSessionType());
    else
      return false;

  } // end isSessionType

  /**
   * Tests to see if the request type of the wrapped request's associated session is a specified type.
   *
   * @param type The request type to test against.
   * @return <CODE>true</CODE> if the wrapped request's associated session's type is equal to <CODE>type</CODE>,
   *         <CODE>false</CODE> if not.
   */
  public boolean isSessionType(String type)
  {
    return isSessionType(RequestType.getEnum(type.toUpperCase()));

  } // end isSessionType

  /**
   * Retrieves an object from the "global object provider" associated with the Dynamo application, as opposed
   * to retrieving it from the {@link com.silverwrist.dynamo.iface.Request Request} object's own
   * {@link com.silverwrist.dynamo.iface.ObjectStore ObjectStore}, which is a per-request "scratch pad."
   *
   * @param namespace The namespace to interpret the name relative to.
   * @param name The name of the object to be retrieved.
   * @return The object reference specified.
   */
  public Object getRequestObject(String namespace, String name)
  {
    ObjectProvider op = (ObjectProvider)(m_req.queryService(ObjectProvider.class));
    return op.getObject(namespace,name);

  } // end getRequestObject

  /**
   * Retrieves a "chain parameter" from the request.  "Chain parameters" are attached to the
   * <CODE>HttpServletRequest</CODE> itself, rather than to the {@link com.silverwrist.dynamo.iface.Request Request}
   * object's {@link com.silverwrist.dynamo.iface.ObjectStore ObjectStore} "scratch pad."
   *
   * @param name Name of the chain parameter to retrieve.
   * @return The value of the chain parameter, or <CODE>null</CODE> if that parameter does not exist.
   */
  public Object getChainParameter(String name)
  {
    ChainParameterInput cpi = (ChainParameterInput)(m_req.queryService(ChainParameterInput.class));
    return cpi.getChainParameter(name);

  } // end getChainParameter

} // end class RequestHelper
