/*
	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
*/
	
// ZMWSReqResp.cpp: implementation of the ZMWSReqResp class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ZMWSReqResp.h"
#include "ZMWSFileUtils.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

ZMWSReqResp::ZMWSReqResp(SOCKET* sock)
{
	retCode = 200;
	status = NONE;
	pClientSocket = NULL;
	pFileHandle = NULL;
	bytesSent_HI = 0;
	bytesSent_LO = 0;
	cnx_policy = CNX_POLICY_KEEP;
	isDir = FALSE;
	isSSL = FALSE;
	aliasRootDir = "";
}

ZMWSReqResp::~ZMWSReqResp()
{
	reqvars.clear();
	respvars.clear();
}

BOOL ZMWSReqResp::addSentBytes(const DWORD& moreBytes) {
	if (bytesSent_LO + moreBytes < bytesSent_LO) 
		++bytesSent_HI;
	bytesSent_LO += moreBytes;
	return TRUE;
}

const std::string ZMWSReqResp::setRespVar(const std::string& varName,
										   const std::string& varVal,
										   const BOOL& Override)
{
	std::string retString("");
	if (Override) {
//		retString = respvars[varName];
		respvars[varName] = varVal;
	} else {
		if (respvars.find(varName) != respvars.end()) {
			retString = respvars[varName];
		} else {
			respvars[varName] = varVal;
		}
	}
	return retString;
}

const std::string ZMWSReqResp::getRespVar(const std::string& varName)
{
	std::string retString("");
	if (respvars.find(varName) != respvars.end()) {
		retString = respvars[varName];
	}
	return retString;
}

void ZMWSReqResp::eraseRespVar(const std::string& varName)
{
	respvars.erase(varName);
}

const std::string ZMWSReqResp::setReqVar(const std::string& varName,
										  const std::string& varVal,
										  const BOOL& Override)
{
	std::string retString("");
	if (Override) {
//		retString = reqvars[varName];
		reqvars[varName] = varVal;
	} else {
		if (reqvars.find(varName) != reqvars.end()) {
			retString = reqvars[varName];
		} else {
			reqvars[varName] = varVal;
		}
	}
	if (varName=="RANGE") 
		UpdateRanges(varVal);
	return retString;
}

const std::string ZMWSReqResp::getReqVar(const std::string& varName)
{
	std::string retString("");
	if (reqvars.find(varName) != reqvars.end()) {
		retString = reqvars[varName];
	}
	return retString;
}

void ZMWSReqResp::setURL(const std::string& value)
{
	std::string urlmin;
	urlmin = value;
	std::transform(urlmin.begin(), urlmin.end(), urlmin.begin(), tolower);
	if (urlmin.substr(0, 7)=="http://") {
		std::string::size_type lastslash = urlmin.find('/', 7);
		if (lastslash != std::string::npos) {
			URL = value.substr(lastslash);
			setReqVar("HOST", value.substr(7, lastslash-7));
		} else {
			URL = '/';
			setReqVar("HOST", value.substr(7));
		}
	} else {
		URL = value;
	}
}

void ZMWSReqResp::setFilePath(const std::string& value)
{
	// get rid of a trailing slash
	filePath = value;
	ZMWSFileUtils::normalizePath(filePath);
	std::string::size_type len = filePath.length();

	DWORD nbOff = 0;
	while (filePath[len-(1+nbOff)]=='\\') {
		++nbOff;
	}
	filePath = (filePath.substr(0, len-nbOff));
}

void ZMWSReqResp::addLang(const std::string& alang, const double& aqual) {
	langs_map.insert (lang_pair_type (aqual, alang));
}


std::string ZMWSReqResp::RemovePort(const std::string& HOSTvar)
{
	std::string host;
	std::string::size_type hostend = HOSTvar.rfind(':');
	if (hostend != std::string::npos)
		host = HOSTvar.substr(0, hostend);
	else
		host = HOSTvar;
	return host;
}

