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

import java.util.*;
import org.apache.commons.lang.enum.*;
import javax.servlet.http.HttpServletResponse;

/**
 * A type-safe enumerated type that encapsulates the HTTP status codes.  We use an enumerated type here
 * so that it can be extended to support additional status codes (the ones defined, say, by WebDAV)
 * without affecting <CODE>HttpServletResponse</CODE>.
 * <p>The descriptions of the status codes are taken from the HTTP 1.1 Specification,
 * <a href="ftp://ftp.rfc-editor.org/in-notes/rfc2616.txt">RFC 2616</a>.
 *
 * @author Eric J. Bowersox &lt;erbo@silcom.com&gt;
 * @version X
 */
public class HttpStatusCode extends ValuedEnum
{
  /*--------------------------------------------------------------------------------
   * The actual enumeration values
   *--------------------------------------------------------------------------------
   */

  // N.B.: We copy the status codes here to allow extending them independent of the codes
  // listed in HttpServletResponse, but we point to the originals in HttpServletResponse
  // to maintain compatibility.

  /**
   * <b>100 Continue</b>. The client SHOULD continue with its request. This interim response is used to
   * inform the client that the initial part of the request has been received and has not yet been rejected
   * by the server. The client SHOULD continue by sending the remainder of the request or, if the request
   * has already been completed, ignore this response. The server MUST send a final response after the
   * request has been completed.
   */
  public static final HttpStatusCode I_CONTINUE =
      new HttpStatusCode("I_CONTINUE",HttpServletResponse.SC_CONTINUE);

  /**
   * <b>101 Switching Protocols</b>. The server understands and is willing to comply with the client's request,
   * via the Upgrade message header field, for a change in the application protocol being used on this connection.
   * The server will switch protocols to those defined by the response's Upgrade header field immediately after
   * the empty line which terminates the 101 response.
   */
  public static final HttpStatusCode I_SWITCH =
      new HttpStatusCode("I_SWITCH",HttpServletResponse.SC_SWITCHING_PROTOCOLS);

  /**
   * <b>200 OK</b>. The request has succeeded. The information returned with the response is dependent on
   * the method used in the request.  (Default status code)
   */
  public static final HttpStatusCode S_OK =
      new HttpStatusCode("S_OK",HttpServletResponse.SC_OK);

  /**
   * <b>201 Created</b>. The request has been fulfilled and resulted in a new resource being created. The
   * newly created resource can be referenced by the URI(s) returned in the entity of the response, with
   * the most specific URI for the resource given by a Location header field. The response SHOULD include
   * an entity containing a list of resource characteristics and location(s) from which the user or user
   * agent can choose the one most appropriate. The entity format is specified by the media type given in
   * the Content-Type header field. The origin server MUST create the resource before returning the 201
   * status code. If the action cannot be carried out immediately, the server SHOULD respond with 202
   * (Accepted) response instead.
   */
  public static final HttpStatusCode S_CREATED =
      new HttpStatusCode("S_CREATED",HttpServletResponse.SC_CREATED);

  /**
   * <b>202 Accepted</b>. The request has been accepted for processing, but the processing has not been
   * completed.  The request might or might not eventually be acted upon, as it might be disallowed when
   * processing actually takes place.
   */
  public static final HttpStatusCode S_ACCEPTED =
      new HttpStatusCode("S_ACCEPTED",HttpServletResponse.SC_ACCEPTED);

  /**
   * <b>203 Non-Authoritative Information</b>. The returned metainformation in the entity-header is not the
   * definitive set as available from the origin server, but is gathered from a local or a third-party copy.
   * The set presented MAY be a subset or superset of the original version. For example, including local
   * annotation information about the resource might result in a superset of the metainformation known by
   * the origin server. Use of this response code is not required and is only appropriate when the response
   * would otherwise be 200 (OK).
   */
  public static final HttpStatusCode S_NONAUTHORITATIVE =
      new HttpStatusCode("S_NONAUTHORITATIVE",HttpServletResponse.SC_NON_AUTHORITATIVE_INFORMATION);

  /**
   * <b>204 No Content</b>. The server has fulfilled the request but does not need to return an entity-body,
   * and might want to return updated metainformation. The response MAY include new or updated metainformation
   * in the form of entity-headers, which if present SHOULD be associated with the requested variant.  If the
   * client is a user agent, it SHOULD NOT change its document view from that which caused the request to be
   * sent. This response is primarily intended to allow input for actions to take place without causing a
   * change to the user agent's active document view, although any new or updated metainformation SHOULD be
   * applied to the document currently in the user agent's active view.
   */
  public static final HttpStatusCode S_NODATA =
      new HttpStatusCode("S_NODATA",HttpServletResponse.SC_NO_CONTENT);

