/*
	ZazouMiniWebServer

	Copyright (C) 2003-2011 Xavier Garreau <xavier@xgarreau.org>

	This file is part of ZazouMiniWebServer.

    ZazouMiniWebServer is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    ZazouMiniWebServer is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with ZazouMiniWebServer; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
*/

#if !defined(AFX_ZMWSREQRESP_H__5D195984_8DB7_4805_B723_B6966B2664C8__INCLUDED_)
#define AFX_ZMWSREQRESP_H__5D195984_8DB7_4805_B723_B6966B2664C8__INCLUDED_

#include "ZOSAL.h"
#include <string>
#include <map>
#include "ZMWSCommon.h"
#include "ZMWSConfig.h"
#include "../ZazouModSsl/ZazouModSsl.h"

typedef std::map<std::string, std::string> RRVARS;
typedef std::pair<std::string, std::string> RRVAR;
typedef int HTTP_RETCODE;

enum REQSTATUS {
	NONE = 0,
	RETCODE_SENT,
	HEADERS_SENT,
	DOC_SENT,
	DONE,
	REQERROR
};

enum { CNX_POLICY_KEEP = 0, CNX_POLICY_CLOSE};

class ZMWSRange {
public:
	enum RANGE_SPEC_TYPE {
		INVALID_RANGE_SPEC, 
		BYTE_RANGE_SPEC,
		PREFIX_BYTE_RANGE_SPEC,
		SUFFIX_BYTE_RANGE_SPEC
	};
	DWORD begin;
	DWORD end;
	RANGE_SPEC_TYPE range_spec_type;
	ZMWSRange () : begin(0),end(0),range_spec_type(INVALID_RANGE_SPEC) {};
	ZMWSRange (DWORD b, DWORD e, const RANGE_SPEC_TYPE& rsp = BYTE_RANGE_SPEC) : begin(b), end(e),range_spec_type(rsp) { }
};

class ZMWSContentRange {
public:
	DWORD begin;
	DWORD end;
	DWORD size;

	ZMWSContentRange () : begin(0), end(0), size(0) { }
	ZMWSContentRange (DWORD b, DWORD e, DWORD s) : begin(b), end(e), size(s) { }
	inline BOOL isValid() { return (size>0); }
};

typedef std::vector<ZMWSRange> ranges_type;
typedef std::vector<ZMWSContentRange> content_ranges_type;

typedef std::multimap<double, std::string> langs_map_type;
typedef std::pair<double, std::string> lang_pair_type;
class ZMWSReqResp  
{
	HTTP_REQMETHOD reqMethod;
	HTTP_RETCODE retCode;
	REQSTATUS status;
	const SOCKET* pClientSocket;
	HANDLE_FILE* pFileHandle;
	RRVARS reqvars;
	RRVARS respvars;
	std::string requestLine;
	std::string respLine;
	std::string filePath;
	std::string fileExtension;
	std::string authFilePath;
	std::string authRealm;
	std::string reqRootDir;
	std::string aliasRootDir;
	std::string URL;
	ZMWSHandler handler;
	std::string errMsg;
	DWORD bytesSent_HI;
	DWORD bytesSent_LO;
	double http_ver;
	BOOL isDir;
	BOOL isSSL;
	ZazouModData_t modssl_data;
	ranges_type ranges;
	content_ranges_type content_ranges;
	langs_map_type langs_map;

void UpdateRanges(const std::string& RangeReq);

public:
	ZMWSReqResp(SOCKET* sock = NULL);
	virtual ~ZMWSReqResp();

	int cnx_policy;
	/*
	 * Les RespVar sont au format HTTP/1.1, majuscule
	 * au début des mots séparés par des "-".
	 * 
	 * Exemples:
	 *		- Content-Type: image/png
	 *		- Connection: Keep-Alive
	 * Et pas comme ça:
	 *		- content-type: image/png
	 *		- Content-type: image/png
	 */
	const std::string setRespVar(const std::string& varName, const std::string& varVal, const BOOL& Override = TRUE);
	const std::string getRespVar(const std::string& varName);
	void eraseRespVar(const std::string& varName);
	const RRVARS& getRespVars() const { return respvars; };