std::string ZMWSReqResp::ComputeDate(SYSTEMTIME& st) {
	std::stringstream dateS;

	switch (st.wDayOfWeek) {
		case 0: dateS << "Sun, "; break;
		case 1: dateS << "Mon, "; break;
		case 2: dateS << "Tue, "; break;
		case 3: dateS << "Wed, "; break;
		case 4: dateS << "Thu, "; break;
		case 5: dateS << "Fri, "; break;
		case 6: dateS << "Sat, "; break;
		default: return "";
	}
	if (st.wDay<10) dateS << "0";
	dateS << st.wDay;
	switch (st.wMonth) {
		case 1: dateS << " Jan "; break;
		case 2: dateS << " Feb "; break;
		case 3: dateS << " Mar "; break;
		case 4: dateS << " Apr "; break;
		case 5: dateS << " May "; break;
		case 6: dateS << " Jun "; break;
		case 7: dateS << " Jul "; break;
		case 8: dateS << " Aug "; break;
		case 9: dateS << " Sep "; break;
		case 10: dateS << " Oct "; break;
		case 11: dateS << " Nov "; break;
		case 12: dateS << " Dec "; break;
		default: return "";
	}
	if (st.wYear<1000) dateS << "0";
	if (st.wYear<100) dateS << "0";
	if (st.wYear<10) dateS << "0";
	dateS << st.wYear << " ";
	if (st.wHour<10) dateS << "0";
	dateS << st.wHour << ":";
	if (st.wMinute<10) dateS << "0";
	dateS << st.wMinute << ":";
	if (st.wSecond<10) dateS << "0";
	dateS << st.wSecond << " GMT";

	return dateS.str();
}

void ZMWSReqResp::UpdateRanges(const std::string& RangeReq)
{
	// On vire "bytes="
	std::string varRangeReq = RangeReq.substr(6);
	std::string::size_type tiret_pos = varRangeReq.find("-");
	
	std::string::size_type virgule_pos = varRangeReq.find(",");
	// On ignore les range multiples pour l'instant
	if (virgule_pos != std::string::npos) return;

	if (tiret_pos != std::string::npos) {
		if (tiret_pos > 0) {
			// on a un byte range
			unsigned long first_byte, last_byte;
			std::string first_byte_str, last_byte_str;
			first_byte_str = varRangeReq.substr(0, tiret_pos);
			first_byte = strtoul(first_byte_str.c_str(), NULL, 10);
			if (tiret_pos < varRangeReq.length()-1) {
				last_byte_str = varRangeReq.substr(tiret_pos + 1);
				last_byte = strtoul(last_byte_str.c_str(), NULL, 10);
				ranges.push_back(ZMWSRange(first_byte, last_byte));
			} else {
				ranges.push_back(ZMWSRange(first_byte, 0, ZMWSRange::PREFIX_BYTE_RANGE_SPEC));
			}
		} else {
			// on a un suffix byte range 
			unsigned long last_n_bytes;
			std::string last_n_bytes_str;
			last_n_bytes_str = varRangeReq.substr(tiret_pos + 1);
			last_n_bytes = strtoul(last_n_bytes_str.c_str(), NULL, 10);
			ranges.push_back(ZMWSRange(0, last_n_bytes, ZMWSRange::SUFFIX_BYTE_RANGE_SPEC));
		}
	}
}

ZMWSRange ZMWSReqResp::popRangeReq() {
	ZMWSRange retRange;
	if (ranges.size()) {
		retRange = ranges.back();
		ranges.pop_back();
	}
	return retRange;
}

void ZMWSReqResp::pushContentRangeResp(ZMWSContentRange range) {
	content_ranges.push_back(range);
}

ZMWSContentRange ZMWSReqResp::popContentRangeResp() {
	ZMWSContentRange retRange;
	if (content_ranges.size()) {
		retRange = content_ranges.back();
		content_ranges.pop_back();
	}
	return retRange;
}

