/*
	File:	Database.10.1.cpp

	Contains: Misc Database routines.

	Copyright:	© 2003 by Apple Computer, Inc., all rights reserved.

 	NOT_FOR_OPEN_SOURCE <to be reevaluated at a later time>

	Change History:
 */

// Sys
#include <sys/stat.h>

// Application
#include "AppResources.h"

// Database
#include "Database.10.1.h"

// Utilities
//#include "cpstrings.h"
#include "COSUtils.h"

// Persistent Objects
#include "CAccount.10.1.h"
#include "CMailSpool.10.1.h"
#include "CEnvelopeInfo.10.1.h"
#include "CEnvelope.10.1.h"
#include "CMessagePart.10.1.h"
#include "CSmallMsgPart.10.1.h"
#include "CMailDatabase.10.1.h"
#include "CRootObject.10.1.h"
#include "CServerPrefs.10.1.h"
#include "CExpansion.10.1.h"
#include "CTextObject.10.1.h"
#include "CUtils.h"
#include "MailTypes.h"
#include "CGlobals.h"

const uInt32	kStandardMinFreeDiskSpace_10_1 = 2 * 1024;

// ---------------------------------------------------------------------------
//	* Globals
// ---------------------------------------------------------------------------

CMailDatabase_10_1		*gDB_10_1 = NULL;

// ---------------------------------------------------------------------------
//	* ValidateMailDB_10_1 ()
//
// ---------------------------------------------------------------------------

sInt32 ValidateMailDB_10_1 ( const char *inDBPath )
{
	sInt32						siResult	= kFnfErr;	
	CFile						*dbFile		= nil;
	const char					*pPath		= nil;
	long						byteCount	= sizeof( SDatabaseHeaderData_10_1 );
	struct stat					statbuf;
	SDatabaseHeaderData_10_1	dbHeader;

	try
	{
		pPath = inDBPath;

		// check if the directory already exists
		siResult = ::stat( pPath, &statbuf );
		if ( siResult == 0 )
		{
			dbFile = new CFile( pPath, false, false );
			if ( dbFile != nil )
			{
				dbFile->seekg( 0 );
				dbFile->Read( &dbHeader, byteCount );

				siResult = kDBNotSafe;

				if ( (dbHeader.fDBState == kDBClosed_10_1) ||
					((dbHeader.fDBState == kDBOpen_10_1) && (dbHeader.fDBReOpenState == kDBSafe_10_1)) )
				{
					siResult = kDBSafe;
				}
		
				delete( dbFile );
				dbFile = nil;
			}
		}
	}

	catch ( int err )
	{
		siResult = err;

		if ( dbFile != nil )
		{
			delete( dbFile );
			dbFile = nil;
		}
	}

	return( siResult );

} // ValidateMailDB_10_1


// ---------------------------------------------------------------------------
//	* CheckDBVersion_10_1 ()
//
// ---------------------------------------------------------------------------

sInt32 CheckDBVersion_10_1 ( const char *inDBPath, eDBVers_10_1 *outDBVer )
{
	sInt32						siResult	= kFnfErr;	
	CFile						*dbFile		= nil;
	const char					*pPath		= nil;
	long						byteCount	= sizeof( SDatabaseHeaderData_10_1 );
	struct stat					statbuf;
	SDatabaseHeaderData_10_1	dbHeader;

	try
	{
		pPath = inDBPath;

		// check if the file already exists
		siResult = ::stat( pPath, &statbuf );
		if ( siResult == 0 )
		{
			dbFile = new CFile( pPath, false, false );
			if ( dbFile != nil )
			{
				dbFile->seekg( 0 );
				dbFile->Read( &dbHeader, byteCount );
		
				if ( ::strncmp( dbHeader.fDatabaseTag, kASIP6xDBTag, CUtils::Strlen( kASIP6xDBTag ) ) == 0 )
				{
					*outDBVer = kDBVer6_X_10_1;
				}
				else if ( ::strncmp( dbHeader.fDatabaseTag, kOSX10_0DBTag, CUtils::Strlen( kOSX10_0DBTag ) ) == 0 )
				{
					*outDBVer = kDBVer10_0_10_1;
				}
				else if ( ::strncmp( dbHeader.fDatabaseTag, kCurrentDBTag, CUtils::Strlen( kOSX10_1DBTag ) ) == 0 )
				{
					*outDBVer = kDBVer10_1_10_1;
				}
				else if ( ::strncmp( dbHeader.fDatabaseTag, kCurrentDBTag, CUtils::Strlen( kCurrentDBTag ) ) == 0 )
				{
					*outDBVer = kDBCurrent_10_1;
				}
				else
				{
					*outDBVer = kDBVerUnknown_10_1;
				}

				siResult = kNoErr;

				delete( dbFile );
				dbFile = nil;
			}
		}
	}

	catch ( int err )
	{
		siResult = err;

		if ( dbFile != nil )
		{
			delete( dbFile );
			dbFile = nil;
		}
	}

	return( siResult );

} // CheckDBVersion_10_1


// ---------------------------------------------------------------------------
//	* InitializeMainDB ()
//
// ---------------------------------------------------------------------------