  /**
   * <b>205 Reset Content</b>. The server has fulfilled the request and the user agent SHOULD reset the document
   * view which caused the request to be sent. This response is primarily intended to allow input for actions
   * to take place via user input, followed by a clearing of the form in which the input is given so that the
   * user can easily initiate another input action.
   */
  public static final HttpStatusCode S_RESET =
      new HttpStatusCode("S_RESET",HttpServletResponse.SC_RESET_CONTENT);

  /**
   * <b>206 Partial Content</b>. The server has fulfilled the partial GET request for the resource.  The
   * request MUST have included a Range header field indicating the desired range, and MAY have included
   * an If-Range header field to make the request conditional.
   */
  public static final HttpStatusCode S_PARTIAL =
      new HttpStatusCode("S_PARTIAL",HttpServletResponse.SC_PARTIAL_CONTENT);

  /**
   * <b>300 Multiple Choices</b>. The requested resource corresponds to any one of a set of representations,
   * each with its own specific location, and agent-driven negotiation information is being provided so that
   * the user (or user agent) can select a preferred representation and redirect its request to that location.
   */
  public static final HttpStatusCode S_CHOICE =
      new HttpStatusCode("S_CHOICE",HttpServletResponse.SC_MULTIPLE_CHOICES);

  /**
   * <b>301 Moved Permanently</b>. The requested resource has been assigned a new permanent URI and any future
   * references to this resource SHOULD use one of the returned URIs.  Clients with link editing capabilities
   * ought to automatically re-link references to the Request-URI to one or more of the new references returned
   * by the server, where possible.
   */
  public static final HttpStatusCode S_MOVED =
      new HttpStatusCode("S_MOVED",HttpServletResponse.SC_MOVED_PERMANENTLY);

  /**
   * <b>302 Moved Temporarily</b> (Redirect). The requested resource resides temporarily under a different URI.
   * Since the redirection might be altered on occasion, the client SHOULD continue to use the Request-URI for
   * future requests.
   */
  public static final HttpStatusCode S_REDIRECT =
      new HttpStatusCode("S_REDIRECT",HttpServletResponse.SC_MOVED_TEMPORARILY);

  /**
   * <b>303 See Other</b>. The response to the request can be found under a different URI and SHOULD be
   * retrieved using a GET method on that resource. This method exists primarily to allow the output of a
   * POST-activated script to redirect the user agent to a selected resource. The new URI is not a
   * substitute reference for the originally requested resource.
   */
  public static final HttpStatusCode S_SEE_OTHER =
      new HttpStatusCode("S_SEE_OTHER",HttpServletResponse.SC_SEE_OTHER);

  /**
   * <b>304 Not Modified</b>. If the client has performed a conditional GET request and access is allowed,
   * but the document has not been modified, the server SHOULD respond with this status code.
   */
  public static final HttpStatusCode S_NOTMODIFIED =
      new HttpStatusCode("S_NOTMODIFIED",HttpServletResponse.SC_NOT_MODIFIED);

  /**
   * <b>305 Use Proxy</b>. The requested resource MUST be accessed through the proxy given by the Location
   * field. The Location field gives the URI of the proxy. The recipient is expected to repeat this single
   * request via the proxy.
   */
  public static final HttpStatusCode S_USE_PROXY =
      new HttpStatusCode("S_USEPROXY",HttpServletResponse.SC_USE_PROXY);

  /**
   * <b>307 Temporary Redirect</b>. The requested resource resides temporarily under a different URI.
   * Since the redirection MAY be altered on occasion, the client SHOULD continue to use the Request-URI
   * for future requests.
   */
  public static final HttpStatusCode S_REDIRECT_TEMP =
      new HttpStatusCode("S_REDIRECT_TEMP",HttpServletResponse.SC_TEMPORARY_REDIRECT);

  /**
   * <b>400 Bad Request</b>. The request could not be understood by the server due to malformed syntax. The
   * client SHOULD NOT repeat the request without modifications.
   */
  public static final HttpStatusCode E_BAD_REQUEST =
      new HttpStatusCode("E_BAD_REQUEST",HttpServletResponse.SC_BAD_REQUEST);

