/*
 * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
 * Copyright (C) 2009 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */

#ifndef HTTPHeaderMap_h
#define HTTPHeaderMap_h

#include <utility>
#include "HTTPHeaderNames.h"
#include <wtf/HashMap.h>
#include <wtf/PassOwnPtr.h>
#include <wtf/Vector.h>
#include <wtf/text/AtomicString.h>
#include <wtf/text/AtomicStringHash.h>
#include <wtf/text/StringHash.h>
#include <wtf/text/StringView.h>

namespace WebCore {

typedef Vector<std::pair<String, String> > CrossThreadHTTPHeaderMapData;

struct HTTPHeaderHashTraits : HashTraits<String> {
	static const int minimumTableSize = 8;
};

class HTTPHeaderMap : public HashMap<String, String, ASCIICaseInsensitiveHash, HTTPHeaderHashTraits> {
private:
	// Adapter that allows the HashMap to take C strings as keys.
	struct CaseFoldingASCIILiteralTranslator {
		static ALWAYS_INLINE unsigned hash(const ASCIILiteral& literal)
		{
			return ASCIICaseInsensitiveHash::hash(literal.characters(), literal.length());
		}

		static ALWAYS_INLINE bool equal(const String& key, const ASCIILiteral& literal)
		{
			return equalIgnoringCase(key, literal);
		}

		static ALWAYS_INLINE void translate(String& location, const ASCIILiteral& literal, unsigned /*hash*/)
		{
			location = String::fromLiteral(literal.characters(), literal.length());
		}
	};

public:
	ALWAYS_INLINE HTTPHeaderMap() {}
	ALWAYS_INLINE ~HTTPHeaderMap() {}

	// Gets a copy of the data suitable for passing to another thread.
	PassOwnPtr<CrossThreadHTTPHeaderMapData> copyData() const;

	void adopt(PassOwnPtr<CrossThreadHTTPHeaderMapData>);

	String get(const String& name) const
	{
		return HashMap<String, String, ASCIICaseInsensitiveHash, HTTPHeaderHashTraits>::get(name);
	}

    String get(HTTPHeaderName headerName) const
    {
    	StringView name = httpHeaderNameString(headerName);
    	return get(name.toStringWithoutCopying());
    }

	AddResult add(const String& name, const String& value)
	{
		return HashMap<String, String, ASCIICaseInsensitiveHash, HTTPHeaderHashTraits>::add(name, value);
	}

	AddResult add(HTTPHeaderName headerName, const String& value)
	{
    	StringView name = httpHeaderNameString(headerName);
		return add(name.toStringWithoutCopying(), value);
	}

	bool addIfNotPresent(HTTPHeaderName headerName, const String& value)
	{
    	StringView name = httpHeaderNameString(headerName);
    	return add(name.toStringWithoutCopying(), value).isNewEntry;
	}

	String get(const ASCIILiteral& name) const
	{
		const_iterator i = find<const ASCIILiteral&, CaseFoldingASCIILiteralTranslator>(name);
		if (i == end())
			return String();
		return i->second;
	}

	bool contains(const ASCIILiteral& name) const
	{
	    return find<const ASCIILiteral&, CaseFoldingASCIILiteralTranslator>(name) != end();
	}

	bool contains(const String& name) const
	{
		return HashMap<String, String, ASCIICaseInsensitiveHash, HTTPHeaderHashTraits>::find(name) != end();
	}

	bool contains(HTTPHeaderName headerName) const
	{
    	StringView name = httpHeaderNameString(headerName);
		return contains(name.toStringWithoutCopying());
	}

	AddResult add(const ASCIILiteral& name, const String& value)
	{
	    return HashMap<String, String, ASCIICaseInsensitiveHash, HTTPHeaderHashTraits>::add<CaseFoldingASCIILiteralTranslator>(name, value);
	}

	void remove(const ASCIILiteral& name)
	{
		HashMap<String, String, ASCIICaseInsensitiveHash, HTTPHeaderHashTraits>::remove(find<const ASCIILiteral&, CaseFoldingASCIILiteralTranslator>(name));
	}

	using HashMap<String, String, ASCIICaseInsensitiveHash, HTTPHeaderHashTraits>::remove;

	void remove(const String& name)
	{
		HashMap<String, String, ASCIICaseInsensitiveHash, HTTPHeaderHashTraits>::remove(name);
	}

	void remove(HTTPHeaderName headerName)
	{
    	StringView name = httpHeaderNameString(headerName);
		remove(name.toStringWithoutCopying());
	}

	AddResult set(const String& name, const String& value)
	{
		return HashMap<String, String, ASCIICaseInsensitiveHash, HTTPHeaderHashTraits>::set(name, value);
	}

	AddResult set(HTTPHeaderName headerName, const String& value)
	{
    	StringView name = httpHeaderNameString(headerName);
		return set(name.toStringWithoutCopying(), value);
	}

	static const String& authorizationName();
	static const String& refererName();
	static const String& contentTypeName();
	static const String& ifMatchName();
	static const String& ifModifiedSinceName();
	static const String& ifNoneMatchName();
	static const String& ifRangeName();
	static const String& ifUnmodifiedSinceName();
};

} // namespace WebCore

#endif // HTTPHeaderMap_h