Boolean InitializeMainDB_10_1 ( const char *inDBPath, uInt32 &outDBFlags )
{
	OSErr					aDBErr				= kNoErr;
	uInt32					anErrorCount		= 0;
	uInt32					pageCount			= 2048;		// xxx what size do we want the DBCache??
	CDBMailObjectCache_10_1	*pDBMailObjectCache	= nil;
	CString					csDBName( 128 );

	pDBMailObjectCache = new CDBMailObjectCache_10_1;
	gDB_10_1 = new CMailDatabase_10_1( kStandardMinFreeDiskSpace_10_1, pDBMailObjectCache, pageCount );

	if ( gDB_10_1 != nil )
	{
		csDBName.Set( inDBPath );

		const char *theDBFileSpec = csDBName.GetData();

		// Tell the database to use the file spec
		aDBErr = gDB_10_1->OpenDatabaseFile( (CFileSpecPtr)theDBFileSpec, kServerDataFileType, kServerAppSignature, false );
		if ( aDBErr != kNoErr )
		{
			if ( aDBErr == kFnfErr )
			{
				aDBErr = CanCreateDB_10_1();
				if ( aDBErr == kNoErr )
				{
					aDBErr = gDB_10_1->OpenDatabaseFile( (CFileSpecPtr)theDBFileSpec, kServerDataFileType, kServerAppSignature, true );
				}
			}

			::chmod( theDBFileSpec, 0100600 );	// Change permissions to -rw-------
			if ( aDBErr == kNoErr )
			{			
				outDBFlags |= kNewDBCreated_10_1;
			}
			else
			{
				if ( aDBErr == CMailDatabase_10_1::kDBWrongVersion )
				{
					outDBFlags |= kWrongDBVersion_10_1;
				}
				else if ( aDBErr == CMailDatabase_10_1::kDBNotClosedProperly )
				{
					// Database may be bad
					outDBFlags |= kPoorlyClosedDB_10_1;
					aDBErr = kNoErr;
				}
				else if ( aDBErr == CMailDatabase_10_1::kDBCanNotOpen )
				{
					outDBFlags |= kCantOpenDB_10_1;
				}
				else if ( aDBErr == CMailDatabase_10_1::kDBDiskFull )
				{
				}
			}
		}
		else
		{
			::chmod( theDBFileSpec, 0100600 );	// Change permissions to -rw-------
			outDBFlags |= kDBIsOK_10_1;
		}

		if ( aDBErr == kNoErr )
		{
			aDBErr = gDB_10_1->AddObjType( kMailRootSignature_10_1,		kCRootObjectDataSize_10_1,		false,	CRootObject_10_1::GetSetFields );
			if (aDBErr != kNoErr)
			{
				anErrorCount++;
			}

			aDBErr = gDB_10_1->AddObjType( kAccountSignature_10_1,			kAccountDataSize_10_1,			false,	CAccount_10_1::GetSetFields );
			if (aDBErr != kNoErr)
			{
				anErrorCount++;
			}

			aDBErr = gDB_10_1->AddObjType( kMailSpoolSignature_10_1,		kMailSpoolDataSize_10_1,			false,	CMailSpool_10_1::GetSetFields );
			if (aDBErr != kNoErr)
			{
				anErrorCount++;
			}

			aDBErr = gDB_10_1->AddObjType( kEnvelopeInfoSignature_10_1,	kEnvelopeInfoDataSize_10_1,		false,	CEnvelopeInfo_10_1::GetSetFields );
			if (aDBErr != kNoErr)
			{
				anErrorCount++;
			}

			aDBErr = gDB_10_1->AddObjType( kEnvelopeSignature_10_1,		kEnvelopeDataSize_10_1,			false,	CEnvelope_10_1::GetSetFields );
			if (aDBErr != kNoErr)
			{
				anErrorCount++;
			}

//			aDBErr = gDB_10_1->AddObjType( kRecipientSignature_10_1,		kRecipientDataSize_10_1,			false,	CRecipient_10_1::GetSetFields );
//			if (aDBErr != kNoErr)
//			{
//				anErrorCount++;
//			}

			aDBErr = gDB_10_1->AddObjType( kMessagePartSignature_10_1,		kMessagePartFixedDataSize_10_1,	false,	CMessagePart_10_1::GetSetFields );
			if (aDBErr != kNoErr)
			{
				anErrorCount++;
			}

			aDBErr = gDB_10_1->AddObjType( KSmallMsgPartSignature_10_1,	kSmallMsgPartFixedDataSize_10_1,	false,	CSmallMsgPart_10_1::GetSetFields );
			if (aDBErr != kNoErr)
			{
				anErrorCount++;
			}

//			aDBErr = gDB_10_1->AddObjType( kHostEntrySignature_10_1,		kHostEntryDataSize_10_1,			false,	CHostEntry_10_1::GetSetFields );
//			if (aDBErr != kNoErr)
//			{
//				anErrorCount++;
//			}

//			aDBErr = gDB_10_1->AddObjType( kStatMgrSignature_10_1,			kStatMgrDataSize_10_1,			false,	CStatMgr_10_1::GetSetFields );
//			if (aDBErr != kNoErr)
//			{
//				anErrorCount++;
//			}

//			aDBErr = gDB_10_1->AddObjType( kMsgTOCSignature_10_1,			kMsgTOCDataSize_10_1,			false,	CMessageTOC_10_1::GetSetFields );
//			if (aDBErr != kNoErr)
//			{
//				anErrorCount++;
//			}

//			aDBErr = gDB_10_1->AddObjType( kHostPrefSignature_10_1,		kHostEntryPrefDataSize_10_1,		false,	CHostEntryPref_10_1::GetSetFields );
//			if (aDBErr != kNoErr)
//			{
//				anErrorCount++;
//			}

			aDBErr = gDB_10_1->AddObjType( kServerPrefsSignature_10_1,		kServerPrefsDataSize_10_1,		false,	CServerPrefs_10_1::GetSetFields );
			if (aDBErr != kNoErr)
			{
				anErrorCount++;
			}

//			aDBErr = gDB_10_1->AddObjType( kDNSCacheSignature_10_1,		kCMXRecordSize_10_1,				false,	CMXRecords_10_1::GetSetFields );
//			if (aDBErr != kNoErr)
//			{
//				anErrorCount++;
//			}

			aDBErr = gDB_10_1->AddObjType( kExpansionSignature_10_1,		kExpansionDataSize_10_1,			false,	CExpansion_10_1::GetSetFields );
			if (aDBErr != kNoErr)
			{
				anErrorCount++;
			}

//			aDBErr = gDB_10_1->AddObjType( kPOP3AcctInfoSignature_10_1,	kCPOP3AcctInfoDataSize_10_1,		false,	CPOP3AcctInfo_10_1::GetSetFields );
//			if (aDBErr != kNoErr)
//			{
//				anErrorCount++;
//			}

//			aDBErr = gDB_10_1->AddObjType( kMessageStringSignature_10_1,	kMessageStringDataSize_10_1,		false,	CMessageString_10_1::GetSetFields );
//			if (aDBErr != kNoErr)
//			{
//				anErrorCount++;
//			}

			aDBErr = gDB_10_1->AddObjType( kTextObjectSignature_10_1,		kTextObjectDataSize_10_1,		false,	CTextObject_10_1::GetSetFields );
			if (aDBErr != kNoErr)
			{
				anErrorCount++;
			}
		}
		// it is very important that we do this _AFTER_ all the database types are registered because
		// the cache interrogates the database to find out what the types are in order to set up
		// a hash table and one cache list per database type.
		pDBMailObjectCache->SetBaseDBPtr(gDB_10_1);

		// create version information here!!!
		
		return( (aDBErr == kNoErr ) && (anErrorCount == 0) );
	}

	return( false );

} // InitializeMainDB