  /**
   * <b>401 Unauthorized</b>. The request requires user authentication. The response MUST include a
   * WWW-Authenticate header field containing a challenge applicable to the requested resource. The client
   * MAY repeat the request with a suitable Authorization header field. If the request already included
   * Authorization credentials, then the 401 response indicates that authorization has been refused for those
   * credentials. If the 401 response contains the same challenge as the prior response, and the user agent
   * has already attempted authentication at least once, then the user SHOULD be presented the entity that
   * was given in the response, since that entity might include relevant diagnostic information.
   */
  public static final HttpStatusCode E_AUTH =
      new HttpStatusCode("E_AUTH",HttpServletResponse.SC_UNAUTHORIZED);

  /**
   * <b>402 Payment Required</b>. This code is reserved for future use.
   */
  public static final HttpStatusCode E_PAYMENT =
      new HttpStatusCode("E_PAYMENT",HttpServletResponse.SC_PAYMENT_REQUIRED);

  /**
   * <b>403 Forbidden</b>. The server understood the request, but is refusing to fulfill it. Authorization
   * will not help and the request SHOULD NOT be repeated. If the request method was not HEAD and the server
   * wishes to make public why the request has not been fulfilled, it SHOULD describe the reason for the
   * refusal in the entity.  If the server does not wish to make this information available to the client,
   * the status code 404 (Not Found) can be used instead.
   */
  public static final HttpStatusCode E_FORBIDDEN =
      new HttpStatusCode("E_FORBIDDEN",HttpServletResponse.SC_FORBIDDEN);

  /**
   * <b>404 Not Found</b>. The server has not found anything matching the Request-URI. No indication is given
   * of whether the condition is temporary or permanent. The 410 (Gone) status code SHOULD be used if the
   * server knows, through some internally configurable mechanism, that an old resource is permanently
   * unavailable and has no forwarding address. This status code is commonly used when the server does not
   * wish to reveal exactly why the request has been refused, or when no other response is applicable.
   */
  public static final HttpStatusCode E_NOTFOUND =
      new HttpStatusCode("E_NOTFOUND",HttpServletResponse.SC_NOT_FOUND);

  /**
   * <b>405 Method Not Allowed</b>. The method specified in the Request-Line is not allowed for the resource
   * identified by the Request-URI. The response MUST include an Allow header containing a list of valid
   * methods for the requested resource.
   */
  public static final HttpStatusCode E_METHOD =
      new HttpStatusCode("E_METHOD",HttpServletResponse.SC_METHOD_NOT_ALLOWED);

  /**
   * <b>406 Not Acceptable</b>. The resource identified by the request is only capable of generating response
   * entities which have content characteristics not acceptable according to the accept headers sent in the request.
   */
  public static final HttpStatusCode E_NOTACCEPTABLE =
      new HttpStatusCode("E_NOTACCEPTABLE",HttpServletResponse.SC_NOT_ACCEPTABLE);

  /**
   * <b>407 Proxy Authentication Required</b>. This code is similar to 401 (Unauthorized), but indicates that
   * the client must first authenticate itself with the proxy. The proxy MUST return a Proxy-Authenticate
   * header field containing a challenge applicable to the proxy for the requested resource. The client MAY
   * repeat the request with a suitable Proxy-Authorization header field.
   */
  public static final HttpStatusCode E_PROXY_AUTH =
      new HttpStatusCode("E_PROXY_AUTH",HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED);

  /**
   * <b>408 Request Timeout</b>. The client did not produce a request within the time that the server was
   * prepared to wait. The client MAY repeat the request without modifications at any later time.
   */
  public static final HttpStatusCode E_TIMEOUT =
      new HttpStatusCode("E_TIMEOUT",HttpServletResponse.SC_REQUEST_TIMEOUT);

  /**
   * <b>409 Conflict</b>. The request could not be completed due to a conflict with the current state of the
   * resource. This code is only allowed in situations where it is expected that the user might be able to
   * resolve the conflict and resubmit the request. The response body SHOULD include enough information for
   * the user to recognize the source of the conflict. Ideally, the response entity would include enough
   * information for the user or user agent to fix the problem; however, that might not be possible and is
   * not required.
   */
  public static final HttpStatusCode E_CONFLICT =
      new HttpStatusCode("E_CONFLICT",HttpServletResponse.SC_CONFLICT);

  /**
   * <b>410 Gone</b>. The requested resource is no longer available at the server and no forwarding address
   * is known. This condition is expected to be considered permanent. Clients with link editing capabilities
   * SHOULD delete references to the Request-URI after user approval. If the server does not know, or has no
   * facility to determine, whether or not the condition is permanent, the status code 404 (Not Found) SHOULD
   * be used instead.
   */
  public static final HttpStatusCode E_GONE =
      new HttpStatusCode("E_GONE",HttpServletResponse.SC_GONE);