	/*
	 * Les ReqVar sont passées en majuscules
	 * et les "-" sont remplacés par des _.
	 * Exemple:
	 *		- Content-Length devient CONTENT_LENGTH
	 */
	const std::string setReqVar(const std::string& varName, const std::string& varVal, const BOOL& Override = TRUE);
	const std::string getReqVar(const std::string& varName);
	const RRVARS& getReqVars() const { return reqvars; };
	const langs_map_type& getLangsMap() const { return langs_map; };
	void addLang(const std::string& lang, const double& aqual);

	void setRequestLine(const std::string& value) { requestLine = value; };
	const std::string& getRequestLine() const { return requestLine; };
	void setRespLine(const std::string& value) { respLine = value; };
	const std::string& getRespLine() const { return respLine; };
	void setAliasedRootDir(const std::string& ard) { aliasRootDir = ard; };
	const std::string& getAliasedRootDir() const { return aliasRootDir; };
	void setReqRootDir(const std::string& rrd) { reqRootDir = rrd; };
	const std::string& getReqRootDir() const { return reqRootDir; };
	void setHTTPVer(const double& value) { http_ver = value; };
	const double& getHTTPVer() const { return http_ver; };
	void setURL(const std::string& value);
	std::string& getURL() { return URL; };
	void setHandler(const ZMWSHandler& value) { handler = value;};
	ZMWSHandler& getHandler() { return handler; };
	void setFilePath(const std::string& value);
	std::string& getFilePath() { return filePath; };
	void setFileExtension(const std::string& value) { fileExtension = value; };
	std::string& getFileExtension() { return fileExtension; };
	void setIsDirectory(const BOOL& value = TRUE) { isDir = value; };
	BOOL& getIsDirectory() { return isDir; };
	void SetIsSSL(const BOOL& value = TRUE) { isSSL = value; };
	BOOL& getIsSSL() { return isSSL; };
	void SetModSSLData(const ZazouModData_t md) { modssl_data = md; };
	ZazouModData_t GetModSSLData() { return modssl_data; }

	void setAuthFilePath(const std::string& afp) { authFilePath = afp; };
	const std::string& getAuthFilePath() { return authFilePath; };
	void setAuthRealm(const std::string& ar) { authRealm = ar; };
	const std::string& getAuthRealm() { return authRealm; };
	
	inline void setRetCode(const HTTP_RETCODE& rc) { retCode = rc; };
	inline const HTTP_RETCODE& getRetCode() const { return retCode;};
	inline void setReqMethod(const HTTP_REQMETHOD& rm) { reqMethod = rm; };
	inline const HTTP_REQMETHOD& getReqMethod() const { return reqMethod;};
	inline void setHandle(HANDLE_FILE* pHandle) { pFileHandle = pHandle; };
	inline HANDLE_FILE* getHandle() const { return pFileHandle; };
	inline void setSocket(const SOCKET* sock) { pClientSocket = sock; };
	inline const SOCKET* getSocket() const { return pClientSocket; };

	BOOL addSentBytes(const DWORD& moreBytes);
	const DWORD& getSentBytes_LO () const { return bytesSent_LO; };
	const DWORD& getSentBytes_HI () const { return bytesSent_HI; };

	ZMWSRange popRangeReq();
	void pushContentRangeResp(ZMWSContentRange range);
	ZMWSContentRange popContentRangeResp();

	std::string ComputeDate(SYSTEMTIME& st);
	std::string RemovePort(const std::string& HOSTvar);

	void setErrorMessage(const std::string& msg) { errMsg = msg; }
	const std::string& getErrorMessage() { return errMsg; }
};

#endif // !defined(AFX_ZMWSREQRESP_H__5D195984_8DB7_4805_B723_B6966B2664C8__INCLUDED_)