// ---------------------------------------------------------------------------
//	* CloseMainDB ()
//
//		- Close, & compress the DB. Delete the memory object.
// ---------------------------------------------------------------------------

void CloseMainDB_10_1 ( void )
{
	const uTime_t	kExitTime = (uTime_t)::time( nil ) + 15;	// 15 seconds..
	if ( gDB_10_1 != NULL )
	{
		CDBMailObjectCache_10_1	*aDBMailObjectCache = (CDBMailObjectCache_10_1 *)gDB_10_1->GetBaseObjectCachePtr();

		aDBMailObjectCache->FlushAllList( true );

		while ( (aDBMailObjectCache->CalcObjectCount() != 0) && (kExitTime > (uTime_t)::time( nil )) )
		{
			aDBMailObjectCache->FlushAllList( true );
		}

		gDB_10_1->CloseDatabaseFile();

		delete( gDB_10_1 );
		gDB_10_1 = NULL;

		delete( aDBMailObjectCache );
		aDBMailObjectCache = NULL;
	}
} // CloseMainDB


// ---------------------------------------------------------------------------
//	* GetDiskFreeSpace ()
//
// ---------------------------------------------------------------------------

void GetDiskFreeSpace_10_1 ( long long &volFree )
{
	volFree = COSUtils::GetFileSystemFreeSpace( COSUtils::GetDBFolder() );
} // GetDiskFreeSpace


// ---------------------------------------------------------------------------
//	* CanCreateDB ()
//
// ---------------------------------------------------------------------------

OSErr CanCreateDB_10_1 ( void )
{
	OSErr		result		= kNoErr;
	long long	freeSpace	= 0;
	long		minFree		= 0;

	GetDiskFreeSpace_10_1( freeSpace );

//	minFree = CMailService::GetMinFreeDiskSpaceKB() * 1024;
	minFree = kFreeDiskSpaceKB * 1024;

	freeSpace -= minFree;

	if ( freeSpace < (512 * 1024) )
	{
		result = CMailDatabase_10_1::kDBDiskFull;
	}

	return( result );

} // CanCreateDB



// ---------------------------------------------------------------------------
//	* IsDBFull
//
// ---------------------------------------------------------------------------

Boolean IsDBFull_10_1 ( void )
{
	Boolean		result		= false;
	return( result );
} // IsDBFull