  /**
   * <b>411 Length Required</b>. The server refuses to accept the request without a defined Content-Length.
   * The client MAY repeat the request if it adds a valid Content-Length header field containing the length
   * of the message-body in the request message.
   */
  public static final HttpStatusCode E_NOLENGTH =
      new HttpStatusCode("E_NOLENGTH",HttpServletResponse.SC_LENGTH_REQUIRED);

  /**
   * <b>412 Precondition Failed</b>. The precondition given in one or more of the request-header fields
   * evaluated to false when it was tested on the server. This response code allows the client to place
   * preconditions on the current resource metainformation (header field data) and thus prevent the
   * requested method from being applied to a resource other than the one intended.
   */
  public static final HttpStatusCode E_PRECONDITION =
      new HttpStatusCode("E_PRECONDITION",HttpServletResponse.SC_PRECONDITION_FAILED);

  /**
   * <b>413 Request Entity Too Large</b>. The server is refusing to process a request because the request
   * entity is larger than the server is willing or able to process. The server MAY close the connection to
   * prevent the client from continuing the request. If the condition is temporary, the server SHOULD include
   * a Retry-After header field to indicate that it is temporary and after what time the client MAY try again.
   */
  public static final HttpStatusCode E_ENTITYTOOBIG =
      new HttpStatusCode("E_ENTITYTOOBIG",HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE);

  /**
   * <b>414 Request URI Too Long</b>. The server is refusing to service the request because the Request-URI is
   * longer than the server is willing to interpret. This rare condition is only likely to occur when a client
   * has improperly converted a POST request to a GET request with long query information, when the client has
   * descended into a URI "black hole" of redirection (e.g., a redirected URI prefix that points to a suffix of
   * itself), or when the server is under attack by a client attempting to exploit security holes present in
   * some servers using fixed-length buffers for reading or manipulating the Request-URI.
   */
  public static final HttpStatusCode E_URITOOLONG =
      new HttpStatusCode("E_URITOOLONG",HttpServletResponse.SC_REQUEST_URI_TOO_LONG);

  /**
   * <b>415 Media Type Not Supported</b>. The server is refusing to service the request because the entity of
   * the request is in a format not supported by the requested resource for the requested method.
   */
  public static final HttpStatusCode E_BAD_TYPE =
      new HttpStatusCode("E_BAD_TYPE",HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);

  /**
   * <b>416 Requested Range Not Satisfiable</b>. A server SHOULD return a response with this status code if
   * a request included a Range request-header field, and none of the range-specifier values in this field
   * overlap the current extent of the selected resource, and the request did not include an If-Range
   * request-header field. (For byte-ranges, this means that the first-byte-pos of all of the byte-range-spec
   * values were greater than the current length of the selected resource.) When this status code is returned
   * for a byte-range request, the response SHOULD include a Content-Range entity-header field specifying the
   * current length of the selected resource. This response MUST NOT use the multipart/byteranges content-type.
   */
  public static final HttpStatusCode E_BAD_RANGE =
      new HttpStatusCode("E_BAD_RANGE",HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);

  /**
   * <b>417 Expectation Failed</b>. The expectation given in an Expect request-header field could not be met by
   * this server, or, if the server is a proxy, the server has unambiguous evidence that the request could not
   * be met by the next-hop server.
   */
  public static final HttpStatusCode E_EXPECTATION =
      new HttpStatusCode("E_EXPECTATION",HttpServletResponse.SC_EXPECTATION_FAILED);

  /**
   * <b>500 Internal Server Error</b>. The server encountered an unexpected condition which prevented it
   * from fulfilling the request.
   */
  public static final HttpStatusCode E_INTERNAL =
      new HttpStatusCode("E_INTERNAL",HttpServletResponse.SC_INTERNAL_SERVER_ERROR);

  /**
   * <b>501 Not Implemented</b>. The server does not support the functionality required to fulfill the request.
   * This is the appropriate response when the server does not recognize the request method and is not capable
   * of supporting it for any resource.
   */
  public static final HttpStatusCode E_NOTIMPL =
      new HttpStatusCode("E_NOTIMPL",HttpServletResponse.SC_NOT_IMPLEMENTED);

