/*
 *
 * @APPLE_LICENSE_HEADER_START@
 *
 * Copyright (c) 1999-2001 Apple Computer, Inc.  All Rights Reserved. The
 * contents of this file constitute Original Code as defined in and are
 * subject to the Apple Public Source License Version 1.2 (the 'License').
 * You may not use this file except in compliance with the License.  Please
 * obtain a copy of the License at http://www.apple.com/publicsource and
 * read it before using this file.
 *
 * This Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.  Please
 * see the License for the specific language governing rights and
 * limitations under the License.
 *
 *
 * @APPLE_LICENSE_HEADER_END@
 *
 */
/*
	File:		QTSSWebDebugModule.cpp

	Contains:	Implements web debug module

	
*/

#include "QTSSWebDebugModule.h"
#include "OS.h"
#include "OSMemory.h"
#include "StrPtrLen.h"
#include "ev.h"

// STATIC DATA

static QTSS_AttributeID	sStateAttr 	= qtssIllegalAttrID;

static StrPtrLen 	sRequestHeader("GET /debug HTTP");

#if MEMORY_DEBUGGING
static char* 		sResponseHeader = "HTTP/1.0 200 OK\r\nServer: TimeShare/1.0\r\nConnection: Close\r\nContent-Type: text/html\r\n\r\n";
static char* 		sResponseEnd = "</BODY></HTML>";
#endif

// FUNCTION PROTOTYPES

QTSS_Error QTSSWebDebugModuleDispatch(QTSS_Role inRole, QTSS_RoleParamPtr inParams);
static QTSS_Error 	Register(QTSS_Register_Params* inParams);
static QTSS_Error 	Filter(QTSS_Filter_Params* inParams);

QTSS_Error QTSSWebDebugModule_Main(void* inPrivateArgs)
{
	return _stublibrary_main(inPrivateArgs, QTSSWebDebugModuleDispatch);
}

QTSS_Error QTSSWebDebugModuleDispatch(QTSS_Role inRole, QTSS_RoleParamPtr inParams)
{
	switch (inRole)
	{
		case QTSS_Register_Role:
			return Register(&inParams->regParams);
		case QTSS_RTSPFilter_Role:
			return Filter(&inParams->rtspFilterParams);
	}
	return QTSS_NoErr;
}

QTSS_Error Register(QTSS_Register_Params* inParams)
{
	// Do role & attribute setup
	(void)QTSS_AddRole(QTSS_RTSPFilter_Role);
	
	// Register an attribute
	static char*		sStateName 			= 	"QTSSWebDebugModuleState";
	(void)QTSS_AddStaticAttribute(qtssRTSPRequestObjectType, sStateName, NULL, qtssAttrDataTypeUInt32);
	(void)QTSS_IDForAttr(qtssRTSPRequestObjectType, sStateName, &sStateAttr);
	
	// Tell the server our name!
	static char* sModuleName = "QTSSWebDebugModule";
	::strcpy(inParams->outModuleName, sModuleName);

	return QTSS_NoErr;
}

QTSS_Error Filter(QTSS_Filter_Params* inParams)
{
	UInt32 theLen = 0;
	char* theFullRequest = NULL;
	(void)QTSS_GetValuePtr(inParams->inRTSPRequest, qtssRTSPReqFullRequest, 0, (void**)&theFullRequest, &theLen);
	
	if ((theFullRequest == NULL) || (theLen < sRequestHeader.Len))
		return QTSS_NoErr;
	if (::memcmp(theFullRequest, sRequestHeader.Ptr, sRequestHeader.Len) != 0)
		return QTSS_NoErr;
		
#if MEMORY_DEBUGGING
	UInt32* theStateVal = NULL;
	(void)QTSS_GetValuePtr(inParams->inRTSPRequest, sStateAttr, 0, (void**)&theStateVal, &theLen);
	//if ((theStateVal == NULL) || (theLen != sizeof(UInt32)))
	//{
		Bool16 theFalse = false;
		(void)QTSS_SetValue(inParams->inRTSPRequest, qtssRTSPReqRespKeepAlive, 0, &theFalse, sizeof(theFalse));

		// Begin writing the HTTP response. We don't need to worry about flow control
		// because we're using the QTSS_RTSPRequestObject for the response, which does buffering
		(void)QTSS_Write(inParams->inRTSPRequest, sResponseHeader, ::strlen(sResponseHeader), &theLen, 0);
		
		//QTSS_EventContextRef* theContext = NULL;
		//(void)QTSS_GetValuePtr(inParams->inRTSPSession, qtssRTSPSesEventCntxt, 0, (void**)&theContext, &theLen);
		//Assert(theContext != NULL);
		//Assert(theLen == sizeof(QTSS_EventContextRef));
		
		//(void)QTSS_RequestEvent(*theContext, EV_WR);
		
	//	UInt32 theValue = 4;
	//	(void)QTSS_SetValue(inParams->inRTSPRequest, sStateAttr, 0, &theValue, sizeof(theValue));
	//	return QTSS_NoErr;
	//}
	
	//we must hold the tagQueue mutex for the duration of this exercise because
	//we don't want any of the values we are reporting to change
	OSMutexLocker locker(OSMemory::GetTagQueueMutex());
	
	//write out header and total allocated memory
	char buffer[1024];
	::sprintf(buffer, "<HTML><TITLE>TimeShare Debug Page</TITLE><BODY>Total dynamic memory allocated: %ld<P>List of objects:<BR>", OSMemory::GetAllocatedMemory());
	(void)QTSS_Write(inParams->inRTSPRequest, buffer, ::strlen(buffer), &theLen, 0);
	
	//now report the list of tags:
	for (OSQueueIter iter(OSMemory::GetTagQueue()); !iter.IsDone(); iter.Next())
	{
		OSMemory::TagElem* elem = (OSMemory::TagElem*)iter.GetCurrent()->GetEnclosingObject();
		Assert(elem != NULL);
		if (elem->numObjects > 0)
		{
			::sprintf(buffer, "Object allocated at: %s, %d. Number of currently allocated objects: %ld, Total size: %ld<BR>", elem->fileName, elem->line, elem->numObjects, elem->totMemory);
			(void)QTSS_Write(inParams->inRTSPRequest, buffer, ::strlen(buffer), &theLen, 0);
		}
	}
	(void)QTSS_Write(inParams->inRTSPRequest, sResponseEnd, ::strlen(sResponseEnd), &theLen, 0);
#endif
	return QTSS_NoErr;
}
