/**
 * Copyright 2010 JBoss Inc
 *
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.eclipse.webdav.internal.kernel;

import java.util.Enumeration;
import java.util.Hashtable;
import org.eclipse.webdav.IContext;
import org.eclipse.webdav.internal.kernel.utils.EnumerationConverter;
import org.eclipse.webdav.internal.kernel.utils.MergedEnumeration;

/**
 * The <code>Context</code> class is essentially a collection of key-value
 * pairings, with defaults.  Implements the <code>Context</code> interface
 * which provides convenience methods for most HTTP and WebDAV message
 * header fields.
 *
 * To be done:
 *
 * 1) Types that take and return dates have not been changed.  We need to write
 * date formats to cope with the different strings that we may be sent, see
 *the HTTP spec for details.
 * 2) Identify the fields where multiple values are permissible, and change the
 *params to be arrays of values.
 *
 */
public class Context implements IContext {

	protected Hashtable properties = new Hashtable(5);
	protected IContext defaults = null;

	protected final class ContextKey {

		protected String key;

		public ContextKey(String key) {
			super();
			this.key = key;
		}

		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (!(obj instanceof ContextKey))
				return false;
			return ((ContextKey) obj).key.equalsIgnoreCase(key);
		}

		public int hashCode() {
			return key.toLowerCase().hashCode();
		}