  /**
   * <b>502 Bad Gateway</b>. The server, while acting as a gateway or proxy, received an invalid response from
   * the upstream server it accessed in attempting to fulfill the request.
   */
  public static final HttpStatusCode E_BAD_GATEWAY =
      new HttpStatusCode("E_BAD_GATEWAY",HttpServletResponse.SC_BAD_GATEWAY);

  /**
   * <b>503 Service Unavailable</b>. The server is currently unable to handle the request due to a temporary
   * overloading or maintenance of the server. The implication is that this is a temporary condition which will
   * be alleviated after some delay. If known, the length of the delay MAY be indicated in a Retry-After header.
   * If no Retry-After is given, the client SHOULD handle the response as it would for a 500 response.
   */
  public static final HttpStatusCode E_UNAVAILABLE =
      new HttpStatusCode("E_UNAVAILABLE",HttpServletResponse.SC_SERVICE_UNAVAILABLE);

  /**
   * <b>504 Gateway Timeout</b>. The server, while acting as a gateway or proxy, did not receive a timely
   * response from the upstream server specified by the URI (e.g. HTTP, FTP, LDAP) or some other auxiliary
   * server (e.g. DNS) it needed to access in attempting to complete the request.
   */
  public static final HttpStatusCode E_GATEWAY_TIMEOUT =
      new HttpStatusCode("E_GATEWAY_TIMEOUT",HttpServletResponse.SC_GATEWAY_TIMEOUT);

  /**
   * <b>505 HTTP Version Not Supported</b>. The server does not support, or refuses to support, the HTTP
   * protocol version that was used in the request message. The server is indicating that it is unable or
   * unwilling to complete the request using the same major version as the client, other than with this
   * error message. The response SHOULD contain an entity describing why that version is not supported and
   * what other protocols are supported by that server.
   */
  public static final HttpStatusCode E_BAD_VERSION =
      new HttpStatusCode("E_BAD_VERSION",HttpServletResponse.SC_HTTP_VERSION_NOT_SUPPORTED);

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

  /**
   * Internal constructor which creates a new element of this enumerated type.
   *
   * @param name The name of the <CODE>HttpStatusCode</CODE> to be created.
   * @param value The numeric value to assign to the <CODE>HttpStatusCode</CODE>.
   */
  private HttpStatusCode(String name, int value)
  {
    super(name,value);

  } // end constructor

  /*--------------------------------------------------------------------------------
   * Standard static method implementations
   *--------------------------------------------------------------------------------
   */

  /**
   * Gets a <CODE>HttpStatusCode</CODE> by name.
   *
   * @param name The name of the <CODE>HttpStatusCode</CODE> to get; may be <CODE>null</CODE>.
   * @return The <CODE>HttpStatusCode</CODE> object, or <CODE>null</CODE> if the <CODE>HttpStatusCode</CODE>
   *         does not exist.
   */
  public static HttpStatusCode getEnum(String name)
  {
    return (HttpStatusCode)getEnum(HttpStatusCode.class,name);

  } // end getEnum

  /**
   * Gets a <CODE>HttpStatusCode</CODE> by numeric value.
   *
   * @param code The numeric value of the <CODE>HttpStatusCode</CODE> to get.
   * @return The <CODE>HttpStatusCode</CODE> object, or <CODE>null</CODE> if the <CODE>HttpStatusCode</CODE>
   *         does not exist.
   */
  public static HttpStatusCode getEnum(int code)
  {
    return (HttpStatusCode)getEnum(HttpStatusCode.class,code);

  } // end getEnum

  /**
   * Gets the <CODE>Map</CODE> of <CODE>HttpStatusCode</CODE> objects by name.
   *
   * @return The <CODE>HttpStatusCode</CODE> object <CODE>Map</CODE>.
   */
  public static Map getEnumMap()
  {
    return getEnumMap(HttpStatusCode.class);

  } // end getEnumMap

  /**
   * Gets the <CODE>List</CODE> of <CODE>HttpStatusCode</CODE> objects, in the order in which the objects are listed
   * in the code above.
   *
   * @return The <CODE>HttpStatusCode</CODE> object <CODE>List</CODE>.
   */
  public static List getEnumList()
  {
    return getEnumList(HttpStatusCode.class);

  } // end getEnumList

  /**
   * Gets an iterator over all <CODE>HttpStatusCode</CODE> objects, in the order in which the objects are listed
   * in the code above.
   *
   * @return The <CODE>HttpStatusCode</CODE> object iterator.
   */
  public static Iterator iterator()
  {
    return iterator(HttpStatusCode.class);

  } // end iterator

} // end class HttpStatusCode
