/*
 *
 * @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:		QTSSPosixFileSysModule.cpp

	Contains:	Implements web stats module

	Written By: Denis Serenyi

	$Log: QTSSPosixFileSysModule.cpp,v $
	Revision 1.10  2001/10/18 02:00:53  lecroy
	removed "pragma mark"s
	Bug #:
	Submitted by:
	Reviewed by:
	
	Revision 1.9  2001/10/18 01:45:32  lecroy
	fixed my big screw up when trying to remove pragma mark's
	Bug #:
	Submitted by:
	Reviewed by:
	
	Revision 1.7  2001/08/02 19:09:03  murata
	Fix bad ModuleUtils initialize calls with bad parameter.
	Bug #:
	Submitted by:
	Reviewed by:
	
	Revision 1.6  2001/03/13 22:24:06  murata
	Replace copyright notice for license 1.0 with license 1.2 and update the copyright year.
	Bug #:
	Submitted by:
	Reviewed by:
	
	Revision 1.5  2000/10/11 07:26:58  serenyi
	import
	
	Revision 1.2  2000/09/25 22:28:59  serenyi
	Got rid of permissions argument to QTSS_Add***Attribute
	
	Revision 1.1.1.1  2000/08/31 00:30:24  serenyi
	Mothra Repository
	
	Revision 1.4  2000/07/16 23:50:17  serenyi
	Module changes to reflect new QTSS_TimeVal type
	
	Revision 1.3  2000/06/19 22:23:32  serenyi
	Updated to new QTSS_AddStaticAttribute API, updated prefs object SetValue to write to the config file
	
	Revision 1.2  2000/06/02 06:58:30  serenyi
	First checkin of module dictionaries
	
	Revision 1.1  2000/05/22 04:37:44  serenyi
	Created
	

*/

#include "QTSSPosixFileSysModule.h"
#include "QTSSModuleUtils.h"

#include "OSMemory.h"
#include "OSFileSource.h"
#include "Socket.h"

// ATTRIBUTES
static QTSS_AttributeID			sOSFileSourceAttr = qtssIllegalAttrID;
static QTSS_AttributeID			sEventContextAttr = qtssIllegalAttrID;

// FUNCTION PROTOTYPES

static QTSS_Error 	QTSSPosixFileSysModuleDispatch(QTSS_Role inRole, QTSS_RoleParamPtr inParams);
static QTSS_Error	Register(QTSS_Register_Params* inParams);
static QTSS_Error	Initialize(QTSS_Initialize_Params* inParams);
static QTSS_Error	OpenFile(QTSS_OpenFile_Params* inParams);
static QTSS_Error	AdviseFile(QTSS_AdviseFile_Params* inParams);
static QTSS_Error	ReadFile(QTSS_ReadFile_Params* inParams);
static QTSS_Error	CloseFile(QTSS_CloseFile_Params* inParams);
static QTSS_Error	RequestEventFile(QTSS_RequestEventFile_Params* inParams);

// FUNCTION IMPLEMENTATIONS

QTSS_Error QTSSPosixFileSysModule_Main(void* inPrivateArgs)
{
	return _stublibrary_main(inPrivateArgs, QTSSPosixFileSysModuleDispatch);
}


QTSS_Error 	QTSSPosixFileSysModuleDispatch(QTSS_Role inRole, QTSS_RoleParamPtr inParams)
{
	switch (inRole)
	{
		case QTSS_Register_Role:
			return Register(&inParams->regParams);
		case QTSS_Initialize_Role:
			return Initialize(&inParams->initParams);
		case QTSS_OpenFile_Role:
			return OpenFile(&inParams->openFileParams);
		case QTSS_AdviseFile_Role:
			return AdviseFile(&inParams->adviseFileParams);
		case QTSS_ReadFile_Role:
			return ReadFile(&inParams->readFileParams);
		case QTSS_CloseFile_Role:
			return CloseFile(&inParams->closeFileParams);
		case QTSS_RequestEventFile_Role:
			return RequestEventFile(&inParams->reqEventFileParams);
	}
	return QTSS_NoErr;
}


QTSS_Error Register(QTSS_Register_Params* inParams)
{
	// Do role & attribute setup
	(void)QTSS_AddRole(QTSS_Initialize_Role);
	
	// Only open needs to be registered for, the rest happen naturally
	(void)QTSS_AddRole(QTSS_OpenFile_Role);

	// Add an attribute to the file object type to store a pointer to our OSFileSource	
	static char*		sOSFileSourceName	= "QTSSPosixFileSysModuleOSFileSource";
	(void)QTSS_AddStaticAttribute(qtssFileObjectType, sOSFileSourceName, NULL, qtssAttrDataTypeVoidPointer);
	(void)QTSS_IDForAttr(qtssFileObjectType, sOSFileSourceName, &sOSFileSourceAttr);

	static char*		sEventContextName	= "QTSSPosixFileSysModuleEventContext";
	(void)QTSS_AddStaticAttribute(qtssFileObjectType, sEventContextName, NULL, qtssAttrDataTypeVoidPointer);
	(void)QTSS_IDForAttr(qtssFileObjectType, sEventContextName, &sEventContextAttr);
	
	// Tell the server our name!
	static char* sModuleName = "QTSSPosixFileSysModule";
	::strcpy(inParams->outModuleName, sModuleName);

	return QTSS_NoErr;
}

