
// 
// Connect to the MySQL database
//
bool clsScene::ConnectToDatabase(void)
{
	// Does this server have access to the database?
	if ( !strcmp(clsServerConfig::getSingleton().DBServerAddress, "") )
	{
		LogDebugMessage(__FUNCTION__, "FATAL: Database information not set!");
		return false;	// Nope
	}

	// yes it does, attempt to connect
	
	LogDebugMessage(__FUNCTION__, "NOTICE: Attempting database connection.");

	// Shutdown our database connection
	if ( mDatabaseConn ) mysql_close( mDatabaseConn );
	mDatabaseConn = NULL;

	mDatabaseConn = mysql_init( (MYSQL*) 0);			// MySQL Init
	
	if ( mDatabaseConn &&							// Connect
		mysql_real_connect( 
			mDatabaseConn,
			clsServerConfig::getSingleton().DBServerAddress,
			clsServerConfig::getSingleton().DBServerLogin,
			clsServerConfig::getSingleton().DBServerAuthCode,
			NULL,
			clsServerConfig::getSingleton().DBServerPortNum,
			NULL,
			0
		) )
	{
		// Default the connection to the correct database/schema.
		if ( mysql_select_db( mDatabaseConn, DB_SCHEMA ) < 0 )
		{
			LogDebugMessage(__FUNCTION__, "CRITICAL! Can't select the database/schema!");
			mysql_close( mDatabaseConn );
			mDatabaseConn = NULL;
			return false;
		} // default database

	} else {
		LogDebugMessage(__FUNCTION__, "CRITICAL! Can't connect to the MySQL server!");
		mysql_close( mDatabaseConn );
		mDatabaseConn = NULL;
		return false;
	} // database connect

	LogDebugMessage(__FUNCTION__, "NOTICE: Database connection successfull.");

	// Set MySQL options;
	mDatabaseConn->reconnect = 1;	// Enable auto reconnect.
	mysql_autocommit( mDatabaseConn, true );

	return true;
} // ConnectToDatabase


//
// Check database connectivity
//
bool clsScene::CheckDatabaseConnectivity(void)
{
	if ( mDatabaseConn )
		if ( mysql_ping( mDatabaseConn ) == 0 ) return true;	// Connection alive

	// If you are here, then something is wrong with our connection.
	LogDebugMessage(__FUNCTION__, "WARNING: Lost database connectivity, reconnecting...");

	// Shutdown our database connection
	if ( mDatabaseConn ) mysql_close( mDatabaseConn );
	mDatabaseConn = NULL;

	// Attempt to re-establish the connection.
	return ConnectToDatabase();
} // CheckDatabaseConnectivity


//
// Check database error
//
void clsScene::CheckDatabaseError(clsRecordSet *RS)
{
	if ( !RS ) return;
	char mMsg[1024];

	sprintf( mMsg, "MySQL Error: %lu: %s", RS->getMySQLErrorNumber(), RS->getMySQLErrorMessage() );
	LogDebugMessage( __FUNCTION__, mMsg );
	
	if ( mDatabaseConn && mysql_info( mDatabaseConn ) )
	{
		sprintf( mMsg, "MySQL Info: %s", mysql_info( mDatabaseConn ) );
		LogDebugMessage( __FUNCTION__, mMsg );
	}

	// Generate MySQL debug trace
	sprintf( mMsg, "d:t:O,mysql.trace.%lu.txt", mCurrentTS );
	mysql_debug( mMsg );
	sprintf( mMsg, "NOTICE: Generated MySQL trace file: %lu", mCurrentTS );
	LogDebugMessage( __FUNCTION__, mMsg );


	switch ( RS->getMySQLErrorNumber() )
	{
		case CR_INVALID_CONN_HANDLE:
		case CR_SERVER_LOST:
			mDatabaseConn = NULL;	// Will force a reconnect!
			CheckDatabaseConnectivity();
			break;

		default:
			break;
	} // switch

} // CheckDatabaseError






