// $Id: CRequest.cc,v 1.8 2003/05/10 06:46:48 ta_muto Exp $

#include <CRequest.h>

wax::CParameterItem::CParameterItem(const xmlChar* initName, const xmlChar* initValue, bool initFixed)
{
	if(initName != NULL) {
		name = xmlStrdup(initName);
	} else {
		name = NULL;
	}
	if(initValue != NULL) {
		origin = xmlStrdup(initValue);
		value = quoteStrdup(initValue);
	} else {
		origin = NULL;
		value = NULL;
	}
	fixed = initFixed;
}

wax::CParameterItem::~CParameterItem()
{
	if(name != NULL)	xmlFree(name);
	if(value != NULL)	xmlFree(value);
	if(origin != NULL)	xmlFree(origin);
}

void wax::CParameterItem::setOriginalValue(const xmlChar* newValue)
{
	if(fixed == true)	return; // safety lock.

	if(value != NULL)	xmlFree(value);
	if(origin != NULL)	xmlFree(origin);
	if(newValue != NULL) {
		origin = xmlStrdup(newValue);
		value = quoteStrdup(newValue);
	} else {
		value = NULL;
		origin = NULL;
	}
}

xmlChar* wax::CParameterItem::quoteStrdup(const xmlChar* newValue)
{
	xmlChar* retValue = NULL;
	if(newValue != NULL) {
		if(xmlStrchr(newValue, '"')) {
			if(xmlStrchr(newValue, '\'')) {
				return NULL;
			} else {
				retValue = xmlStrdup((const xmlChar*)"'");
				retValue = xmlStrcat(retValue, newValue);
				retValue = xmlStrcat(retValue, (const xmlChar*)"'");
			}
		} else {
			retValue = xmlStrdup((const xmlChar*)"\"");
			retValue = xmlStrcat(retValue, newValue);
			retValue = xmlStrcat(retValue, (const xmlChar*)"\"");
		}
	}
	return retValue;
}

wax::CRequest::CRequest()
{
	userAgent = NULL;
}

wax::CRequest::~CRequest()
{
	if(userAgent != NULL)	xmlFree(userAgent);
}

#define CHUNKBUFFER	1024

bool wax::CRequest::init()
{
	char* eua = getenv("HTTP_USER_AGENT");
	if(eua == NULL) {
		userAgent = xmlStrdup((const xmlChar*)"");
	} else {
		userAgent = xmlStrdup((const xmlChar*)eua);
	}

	// parse Request Parameter.
	char* queryString = getenv("QUERY_STRING");
	if(queryString != NULL && strcmp(queryString, "")) {
		char* buffer = new char[strlen(queryString) + 1];
		strcpy(buffer, queryString);
		parseParameter(buffer);
		delete [] buffer;
	}
	char* contentLength = getenv("CONTENT_LENGTH");
	if(contentLength != NULL) {
		char* contentType = getenv("CONTENT_TYPE");
		if(contentType != NULL) {
			if(!strcmp(contentType, "application/x-www-form-urlencoded")) {
				int length = atoi(contentLength);
				char buffer[CHUNKBUFFER];
				int size;
				int chunk = 0;
				while((size = fread(buffer + chunk, 1, CHUNKBUFFER - chunk, stdin)) > 0) {
					buffer[size] = '\0';
					
					chunk = parseParameter(buffer, false);
					if(chunk >= CHUNKBUFFER) {
						IError::message(ERR_POSTEDDATA);
						return false;
					}
				}
				if(chunk > 0) {
					parseParameter(buffer, true);
				}
			}
			// else if("text/xml"?) { I thinking... and others. (ex.multipart-form)
			
			
		}
	}
	return true;
}

wax::CParameterItem* wax::CRequest::findParameter(const xmlChar* name)
{
	CParameterItem* item = (CParameterItem*) params.getHead();
	while(item != NULL) {
		if(!xmlStrcmp(item->getName(), name)) {
			return item;
		}
		item = (CParameterItem*) item->getNext();
	}
	return NULL;
}

int wax::CRequest::parseParameter(char* paramString, bool isFinish)
{
	if(paramString != NULL) {
		int size = 0;
		char* namePtr = paramString;
		for(int i = 0; paramString[i] != '\0'; i++) {
			if(paramString[i] == '=') {
				paramString[i] = '\0';
				i++;
				char* valuePtr = &(paramString[i]);
				while(paramString[i] != '&' && paramString[i] != '\0') {
					i++;
				}
				if(paramString[i] == '\0' && isFinish == false) {
					sprintf(paramString, "%s=%s", namePtr, valuePtr);
					return strlen(paramString);
				}
				paramString[i] = '\0';
				escapeTokens(namePtr, valuePtr);
				namePtr = &(paramString[i+1]);
			}
		}
	}
	return 0;
}

void wax::CRequest::escapeTokens(char* name, char* value)
{
	escape(name);
	escape(value);
	
	CXmlStr xName(C2UTF8(name));
	CXmlStr xVal(C2UTF8(value));
	
	params.addItem(new CParameterItem(xName.value(), xVal.value(), true));
}

void wax::CRequest::escape(char* source)
{
	char* dest;
	for(dest = source; *source != '\0'; source++) {
		if(*source == '%') {
//			oops! Bug in Visual C++ 7?
//			*dest++ = (AtoH(*++source)<<4) + AtoH(*++source);
			char work = (AtoH(*(source+1)) << 4) + AtoH(*(source+2));
			*dest++ = work;
			source += 2;
		} else if(*source == '+') {
			*dest++ = ' ';
		} else {
			*dest++ = *source;
		}
	}
	*dest = '\0';
}

char wax::CRequest::AtoH(char c)
{
	if('0' <= c && c <= '9')	return c - '0';
	if('A' <= c && c <= 'F')	return c - 'A' + 10;
	return 0;
}