QTSS_Error Initialize(QTSS_Initialize_Params* inParams)
{
	// Setup module utils
	QTSSModuleUtils::Initialize(inParams->inMessages, inParams->inServer, inParams->inErrorLogStream);
	return QTSS_NoErr;
}

QTSS_Error	OpenFile(QTSS_OpenFile_Params* inParams)
{
	OSFileSource* theFileSource = NEW OSFileSource(inParams->inPath);

	UInt64 theLength = theFileSource->GetLength();
	
	//
	// OSFileSource returns mod date as a time_t.
	// This is the same as a QTSS_TimeVal, except the latter is in msec
	QTSS_TimeVal theModDate = (QTSS_TimeVal)theFileSource->GetModDate();
	theModDate *= 1000;
	
	//
	// Check to see if the file actually exists
	if (theLength == 0)
	{
		delete theFileSource;
		return QTSS_FileNotFound;
	}
	
	//
	// Add this new file source object to the file object
	QTSS_Error theErr = QTSS_SetValue(inParams->inFileObject, sOSFileSourceAttr, 0, &theFileSource, sizeof(theFileSource));
	if (theErr != QTSS_NoErr)
	{
		delete theFileSource;
		return QTSS_RequestFailed;
	}

	//
	// If caller wants async I/O, at this point we should set up the EventContext
	if (inParams->inFlags & qtssOpenFileAsync)
	{
		EventContext* theEventContext = NEW EventContext(EventContext::kInvalidFileDesc, Socket::GetEventThread());
		theEventContext->InitNonBlocking(theFileSource->GetFD());
		
		theErr = QTSS_SetValue(inParams->inFileObject, sEventContextAttr, 0, &theEventContext, sizeof(theEventContext));
		if (theErr != QTSS_NoErr)
		{
			delete theFileSource;
			delete theEventContext;
			return QTSS_RequestFailed;
		}
	}
	
	//
	// Set up the other attribute values in the file object
	(void)QTSS_SetValue(inParams->inFileObject, qtssFlObjLength, 0, &theLength, sizeof(theLength));
	(void)QTSS_SetValue(inParams->inFileObject, qtssFlObjModDate, 0, &theModDate, sizeof(theModDate));

	return QTSS_NoErr;
}

QTSS_Error	AdviseFile(QTSS_AdviseFile_Params* inParams)
{
	OSFileSource** theFile = NULL;
	UInt32 theLen = 0;
	
	(void)QTSS_GetValuePtr(inParams->inFileObject, sOSFileSourceAttr, 0, (void**)&theFile, &theLen);
	Assert(theLen == sizeof(OSFileSource*));
	(*theFile)->Advise(inParams->inPosition, inParams->inSize);
		
	return QTSS_NoErr;
}

QTSS_Error	ReadFile(QTSS_ReadFile_Params* inParams)
{
	OSFileSource** theFile = NULL;
	UInt32 theLen = 0;
	
	(void)QTSS_GetValuePtr(inParams->inFileObject, sOSFileSourceAttr, 0, (void**)&theFile, &theLen);
	Assert(theLen == sizeof(OSFileSource*));
	OS_Error osErr = (*theFile)->Read(inParams->inFilePosition, inParams->ioBuffer, inParams->inBufLen, inParams->outLenRead);

	if (osErr == EAGAIN)
		return QTSS_WouldBlock;
	else if (osErr != OS_NoErr)
		return QTSS_RequestFailed;
	else
		return QTSS_NoErr;
}

QTSS_Error	CloseFile(QTSS_CloseFile_Params* inParams)
{
	OSFileSource** theFile = NULL;
	EventContext** theContext = NULL;
	UInt32 theLen = 0;
	
	QTSS_Error theErr = QTSS_GetValuePtr(inParams->inFileObject, sOSFileSourceAttr, 0, (void**)&theFile, &theLen);
	Assert(theErr == QTSS_NoErr);
	theErr = QTSS_GetValuePtr(inParams->inFileObject, sEventContextAttr, 0, (void**)&theContext, &theLen);
	
	if (theErr == QTSS_NoErr)
	{
		//
		// If this file was opened up in async mode, there is an EventContext associated with it.
		// We should first make sure that the OSFileSource destructor doesn't close the FD
		// (the EventContext will do it), then close the EventContext
		(*theFile)->ResetFD();
		delete *theContext;
	}
	delete *theFile;
	return QTSS_NoErr;
}

QTSS_Error	RequestEventFile(QTSS_RequestEventFile_Params* inParams)
{
	QTSS_ModuleState* theState = (QTSS_ModuleState*)OSThread::GetMainThreadData();
	if (OSThread::GetCurrent() != NULL)
		theState = (QTSS_ModuleState*)OSThread::GetCurrent()->GetThreadData();

	Assert(theState->curTask != NULL);
	
	EventContext** theContext = NULL;
	UInt32 theLen = 0;
	
	QTSS_Error theErr = QTSS_GetValuePtr(inParams->inFileObject, sEventContextAttr, 0, (void**)&theContext, &theLen);
	if (theErr == QTSS_NoErr)
	{
		//
		// This call only works if the file is async!
		(*theContext)->SetTask(theState->curTask);
		(*theContext)->RequestEvent();
		
		return QTSS_NoErr;
	}
	return QTSS_RequestFailed;
}
