/**
 * @file
 */
#ifndef UI_UTIL_HTTP_COOKIE_HPP
#define UI_UTIL_HTTP_COOKIE_HPP

// STDC
#include <ctime>

// STDC++
#include <string>
#include <vector>

// C++ libraries
#include <ui-utilcpp/http/Header.hpp>

namespace UI {
namespace Util {
namespace Http {

/** @todo Parts marked "GENERIC PART" should be solved by a generic key/pair vector. */

class Cookie: private std::pair<std::string, std::string>
{
public:
	Cookie(std::string const & name, std::string const & value);
	std::string const & getName()  const;
	std::string const & getValue() const;
};

/** @brief Handle "Cookie" request header field values syntactically.
 *
 * @note Wording <em>line</em> means a string in "Cookie" header field
 * value syntax ("a=b;c=d;e=f") as described
 * http://wp.netscape.com/newsref/std/cookie_spec.html .
 */
class Cookies: public std::vector<Cookie>
{
public:
	Cookies(std::string const & line="", std::string const & prefix="");
	Cookies(HeaderField const & field, std::string const & prefix="");
	Cookies(Header const & header, std::string const & prefix="");

	/** @name Modifiers (add cookies).
	 *  @{ */
	Cookies & add(std::string const & name, std::string const & value);
	Cookies & addLine(std::string const & line, std::string const & prefix="");
	Cookies & add(Header const & header, std::string const & prefix="");
	/** @} */

	/** @name Accessors.
	 *  @{ */
	// GENERIC PART
	const_iterator find(std::string const & name) const;
	bool exists(std::string const & name) const;
	std::string const & get(std::string const & name, bool doThrow=true) const;
	// END GENERIC PART
	std::string getLine(std::string const & prefix="") const;
	/** @} */
};

/** @brief Handle "SetCookie" request header field values syntactically.
 *
 * @note Wording <em>line</em> means a string in "SetCookie" header
 * field value syntax ("NAME=a;expires=b;path=c;...") as described
 * http://wp.netscape.com/newsref/std/cookie_spec.html .
 *
 * @todo Syntax integrity checks for setVALUE methods (expires, domain, path, ...).
 */
class SetCookie
{
public:
	SetCookie(HeaderField const & field);
	SetCookie(std::string const & name, std::string const & value="");

	/** @name Modifiers (set values).
	 *  @{ */
	SetCookie & setName(std::string const & name);
	SetCookie & setValue(std::string const & value);
	SetCookie & setExpires(std::string const & expires="Tue, 01-Jan-1980 00:00:00 GMT");
	SetCookie & setExpires(time_t const timestamp);
	SetCookie & setPath(std::string const & path);
	SetCookie & setDomain(std::string const & domain);
	SetCookie & setSecure(bool const & secure=true);

	/** @brief This resets all values and sets the values in line. */
	SetCookie & setLine(std::string const & line);
	/** @} */

	/** @name Accessors. */
	/** @{ */
	std::string const & getName()    const;
	std::string const & getValue()   const;
	std::string const & getExpires() const;
	std::string const & getPath()    const;
	std::string const & getDomain()  const;
	/** @} */

private:
	void addTok(std::string & line, std::string const & name, std::string const & value) const;
	void addTokDef(std::string & line, std::string const & name, std::string const & value, std::string const & defaultValue) const;

public:
	/** @brief Composition. */
	std::string getLine(std::string const & prefix="",
	                    std::string const & expiresDefault="",
	                    std::string const & pathDefault="",
	                    std::string const & domainDefault="") const;

private:
	std::string name_;
	std::string value_;
	std::string expires_;
	std::string path_;
	std::string domain_;
	bool secure_;
};


/** @brief Handle a vector of SetCookie's. */
class SetCookies: public std::vector<SetCookie>
{
public:
	SetCookies();
	SetCookies(Header const & header);

	SetCookie & add(std::string const & name, std::string const & value="");

	/** @name Accessors. */
	/** @{ */
	// GENERIC PART
	const_iterator find(std::string const & name) const;
	bool exists(std::string const & name) const;
	SetCookie const & get(std::string const & name) const;
	// END GENERIC PART

	Header getHeader(std::string const & prefix="",
	                 std::string const & expiresDefault="",
	                 std::string const & pathDefault="",
	                 std::string const & domainDefault="") const;
	/** @} */
};

}}}
#endif