		public String toString() {
			return key;
		}
	}

	public final class ContextKeyToStringEnum extends EnumerationConverter {
		ContextKeyToStringEnum(Enumeration sourceEnum) {
			super(sourceEnum);
		}

		public Object nextElement() {
			return ((ContextKey) sourceEnum.nextElement()).key;
		}
	}

	// Field names used in HTTP message headers.

	// from HTTP/1.1
	public final String ACCEPT = "Accept"; //$NON-NLS-1$
	public final String ACCEPT_CHARSET = "Accept-Charset"; //$NON-NLS-1$
	public final String ACCEPT_ENCODING = "Accept-Encoding"; //$NON-NLS-1$
	public final String ACCEPT_LANGUAGE = "Accept-Language"; //$NON-NLS-1$
	public final String ACCEPT_RANGES = "Accept-Ranges"; //$NON-NLS-1$
	public final String AGE = "Age"; //$NON-NLS-1$
	public final String ALLOW = "Allow"; //$NON-NLS-1$
	public final String AUTHORIZATION = "Authorization"; //$NON-NLS-1$
	public final String CACHE_CONTROL = "Cache-Control"; //$NON-NLS-1$
	public final String CONNECTION = "Connection"; //$NON-NLS-1$
	public final String CONTENT_BASE = "Content-Base"; //$NON-NLS-1$
	public final String CONTENT_ENCODING = "Content-Encoding"; //$NON-NLS-1$
	public final String CONTENT_LANGUAGE = "Content-Language"; //$NON-NLS-1$
	public final String CONTENT_LENGTH = "Content-Length"; //$NON-NLS-1$
	public final String CONTENT_LOCATION = "Content-Location"; //$NON-NLS-1$
	public final String CONTENT_MD5 = "Content-MD5"; //$NON-NLS-1$
	public final String CONTENT_RANGE = "Content-Range"; //$NON-NLS-1$
	public final String CONTENT_TYPE = "Content-Type"; //$NON-NLS-1$
	public final String DATE = "Date"; //$NON-NLS-1$
	public final String ETAG = "ETag"; //$NON-NLS-1$
	public final String EXPIRES = "Expires"; //$NON-NLS-1$
	public final String FROM = "From"; //$NON-NLS-1$
	public final String HOST = "Host"; //$NON-NLS-1$
	public final String IF_MODIFIED_SINCE = "If-Modified-Since"; //$NON-NLS-1$
	public final String IF_MATCH = "If-Match"; //$NON-NLS-1$
	public final String IF_NONE_MATCH = "If-None-Match"; //$NON-NLS-1$
	public final String IF_RANGE = "If-Range"; //$NON-NLS-1$
	public final String IF_UNMODIFIED_SINCE = "If-Unmodified-Since"; //$NON-NLS-1$
	public final String LAST_MODIFIED = "Last-Modified"; //$NON-NLS-1$
	public final String LOCATION = "Location"; //$NON-NLS-1$
	public final String MAX_FORWARDS = "Max-Forwards"; //$NON-NLS-1$
	public final String PRAGMA = "Pragma"; //$NON-NLS-1$
	public final String PROXY_AUTHENTICATE = "Proxy-Authenticate"; //$NON-NLS-1$
	public final String PROXY_AUTHORIZATION = "Proxy-Authorization"; //$NON-NLS-1$
	public final String PUBLIC = "Public"; //$NON-NLS-1$
	public final String RANGE = "Range"; //$NON-NLS-1$
	public final String REFERER = "Referer"; //$NON-NLS-1$
	public final String RETRY_AFTER = "Retry-After"; //$NON-NLS-1$
	public final String SERVER = "Server"; //$NON-NLS-1$
	public final String TRANSFER_ENCODING = "Transfer-Encoding"; //$NON-NLS-1$
	public final String UPGRADE = "Upgrade"; //$NON-NLS-1$
	public final String USER_AGENT = "User-Agent"; //$NON-NLS-1$
	public final String VARY = "Vary"; //$NON-NLS-1$
	public final String VIA = "Via"; //$NON-NLS-1$
	public final String WARNING = "Warning"; //$NON-NLS-1$
	public final String WWW_AUTHENTICATE = "WWW-Authenticate"; //$NON-NLS-1$

	// from WebDAV
	public final String DAV = "DAV"; //$NON-NLS-1$
	public final String DEPTH = "Depth"; //$NON-NLS-1$
	public final String DESTINATION = "Destination"; //$NON-NLS-1$
	public final String IF = "If"; //$NON-NLS-1$
	public final String LOCK_TOKEN = "Lock-Token"; //$NON-NLS-1$
	public final String OVERWRITE = "Overwrite"; //$NON-NLS-1$
	public final String STATUS_URI = "Status-URI"; //$NON-NLS-1$
	public final String TIMEOUT = "Timeout"; //$NON-NLS-1$

	// from Advanced Collections
	public final String ALL_BINDINGS = "All-Bindings"; //$NON-NLS-1$
	public final String REF_TARGET = "Ref-Target"; //$NON-NLS-1$
	public final String RES_TYPE = "Resource-Type"; //$NON-NLS-1$
	public final String PASSTHROUGH = "Passthrough"; //$NON-NLS-1$
	public final String ORDERED = "Ordered"; //$NON-NLS-1$
	public final String POSITION = "Position"; //$NON-NLS-1$

	// from Delta-V
	public final String LABEL = "Label"; //$NON-NLS-1$

	public Context() {
		super();
	}

	/**
	 * Constructor for the class. Set the property defaults to be
	 * the given value.
	 *
	 * @param defaults the default property values for the context
	 */
	public Context(IContext defaults) {
		super();
		this.defaults = defaults;
	}

	/**
	 * Copy all the default values into the receiver.
	 */
	public void collapse() {
		if (defaults != null) {
			Enumeration keysEnum = defaults.keys();
			while (keysEnum.hasMoreElements()) {
				String key = (String) keysEnum.nextElement();
				put(key, get(key));
			}
			defaults = null;
		}
	}

	/**
	 * Return the value for the given key.
	 *
	 * @param key the key to look up
	 * @return the value for the key or null if none.
	 */
	public String get(String key) {
		String value = (String) properties.get(new ContextKey(key));
		if (value == null && defaults != null)
			return defaults.get(key);
		return value;
	}

	/**
	 * Gets the media types that are acceptable for a response.
	 * Return the string value for the ACCEPT key.
	 *
	 * <p>Implements the corresponding API in the interface 
	 * <code>Context</code>.</p>
	 *
	 * @return the value for ACCEPT
	 * @see Context#getAccept()
	 */
	public String getAccept() {
		return get(ACCEPT);
	}

	/**
	 * Gets the character sets that are acceptable for a response.
	 * Return the string value for the ACCEPT_CHARSET key.
	 *
	 * <p>Implements the corresponding API in the interface 
	 * <code>Context</code>.</p>
	 *
	 * @return the value for ACCEPT_CHARSET
	 * @see Context#getAcceptCharset()
	 */
	public String getAcceptCharset() {
		return get(ACCEPT_CHARSET);
	}

	/**
	 * Get what content-encoding values are acceptable for a response.
	 * Return the string value for the ACCEPT_ENCODING key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for ACCEPT_ENCODING
	 * @see Context#getAcceptEncoding()
	 */
	public String getAcceptEncoding() {
		return get(ACCEPT_ENCODING);
	}

	/**
	 * Get the natural languages that are acceptable for a response.
	 * Return the string value for the ACCEPT_LANGUAGE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for ACCEPT_LANGUAGE
	 * @see Context#getAcceptLanguage()
	 */
	public String getAcceptLanguage() {
		return get(ACCEPT_LANGUAGE);
	}

	/**
	 * Get the range requests acceptable to a server.
	 * Return the string value for the ACCEPT_RANGES key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for ACCEPT_RANGES
	 * @see Context#getAcceptRanges()
	 */
	public String getAcceptRanges() {
		return get(ACCEPT_RANGES);
	}

	/**
	 * Get the sender's estimate of the time since the response was generated.
	 * Return the int value for the AGE key. Return -1 if the value is not set.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for AGE
	 * @see Context#getAge()
	 */
	public int getAge() {
		String ageString = get(AGE);
		return (ageString == null) ? -1 : Integer.parseInt(ageString);
	}

	/**
	 * Return the string value for the ALL_BINDINGS key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for ALL_BINDINGS
	 * @see Context#getAllBindings()
	 */
	public String getAllBindings() {
		return get(ALL_BINDINGS);
	}

	/**
	 * Gets the methods allowed on a resource
	 * Return the string value for the ALLOW key.
	 *
	 * <p>Implements the corresponding API in the interface 
	 * <code>Context</code>.</p>
	 *
	 * @return the value for ALLOW
	 * @see Context#getAllow()
	 */
	public String getAllow() {
		return get(ALLOW);
	}

	/**
	 * Get the user's credentials for the realm of the resource being requested.
	 * Return the string value for the AUTHORIZATION key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for AUTHORIZATION
	 * @see Context#getAuthorization()
	 */
	public String getAuthorization() {
		return get(AUTHORIZATION);
	}

	/**
	 * Get the cache control directives that must be obeyed.
	 * Return the string value for the CACHE_CONTROL key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for CACHE_CONTROL
	 * @see Context#getCacheControl()
	 */
	public String getCacheControl() {
		return get(CACHE_CONTROL);
	}

	/**
	 * Get sender connection options.
	 * Return the string value for the CONNECTION key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for CONNECTION
	 * @see Context#getConnection()
	 */
	public String getConnection() {
		return get(CONNECTION);
	}

	/**
	 * Return the String value for the CONTENT_BASE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for CONTENT_BASE
	 * @see Context#getContentBase()
	 */
	public String getContentBase() {
		return get(CONTENT_BASE);
	}

	/**
	 * Get what additional content encodings have been applied to the entity body.
	 * Return the string value for the CONTENT_ENCODING key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for CONTENT_ENCODING
	 * @see Context#getContentEncoding()
	 */
	public String getContentEncoding() {
		return get(CONTENT_ENCODING);
	}

	/**
	 * Gets the natural language of the intended audience for the entity body.
	 * Return the string value for the CONTENT_LANGUAGE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for CONTENT_LANGUAGE
	 * @see Context#getContentLanguage()
	 */
	public String getContentLanguage() {
		return get(CONTENT_LANGUAGE);
	}

	/**
	 * Get the content length in bytes of the entity body.
	 * Return the value for the CONTENT_LENGTH key.
	 * Returns -1 if the Content-Length has not been set.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for CONTENT_LENGTH
	 * @see Context#getContentLength()
	 */
	public long getContentLength() {
		String lengthString = get(CONTENT_LENGTH);
		return (lengthString == null) ? -1 : Long.parseLong(lengthString);
	}

	/**
	 * Return the String value for the CONTENT_LOCATION key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for CONTENT_LOCATION
	 * @see Context#getContentLocation()
	 */
	public String getContentLocation() {
		return get(CONTENT_LOCATION);
	}

	/**
	 * Return the string value for the CONTENT_MD5 key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for CONTENT_MD5
	 * @see Context#getContentMD5()
	 */
	public String getContentMD5() {
		return get(CONTENT_MD5);
	}

	/**
	 * Return the string value for the CONTENT_RANGE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for CONTENT_RANGE
	 * @see Context#getContentRange()
	 */
	public String getContentRange() {
		return get(CONTENT_RANGE);
	}

	/**
	 * Get the MIME type for the response contents. 
	 * Return the string value for the CONTENT_TYPE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for CONTENT_TYPE
	 * @see Context#getContentType()
	 */
	public String getContentType() {
		return get(CONTENT_TYPE);
	}

	/**
	 * The date the request was made.
	 * Return the string value for the DATE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for DATE
	 * @see Context#getDate()
	 */
	public String getDate() {
		// TBD parse and return as a Java date
		return get(DATE);
	}

	/**
	 * Get the DAV level supported by the server.
	 * Return the string value for the DAV key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for DAV
	 * @see Context#getDAV()
	 */
	public String getDAV() {
		return get(DAV);
	}

	/**
	 * Return the string value for the DEPTH key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for DEPTH
	 * @see Context#getDepth()
	 */
	public String getDepth() {
		return get(DEPTH);
	}

	/**
	 * Get the destination URI for a copy or move operation.
	 * Return the URI value for the DESTINATION key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for DESTINATION
	 * @see Context#getDestination()
	 */
	public String getDestination() {
		return get(DESTINATION);
	}

	/**
	 * Get the entity tag for the associated entity.
	 * Return the string value for the ETAG key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for ETAG
	 * @see Context#getETag()
	 */
	public String getETag() {
		return get(ETAG);
	}

	/**
	 * Get the date/time after which the response should be considered stale.
	 * Return the string value for the EXPIRES key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for EXPIRES
	 * @see Context#getExpires()
	 */
	public String getExpires() {
		// TDB : Parse and return as a date
		return get(EXPIRES);
	}

	/**
	 * Return the string value for the FROM key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for FROM
	 * @see Context#getFrom()
	 */
	public String getFrom() {
		return get(FROM);
	}

	/**
	 * Get the Internet host and port of the resource being requested.
	 * Return the string value for the HOST key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for HOST
	 * @see Context#HOST
	 */
	public String getHost() {
		return get(HOST);
	}

	/**
	 * Return the string value for the IF key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for IF
	 * @see Context#getIfKey()
	 */
	public String getIfKey() {
		return get(IF);
	}

	/**
	 * Return the string value for the IF_MATCH key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for IF_MATCH
	 * @see Context#getIfMatch()
	 */
	public String getIfMatch() {
		return get(IF_MATCH);
	}

	/**
	 * Return the string value for the IF_MODIFIED_SINCE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for IF_MODIFIED_SINCE
	 * @see Context#getIfModifiedSince()
	 */
	public String getIfModifiedSince() {
		return get(IF_MODIFIED_SINCE);
	}

	/**
	 * Return the string value for the IF_NONE_MATCH key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for IF_NONE_MATCH
	 * @see Context#getIfNoneMatch()
	 */
	public String getIfNoneMatch() {
		return get(IF_NONE_MATCH);
	}

	/**
	 * Return the string value for the IF_RANGE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for IF_RANGE
	 * @see Context#getIfRange()
	 */
	public String getIfRange() {
		return get(IF_RANGE);
	}

	/**
	 * Return the string value for the IF_UNMODIFIED_SINC key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for IF_UNMODIFIED_SINCE
	 * @see Context#getIfUnmodifiedSince()
	 */
	public String getIfUnmodifiedSince() {
		return get(IF_UNMODIFIED_SINCE);
	}

	/**
	 * Get the message label selector.
	 * Return the string value for the LABEL key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for LABEL
	 * @see Context#getLabel()
	 */
	public String getLabel() {
		return get(LABEL);
	}

	/**
	 * Get when the resource was last modified.
	 * Return the string value for the LAST_MODIFIED key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for LAST_MODIFIED
	 * @see Context#getLastModified()
	 */
	public String getLastModified() {
		// TDB: return as date
		return get(LAST_MODIFIED);
	}

	/**
	 * Get the redirect location.
	 * Return the URI value for the LOCATION key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for LOCATION
	 * @see Context#getLocation()
	 */
	public String getLocation() {
		return get(LOCATION);
	}

	/**
	 * Gets the lock token for the resource, or null if it is not set.
	 * Return the lock token value for the LOCK_TOKEN key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for LOCK_TOKEN
	 * @see Context#getLockToken()
	 */
	public String getLockToken() {
		return get(LOCK_TOKEN);
	}

	/**
	 * Return the integer value for the MAX_FORWARDS key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for MAX_FORWARDS
	 * @see Context#getMaxForwards()
	 */
	public int getMaxForwards() {
		String s = get(MAX_FORWARDS);
		return s == null ? -1 : Integer.parseInt(s);
	}

	/**
	 * Return the string value for the ORDERED key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for ORDERED
	 * @see Context#getOrdered()
	 */
	public String getOrdered() {
		return get(ORDERED);
	}

	/**
	 * Get the flag that indicates if copy or move should overwrite
	 * an existing destination. Return the boolean value for the 
	 * OVERWRITE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for OVERWRITE
	 * @see Context#OVERWRITE
	 */
	public boolean getOverwrite() {
		String overwriteString = get(OVERWRITE);
		return overwriteString == null ? false : overwriteString.equalsIgnoreCase("T"); //$NON-NLS-1$
	}

	/**
	 * Return the boolean value for the PASSTHROUGH key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for PASSTHROUGH
	 * @see Context#getPassthrough()
	 */
	public boolean getPassthrough() {
		String s = get(PASSTHROUGH);
		return s == null ? false : s.equalsIgnoreCase("T"); //$NON-NLS-1$
	}

	/**
	 * Return the string value for the POSITION key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for POSITION
	 * @see Context#getPosition()
	 */
	public String getPosition() {
		return get(POSITION);
	}

	/**
	 * Return the string value for the PRAGMA key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for PRAGMA
	 * @see Context#getPragma()
	 */
	public String getPragma() {
		return get(PRAGMA);
	}

	/**
	 * Get any precondition that must be true in order for method
	 * execution to be successful. A precondition corresponds to the
	 * WebDAV "If" header. 
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for PRECONDITION
	 * @see Context#getPrecondition()
	 */
	public String getPrecondition() {
		return get(IF);
	}

	/**
	 * Return the string value for the PROXY_AUTHENTICATE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for PROXY_AUTHENTICATE
	 * @see Context#getProxyAuthenticate()
	 */
	public String getProxyAuthenticate() {
		return get(PROXY_AUTHENTICATE);
	}

	/**
	 * Return the string value for the PROXY_AUTHORIZATION key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for PROXY_AUTHORIZATION
	 * @see Context#getProxyAuthorization()
	 */
	public String getProxyAuthorization() {
		return get(PROXY_AUTHORIZATION);
	}

	/**
	 * Return the string value for the PUBLIC_KEY key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for PUBLIC_KEY
	 * @see Context#getPublicKey()
	 */
	public String getPublicKey() {
		return get(PUBLIC);
	}

	/**
	 * Return the string value for the RANGE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for RANGE
	 * @see Context#getRange()
	 */
	public String getRange() {
		return get(RANGE);
	}

	/**
	 * Get the URI of the resource from which the request was obtained.
	 * Return the String value for the REFERER key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for REFERER
	 * @see Context#getReferer()
	 */
	public String getReferer() {
		return get(REFERER);
	}

	/**
	 * Return the URI value for the REF_TARGET key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for REF_TARGET
	 * @see Context#getRefTarget()
	 */
	public String getRefTarget() {
		return get(REF_TARGET);
	}

	/**
	 * Return the string value for the RESOURCE_TYPE  key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for RESOURCE_TYPE
	 * @see Context#getResourceType()
	 */
	public String getResourceType() {
		return get(RES_TYPE);
	}

	/**
	 * Return the string value for the RETRY_AFTER key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for RETRY_AFTER
	 * @see Context#getRetryAfter()
	 */
	public String getRetryAfter() {
		return get(RETRY_AFTER);
	}

	/**
	 * Get information about the software used by the origin server
	 * to handle the request. Return the string value for the SERVER 
	 * key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for SERVER
	 * @see Context#getServer()
	 */
	public String getServer() {
		return get(SERVER);
	}

	/**
	 * Get the String of the resource whose method is in process.
	 * Return the URI value for the STATUS_URI key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for STATUS_URI
	 * @see Context#getStatusURI()
	 */
	public String getStatusURI() {
		return get(STATUS_URI);
	}

	/**
	 * Get the lock timeout value. The value -1 means that the 
	 * value was not set, the value -2 means that the value was "Infinity".
	 * Return the integer value for the TIMEOUT key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for TIMEOUT
	 * @see Context#getTimeout()
	 */
	public int getTimeout() {
		String timeoutString = get(TIMEOUT);
		if (timeoutString == null)
			return -1;
		if (timeoutString.equalsIgnoreCase(DEPTH_INFINITY))
			return -2;
		if (timeoutString.regionMatches(true, 1, "Second-", 1, 7)) //$NON-NLS-1$
			return Integer.parseInt(timeoutString.substring(7));
		// ignore all other cases, and use infinite timeout
		return -2;
	}

	/**
	 * Return the string value for the TRANSFER_ENCODING key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for TRANSFER_ENCODING
	 * @see Context#getTransferEncoding()
	 */
	public String getTransferEncoding() {
		return get(TRANSFER_ENCODING);
	}

	/**
	 * Return the string value for the UPGRADE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for UPGRADE
	 * @see Context#getUpgrade()
	 */
	public String getUpgrade() {
		return get(UPGRADE);
	}

	/**
	 * Get information about the user agent originating the request.
	 * Return the string value for the USER_AGENT key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for USER_AGENT
	 * @see Context#getUserAgent()
	 */
	public String getUserAgent() {
		return get(USER_AGENT);
	}

	/**
	 * Return the string value for the VARY key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for VARY
	 * @see Context#getVary()
	 */
	public String getVary() {
		return get(VARY);
	}

	/**
	 * Return the string value for the VIA key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for VIA
	 * @see Context#getVia()
	 */
	public String getVia() {
		return get(VIA);
	}

	/**
	 * Return the string value for the WARNING key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for WARNING
	 * @see Context#getWarning()
	 */
	public String getWarning() {
		return get(WARNING);
	}

	/**
	 * Return the string value for the WWW_AUTHENTICATE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for WWW_AUTHENTICATE
	 * @see Context#getWWWAuthenticate()
	 */
	public String getWWWAuthenticate() {
		return get(WWW_AUTHENTICATE);
	}

	/**
	 * Return an enumeration over the context's keys. (recursively computes the
	 * keys based on keys defaults as well)
	 *
	 * @return an enumeration over the context keys
	 */
	public Enumeration keys() {

		if (defaults == null)
			return new ContextKeyToStringEnum(properties.keys());

		Enumeration allKeys = new MergedEnumeration(new ContextKeyToStringEnum(properties.keys()), defaults.keys());

		Hashtable keysSet = new Hashtable();
		while (allKeys.hasMoreElements())
			keysSet.put(allKeys.nextElement(), "ignored"); //$NON-NLS-1$

		return keysSet.keys();
	}

	/**
	 * Put the given key-value pair into the context.
	 *
	 * @param key the key
	 * @param value its associated value
	 */
	public void put(String key, String value) {
		ContextKey ckey = new ContextKey(key);
		if ((value == null) || (value.length() == 0))
			properties.remove(ckey);
		else
			properties.put(ckey, value);
	}

	/**
	 * Remove the given key from the context
	 *
	 * @param key the key to remove
	 */
	public void removeKey(String key) {
		properties.remove(new ContextKey(key));
	}

	/**
	 * Set what media types are acceptable for a response.
	 * Set the string value for the ACCEPT key.
	 *
	 * <p>Implements the corresponding API in the interface 
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for ACCEPT
	 * @see Context#setAccept(String)
	 */
	public void setAccept(String value) {
		put(ACCEPT, value);
	}

	/**
	 * Sets which character sets are acceptable for a response.
	 * Set the string value for the ACCEPT_CHARSET key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for ACCEPT_CHARSET
	 * @see Context#setAcceptCharset(String)
	 */
	public void setAcceptCharset(String value) {
		put(ACCEPT_CHARSET, value);
	}

	/**
	 * Set the content-encoding values which are acceptable for a response.
	 * Set the string value for the ACCEPT_ENCODING key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for ACCEPT_ENCODING
	 * @see Context#setAcceptEncoding(String)
	 */
	public void setAcceptEncoding(String value) {
		put(ACCEPT_ENCODING, value);
	}

	/**
	 * Get the natural languages that are acceptable for a response.
	 * Return the string value for the ACCEPT_LANGUAGE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @return the value for ACCEPT_LANGUAGE
	 * @see Context#setAcceptLanguage()
	 */
	public String setAcceptLanguage() {
		return get(ACCEPT_LANGUAGE);
	}

	/**
	 * Set which natural languages are acceptable for a response.
	 * Set the string value for the ACCEPT_LANGUAGE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for ACCEPT_LANGUAGE
	 * @see Context#setAcceptLanguage(String)
	 */
	public void setAcceptLanguage(String value) {
		put(ACCEPT_LANGUAGE, value);
	}

	/**
	 * Set the range requests acceptable to a server.
	 * Set the string value for the ACCEPT_RANGES key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for ACCEPT_RANGES
	 * @see Context#setAcceptRanges(String)
	 */
	public void setAcceptRanges(String value) {
		put(ACCEPT_RANGES, value);
	}

	/**
	 * Set the sender's estimate of the time since the response was generated.
	 * Set the int value for the AGE key. Set the value to -1 to remove the key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param seconds the value for AGE
	 * @see Context#setAge(int)
	 */
	public void setAge(int seconds) {
		put(AGE, (seconds == -1) ? "" : Integer.toString(seconds)); //$NON-NLS-1$
	}

	/**
	 * Set the string value for the ALL_BINDINGS key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param s the value for ALL_BINDINGS
	 * @see Context#setAllBindings(String)
	 */
	public void setAllBindings(String s) {
		put(ALL_BINDINGS, s);
	}

	/**
	 * Sets methods allowed on a resource
	 * Set the string value for the ALLOW key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for ALLOW
	 * @see Context#setAllow(String)
	 */
	public void setAllow(String value) {
		put(ALLOW, value);
	}

	/**
	 * Set the user's credentials for the realm of the resource being requested.
	 * Set the string value for the AUTHORIZATION key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for AUTHORIZATION
	 * @see Context#setAuthorization(String)
	 */
	public void setAuthorization(String value) {
		put(AUTHORIZATION, value);
	}

	/**
	 * Set the cache control directives that must be obeyed.
	 * Set the string value for the CACHE_CONTROL key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for CACHE_CONTROL
	 * @see Context#setCacheControl(String)
	 */
	public void setCacheControl(String value) {
		put(CACHE_CONTROL, value);
	}

	/**
	 * Set sender connection options.
	 * Set the string value for the CONNECTION key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for CONNECTION
	 * @see Context#setConnection(String)
	 */
	public void setConnection(String value) {
		put(CONNECTION, value);
	}

	/**
	 * Set the String URL value for the CONTENT_BASE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param url the value for CONTENT_BASE
	 * @see Context#setContentBase(String)
	 */
	public void setContentBase(String url) {
		put(CONTENT_BASE, url);
	}

	/**
	 * Sets the additional content encodings that have been applied to the entity body.
	 * Set the string value for the CONTENT_ENCODING key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for CONTENT_ENCODING
	 * @see Context#setContentEncoding(String)
	 */
	public void setContentEncoding(String value) {
		put(CONTENT_ENCODING, value);
	}

	/**
	 * Sets the natural language of the intended audience for the entity body.
	 * Set the string value for the CONTENT_LANGUAGE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for CONTENT_LANGUAGE
	 * @see Context#setContentLanguage(String)
	 */
	public void setContentLanguage(String value) {
		put(CONTENT_LANGUAGE, value);
	}

	/**
	 * Set the content length in bytes of the entity body.
	 * Set the value for the CONTENT_LENGTH key.
	 * Pass the value -1 to remove the key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for CONTENT_LENGTH
	 * @see Context#setContentLength(long)
	 */
	public void setContentLength(long value) {
		put(CONTENT_LENGTH, (value == -1) ? "" : Long.toString(value)); //$NON-NLS-1$
	}

	/**
	 * Set the String URI value for the CONTENT_LOCATION key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for CONTENT_LOCATION
	 * @see Context#setContentLocation(String)
	 */
	public void setContentLocation(String value) {
		put(CONTENT_LOCATION, value);
	}

	/**
	 * Set the string value for the CONTENT_MD5 key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for CONTENT_MD5
	 * @see Context#setContentMD5(String)
	 */
	public void setContentMD5(String value) {
		put(CONTENT_MD5, value);
	}

	/**
	 * Set the string value for the CONTENT_RANGE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for CONTENT_RANGE
	 * @see Context#setContentRange(String)
	 */
	public void setContentRange(String value) {
		put(CONTENT_RANGE, value);
	}

	/**
	 * Set the MIME type for the response contents. 
	 * Set the string value for the CONTENT_TYPE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for CONTENT_TYPE
	 * @see Context#setContentType(String)
	 */
	public void setContentType(String value) {
		put(CONTENT_TYPE, value);
	}

	/**
	 * Set the date the request was made.
	 * Set the string value for the DATE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for DATE
	 * @see Context#setDate(String)
	 */
	public void setDate(String value) {
		put(DATE, value);
	}

	/**
	 * Set the DAV level supported by the server.
	 * Set the string value for the DAV key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for DAV
	 * @see Context#setDAV(String)
	 */
	public void setDAV(String value) {
		put(DAV, value);
	}

	/**
	 * Set the string value for the DEPTH key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param s the value for DEPTH
	 * @see Context#setDepth(String)
	 */
	public void setDepth(String s) {
		put(DEPTH, s);
	}

	/**
	 * Set the destination URI for a copy or move operation.
	 * Set the URI value for the DESTINATION key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for DESTINATION
	 * @see Context#setDestination(String)
	 */
	public void setDestination(String value) {
		put(DESTINATION, value);
	}

	/**
	 * Set the entity tag for the associated entity.
	 * Set the string value for the ETAG key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for ETAG
	 * @see Context#setETag(String)
	 */
	public void setETag(String value) {
		put(ETAG, value);
	}

	/**
	 * Set the date/time after which the response should be considered stale.
	 * Set the string value for the EXPIRES key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for EXPIRES
	 * @see Context#setExpires(String)
	 */
	public void setExpires(String value) {
		// TDB accept a date
		put(EXPIRES, value);
	}

	/**
	 * Set the string value for the FROM key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param s the value for FROM
	 * @see Context#FROM
	 */
	public void setFrom(String s) {
		put(FROM, s);
	}

	/**
	 * Set the Internet host and port of the resource being requested.
	 * Set the string value for the HOST key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for HOST
	 * @see Context#setHost(String)
	 */
	public void setHost(String value) {
		put(HOST, value);
	}

	/**
	 * Set the string value for the IF key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param s the value for IF
	 * @see Context#setIfKey(String)
	 */
	public void setIfKey(String s) {
		put(IF, s);
	}

	/**
	 * Set the string value for the IF_MATCH key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param s the value for IF_MATCH
	 * @see Context#setIfMatch(String)
	 */
	public void setIfMatch(String s) {
		put(IF_MATCH, s);
	}

	/**
	 * Set the string value for the IF_MODIFIED_SINCE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param s the value for IF_MODIFIED_SINCE
	 * @see Context#setIfModifiedSince(String)
	 */
	public void setIfModifiedSince(String s) {
		put(IF_MODIFIED_SINCE, s);
	}

	/**
	 * Set the string value for the IF_NONE_MATCH key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param s the value for IF_NONE_MATCH
	 * @see Context#setIfNoneMatch(String)
	 */
	public void setIfNoneMatch(String s) {
		put(IF_NONE_MATCH, s);
	}

	/**
	 * Set the string value for the IF_RANGE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param s the value for IF_RANGE
	 * @see Context#setIfRange(String)
	 */
	public void setIfRange(String s) {
		put(IF_RANGE, s);
	}

	/**
	 * Set the string value for the IF_UNMODIFIED_SINCE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param s the value for IF_UNMODIFIED_SINCE
	 * @see Context#setIfUnmodifiedSince(String)
	 */
	public void setIfUnmodifiedSince(String s) {
		put(IF_UNMODIFIED_SINCE, s);
	}

	/**
	 * Set the method's label selector.
	 * Set the string value for the LABEL key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for LABEL
	 * @see Context#setLabel(String)
	 */
	public void setLabel(String value) {
		put(LABEL, value);
	}

	/**
	 * Set when the resource was last modified.
	 * Set the string value for the LAST_MODIFIED key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for LAST_MODIFIED
	 * @see Context#setLastModified(String)
	 */
	public void setLastModified(String value) {
		// TDB set as a date
		put(LAST_MODIFIED, value);
	}

	/**
	 * Sets the redirect location.
	 * Set the URI value for the LOCATION key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for LOCATION
	 * @see Context#LOCATION
	 */
	public void setLocation(String value) {
		put(LOCATION, value);
	}

	/**
	 * Set the lock token for the resource.
	 * Set the lock token value for the LOCK_TOKEN key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param token the value for LOCK_TOKEN
	 * @see Context#setLockToken(String)
	 */
	public void setLockToken(String token) {
		put(LOCK_TOKEN, token);
	}

	/**
	 * Set the integer value for the MAX_FORWARDS key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param i the value for MAX_FORWARDS
	 * @see Context#setMaxForwards(int)
	 */
	public void setMaxForwards(int i) {
		put(MAX_FORWARDS, Integer.toString(i));
	}

	/**
	 * Set the string value for the ORDERED key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for ORDERED
	 * @see Context#setOrdered(String)
	 */
	public void setOrdered(String value) {
		put(ORDERED, value);
	}

	/**
	 * Set if copy or move should overwrite an existing destination.
	 * Set the boolean value for the OVERWRITE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for OVERWRITE
	 * @see Context#setOverwrite(boolean)
	 */
	public void setOverwrite(boolean value) {
		put(OVERWRITE, value ? "T" : "F"); //$NON-NLS-1$ //$NON-NLS-2$
	}

	/**
	 * Set the boolean value for the PASSTHROUGH key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for PASSTHROUGH
	 * @see Context#setPassthrough(boolean)
	 */
	public void setPassthrough(boolean value) {
		put(PASSTHROUGH, value ? "T" : "F"); //$NON-NLS-1$ //$NON-NLS-2$
	}

	/**
	 * Set the string value for the POSITION key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param s the value for POSITION
	 * @see Context#setPosition(String)
	 */
	public void setPosition(String s) {
		put(POSITION, s);
	}

	/**
	 * Set the string value for the PRAGMA key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for PRAGMA
	 * @see Context#setPragma(String)
	 */
	public void setPragma(String value) {
		put(PRAGMA, value);
	}

	/**
	 * Set any precondition that must be true in order for method
	 * execution to be successful. A precondition corresponds to the
	 * WebDAV "If" header. 
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for the precondition
	 * @see Context#setPrecondition(String)
	 */
	public void setPrecondition(String value) {
		put(IF, value);
	}

	/**
	 * Set the string value for the PROXY_AUTHENTICATE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for PROXY_AUTHENTICATE
	 * @see Context#setProxyAuthenticate(String)
	 */
	public void setProxyAuthenticate(String value) {
		put(PROXY_AUTHENTICATE, value);
	}

	/**
	 * Set the string value for the PROXY_AUTHORIZATION key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for PROXY_AUTHORIZATION
	 * @see Context#setProxyAuthorization(String)
	 */
	public void setProxyAuthorization(String value) {
		put(PROXY_AUTHORIZATION, value);
	}

	/**
	 * Set the string value for the PUBLIC_KEY key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for PUBLIC_KEY
	 * @see Context#setPublicKey(String)
	 */
	public void setPublicKey(String value) {
		put(PUBLIC, value);
	}

	/**
	 * Set the string value for the RANGE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for RANGE
	 * @see Context#setRange(String)
	 */
	public void setRange(String value) {
		put(RANGE, value);
	}

	/**
	 * Set the URI of the resource from which the request was obtained.
	 * Set the String value for the REFERER key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for REFERER
	 * @see Context#setReferer(String)
	 */
	public void setReferer(String value) {
		put(REFERER, value);
	}

	/**
	 * Set the URI value for the REF_TARGET key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for REF_TARGET
	 * @see Context#setRefTarget(String)
	 */
	public void setRefTarget(String value) {
		put(REF_TARGET, value);
	}

	/**
	 * Set the string value for the RESOURCE_TYPE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for RESOURCE_TYPE
	 * @see Context#setResourceType(String)
	 */
	public void setResourceType(String value) {
		put(RES_TYPE, value);
	}

	/**
	 * Set the string value for the RETRY_AFTER key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for RETRY_AFTER
	 * @see Context#setRetryAfter(String)
	 */
	public void setRetryAfter(String value) {
		put(RETRY_AFTER, value);
	}

	/**
	 * Set information about the software used by the origin server
	 * to handle the request. Set the string value for the SERVER key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for SERVER
	 * @see Context#setServer(String)
	 */
	public void setServer(String value) {
		put(SERVER, value);
	}

	/**
	 * Set the URI of the resource whose method is in process.
	 * Set the String value for the STATUS_URI key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for STATUS_URI
	 * @see Context#setStatusURI(String)
	 */
	public void setStatusURI(String value) {
		put(STATUS_URI, value);
	}

	/**
	 * Set the lock timeout value in seconds. Pass -1 to clear the 
	 * value, pass -2 to set "Infinity". Set the integer value for the 
	 * TIMEOUT key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for TIMEOUT
	 * @see Context#setTimeout(int)
	 */
	public void setTimeout(int value) {
		if (value == -1)
			put(TIMEOUT, ""); //$NON-NLS-1$
		else
			put(TIMEOUT, (value == -2) ? DEPTH_INFINITY : "Second-" + Integer.toString(value)); //$NON-NLS-1$
	}

	/**
	 * Set the string value for the TRANSFER_ENCODING key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for TRANSFER_ENCODING
	 * @see Context#setTransferEncoding(String)
	 */
	public void setTransferEncoding(String value) {
		put(TRANSFER_ENCODING, value);
	}

	/**
	 * Set the string value for the UPGRADE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for UPGRADE
	 * @see Context#setUpgrade(String)
	 */
	public void setUpgrade(String value) {
		put(UPGRADE, value);
	}

	/**
	 * Set information about the user agent originating the request.
	 * Set the string value for the USER_AGENT key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for USER_AGENT
	 * @see Context#setUserAgent(String)
	 */
	public void setUserAgent(String value) {
		put(USER_AGENT, value);
	}

	/**
	 * Set the string value for the VARY key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for VARY
	 * @see Context#setVary(String)
	 */
	public void setVary(String value) {
		put(VARY, value);
	}

	/**
	 * Set the string value for the VIA key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for VIA
	 * @see Context#setVia(String)
	 */
	public void setVia(String value) {
		put(VIA, value);
	}

	/**
	 * Set the string value for the WARNING key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for WARNING
	 * @see Context#setWarning(String)
	 */
	public void setWarning(String value) {
		put(WARNING, value);
	}

	/**
	 * Set the string value for the WWW_AUTHENTICATE key.
	 *
	 * <p>Implements the corresponding API in the interface
	 * <code>Context</code>.</p>
	 *
	 * @param value the value for WWW_AUTHENTICATE
	 * @see Context#setWWWAuthenticate(String)
	 */
	public void setWWWAuthenticate(String value) {
		put(WWW_AUTHENTICATE, value);
	}

	/**
	 * Return a string representation of the context.
	 *
	 * @return the context, as a String
	 */
	public String toString() {
		StringBuffer buffer = new StringBuffer();
		Enumeration keysEnum = keys();
		while (keysEnum.hasMoreElements()) {
			String key = (String) keysEnum.nextElement();
			buffer.append(key);
			buffer.append(": "); //$NON-NLS-1$
			buffer.append(get(key));
			buffer.append('\n');
		}
		return buffer.toString();
	}
}