/*****************************************************************************
It is VERY VERY VERY VERY important that when saving inventory items
to the database from this service that you ONLY update
the ContInvKey, Quadrant, Sector, and Position data.
because OTHER Services (namely clsInventoryServices) is ALSO updating
the Inventory table!
/****************************************************************************/
bool clsScene::saveInventory(clsInventory *Inventory)
{
	unsigned int mRecordCount=0;
	char mSQL[clsRecordSet::SQLStatementSize], mTemp[1024];
	const char *p=NULL;
	clsRecordSet mInvRS;
	Ogre::Vector3 mQuadrant( Ogre::Vector3::ZERO ), mSector( Ogre::Vector3::ZERO );

	if ( !Inventory ) return false;
	if ( !mDatabaseConn ) return false;

	mQuadrant = Ogre::Vector3( mThisService->QuadrantX, mThisService->QuadrantY, mThisService->QuadrantZ );
	mSector = Ogre::Vector3( mThisService->SectorX, mThisService->SectorY, mThisService->SectorZ );

	clsObjectType::ObjectTypes mOT = Inventory->getObjectType();

	// Do not save quadrant level inventory items!
	if ( mOT > clsObjectType::ObjectTypes::OTI_QUAD_BEGIN
		&& mOT < clsObjectType::ObjectTypes::OTI_QUAD_END )
	{
		sprintf( mTemp, "ERROR: Inventory %lu. Attempting to save a QUADRANT level item.",
			Inventory->getInventoryKey() );
		LogDebugMessage( __FUNCTION__, mTemp );
		return false;
	} // Quadrant level

	// Do not save items not in this sector!
	if ( Inventory->getInventoryQuadrant() != mQuadrant
		|| Inventory->getInventorySector() != mSector )
	{
		sprintf( mTemp, "ERROR: Inventory %lu. Attempting to save an item not in this Quad/Sector.",
			Inventory->getInventoryKey() );
		LogDebugMessage( __FUNCTION__, mTemp );
		return false;
	} // Quad/Sect?


	// Set the Database connection
	mInvRS.setDBConnection( mDatabaseConn );

	// Build SQL Query string
	strcpy( mSQL, "UPDATE Inventory SET " );

	sprintf( mTemp, "ContInvKey=%lu", Inventory->getInventoryContKey() );
	strcat( mSQL, mTemp );

	sprintf( mTemp, ", ContAs=%lu", Inventory->getInventoryContAs() );
	strcat( mSQL, mTemp );

	// We use "mThisService" data so we can't be spoofed.
	sprintf( mTemp, ", QuadrantX=%.0f", mThisService->QuadrantX );
	strcat( mSQL, mTemp );
	sprintf( mTemp, ", QuadrantY=%.0f", mThisService->QuadrantY );
	strcat( mSQL, mTemp );
	sprintf( mTemp, ", QuadrantZ=%.0f", mThisService->QuadrantZ );
	strcat( mSQL, mTemp );

	// We use "mThisService" data so we can't be spoofed.
	sprintf( mTemp, ", SectorX=%.0f", mThisService->SectorX );
	strcat( mSQL, mTemp );
	sprintf( mTemp, ", SectorY=%.0f", mThisService->SectorY );
	strcat( mSQL, mTemp );
	sprintf( mTemp, ", SectorZ=%.0f", mThisService->SectorZ );
	strcat( mSQL, mTemp );

	sprintf( mTemp, ", PositionX=%.3f", Inventory->getInventoryPosition().x );
	strcat( mSQL, mTemp );
	sprintf( mTemp, ", PositionY=%.3f", Inventory->getInventoryPosition().y );
	strcat( mSQL, mTemp );
	sprintf( mTemp, ", PositionZ=%.3f", Inventory->getInventoryPosition().z );
	strcat( mSQL, mTemp );

	sprintf( mTemp, ", OrientationW=%.3f", Inventory->getInventoryOrientation().w );
	strcat( mSQL, mTemp );
	sprintf( mTemp, ", OrientationX=%.3f", Inventory->getInventoryOrientation().x );
	strcat( mSQL, mTemp );
	sprintf( mTemp, ", OrientationY=%.3f", Inventory->getInventoryOrientation().y );
	strcat( mSQL, mTemp );
	sprintf( mTemp, ", OrientationZ=%.3f", Inventory->getInventoryOrientation().z );
	strcat( mSQL, mTemp );

	strcat( mSQL, ", RecLastModified=NULL" );

	sprintf( mTemp, " WHERE InventoryKey=%lu", Inventory->getInventoryKey() );
	strcat( mSQL, mTemp );
	
	// Set the SQL Query command
	mInvRS.setSQLQuery( mSQL );
	
	// Execute the SQL Query command
	if ( !mInvRS.executeSQLQuery() )
	{
		sprintf( mTemp, "ERROR: Inventory %lu. SQL UPDATE 'Query' failed!", Inventory->getInventoryKey() );
		LogDebugMessage( __FUNCTION__, mTemp );
		LogDebugMessage( __FUNCTION__, mSQL );
		CheckDatabaseError( &mInvRS );
		return false;
	}

	if ( mInvRS.getNumberOfAffectedRows() < 1 )
	{
		sprintf( mTemp, "ERROR: Inventory %lu. SQL UPDATE did not affect any rows!", Inventory->getInventoryKey() );
		LogDebugMessage( __FUNCTION__, mTemp );
		LogDebugMessage( __FUNCTION__, mSQL );
		CheckDatabaseError( &mInvRS );
		return false;
	}

	// TODO: Update Inventory Properties?

	return true;

} // saveInventory

