// Author : Chris Tolley
// Date   : 7/21/2004
// SurvivalEngine.cpp contains the class definition for the engine that will
// drive Survival

#pragma warning ( disable : 4305 )
#pragma warning ( disable : 4786 )

#include "SurvivalEngine.h"
#include <gl/gl.h>
#include <gl/glu.h>
#include <time.h>
#include <string>
#include <vector>
#include <stack>
#include <map>

using namespace std;

#include "logger.h"
#include "InputSystem.h"
#include "quadTreeTerrain.h"
#include "viewFrustum.h"
#include "Plant.h"
#include "WaterPool.h"
#include "Bug.h"
#include "ScreenWriter.h"
#include "carcus.h"
#include "HiResTimer.h"

// Some constants to help organize things
// The size of the quad tree that the terrain is based off of.  Must 2^n + 1
const int    QUAD_SIZE         = 129;
// The size of the texture to be generated for the terrain.  Must 2^n
const int    QUAD_TEXTURE_SIZE = 1024;
// The file where the height map is found
const string TERRAIN_FILE      = "images/flat.raw";
// Used in rendering the terrain.  It's level of detail
const int	 TERRAIN_DETAIL    = 6;
// The height scale used with on the terrain
const double TERRAIN_SCALE	   = .05;
// The name of the player controlled bug
const string PLAYER			   = "player";
// The name of the computer controlled bug
const string COMP			   = "comp";
// The base fertility rate
const int    BASE_FERTILITY	   = 30;
// The max fertility rate
const int	 MAX_FERTILITY	   = BUG_LIFETIME;
// The max number of bugs that there can be
const int	 MAX_BUGS		   = 200;
// The player bug model file
const char*  PLAYER_MODEL	   = "models/Turtle.ms3d";
// The computer bug model file
const char*  COMPUTER_MODEL	   = "models/Bug.ms3d";

// Default Constructor
SurvivalEngine::SurvivalEngine() 
: m_qtObjectMap( QUAD_SIZE - 1 ), m_iFertilityRate( 1 ), m_iFPS( 0 ),
  m_bPaused( false ), m_bSpaceDown( false ), m_gsStatus( GAME_ON )
{
}// End SurvivalEngine::Constructor


// Destructor
SurvivalEngine::~SurvivalEngine()
{
	// Delete the quadTree if it exists
	if( m_qtTerrain )
	{
		delete m_qtTerrain;
		// Log the status of deleting the terrain
		logger::event( "SurvivalEngine::Destructor", 
					   "Successfully deleted the terrain.", 0 );
	}// End if
}// End SurvivalEngine::Destructor


// Initializes all the engine variables.  Returns true if successful
bool SurvivalEngine::Initialize( HWND hwnd, HINSTANCE hInstance, 
								 CInputSystem* input, HiResTimer* timer )
{
	// Seed the random number generator
	srand( time( NULL ) );

	// Set up the input system
	m_Input = input;

	// Point to the timer
	m_Timer = timer;

	// Create the quadTree
	m_qtTerrain = 
		new quadTreeTerrain( QUAD_SIZE, TERRAIN_FILE.c_str(), 
							 QUAD_TEXTURE_SIZE, TERRAIN_SCALE );

	logger::event( "SurvivalEngine::Initialize",
				   "Terrain created successfully.", 0 );

	// Initialize the Survival camera
	m_scCamera.Initialize( m_Input, m_qtTerrain );

	// Initialize the Plants, WaterPools, and Bugs
	Plant::InitList( "models/Mushroom.ms3d", this );
	WaterPool::Initialize( m_qtTerrain, "images/water.bmp" );
	Bug::InitializeList( this, m_qtTerrain, &m_qtObjectMap );


	// Initialize the object map ( quad tree )
	m_qtObjectMap.Initialize( QUAD_SIZE - 1, 0, QUAD_SIZE - 1, 0 );

	// Initialize the camera
	m_bcCamera.Initialize( m_Input, m_qtTerrain, &m_qtObjectMap, this, 
						   "player" );

	// Log that the camera was initialized successfully
	logger::event( "SurvivalEngine::Initialize", "Camera initiailized", 0 );

	// Initialize the map that stores the bugs
	m_mapBugs.insert( make_pair< string, vector< SmartPointer > >
								( PLAYER, vector< SmartPointer >() ) );
	m_mapBugs.insert( make_pair< string, vector< SmartPointer > >
								( COMP,   vector< SmartPointer >() ) );

	// Create some WaterPools
	for( int n = 0; n < 8; ++n )
	{
		SmartPointer water( new WaterPool
					( rand() % QUAD_SIZE, rand() % QUAD_SIZE, 3 ) );

		m_vecWaterPools.push_back( water );
		m_qtObjectMap.Insert( water );
	}// End for n

	// Return true if we reached this point.
	return true;
}// End SurvivalEngine::Initialize


// Prepares everything for a game
void SurvivalEngine::SetupGame( enum EngineState state )
{
	// Set the current state of the engine
	m_esState = state;

	// The for loop variable
	int n = 0;
	// The map for loop variable
	map< string, vector< SmartPointer > >::iterator it;

	// A SmartPointer to a bug
	SmartPointer bug;

	// Set up the game status
	m_gsStatus = GAME_ON;

	// Set up the game based on the state
	switch( m_esState )
	{
	case PLAY:
		// Create a bug for the camera
		bug = SmartPointer( new Bug( 0, 0, PLAYER_MODEL, PLAYER ) );

		// Rotate the bug so it starts facing up and down down
		bug->Rotate( 0, 180, 0 );

		// Set the camera to this bug
		m_bcCamera.SetFocus( bug );

		// Create the plants
		for( n = 0; n < 10; ++n )
		{
			// Get a random position for the new plant
			float x = rand() % QUAD_SIZE;
			float z = rand() % QUAD_SIZE;

			// Create the plants
			SmartPointer plant( 
						new Plant( x, m_qtTerrain->GetHeightAt( x, z ), z ) );

			// Add the new plant to the quadtree and to the vector that holds 
			// all plants
			m_vPlants.push_back( plant );
			m_qtObjectMap.Insert( plant );
		}// End for n

		// Get the place to store computer bugs
		it = m_mapBugs.find( COMP );

		// Create threshold values for the new bug
		ThresholdValues tv;
		tv.Drink_     = 128;
		tv.Eat_       = 128;
		tv.Fight_     = 200;
		tv.Reproduce_ = 30;
		tv.Rest_	  = 30;

		// Create a patrol path for the new bug
		PatrolPath pp;
		for( n = 0; n < PATROL_PATH_LENGTH; ++n )
		{
			pp.Path_[n] = rand() % 256;
		}// End for n

		// Create the new bug
		bug = SmartPointer( new Bug( COMP, Gene( tv, pp ), 
							  COMPUTER_MODEL, QUAD_SIZE - 1, QUAD_SIZE - 1 ) );

		// Add the bug to the 
		m_mapBugs.find( COMP )->second.push_back( bug );

		break;
	case OBSERVE:
		// Create the plants
		for( n = 0; n < 10; ++n )
		{
			// Get a random position for the new plant
			float x = rand() % QUAD_SIZE;
			float z = rand() % QUAD_SIZE;

			// Create the plants
			SmartPointer plant( 
						new Plant( x, m_qtTerrain->GetHeightAt( x, z ), z ) );

			// Add the new plant to the quadtree and to the vector that holds 
			// all plants
			m_vPlants.push_back( plant );
			m_qtObjectMap.Insert( plant );
		}// End for n

		// Get the place to store computer bugs
		it = m_mapBugs.find( COMP );
		// Create some Bugs
		for( n = 0; n < 5; ++n )
		{
			int x = rand() % QUAD_SIZE;
			int z = rand() % QUAD_SIZE;

			// Create a bug
			SmartPointer bug( new Bug( x, z, COMPUTER_MODEL, COMP ) );

			// Add the bug to the vector of objects
			it->second.push_back( bug );

			// Put the bug onto the object map
			m_qtObjectMap.Insert( bug );
		}// End for n

		// Create some more Bugs of the other species
		it = m_mapBugs.find( PLAYER );
		for( n = 0; n < 5; ++n )
		{
			int x = rand() % QUAD_SIZE;
			int z = rand() % QUAD_SIZE;

			// Create a bug
			SmartPointer bug( new Bug( x, z, PLAYER_MODEL, PLAYER ) );

			// Add the bug to the vector of objects
			it->second.push_back( bug );

			// Put the bug onto the object map
			m_qtObjectMap.Insert( bug );
		}// End for n
		break;
	default:
		break;
	}// End switch( m_esState )

	// Reset the timer
	m_Timer->getElapsedSeconds();
}// End SurvivalEngine::SetupGame


// Cleans up everything after a game
void SurvivalEngine::CleanUpGame()
{
	// Clean out the quadTree
	m_qtObjectMap.RemoveAll();

	// Clean out the vectors
	m_vCarcus.clear();
	m_vecNewObjects.clear();
	m_vPlants.clear();

	// Reset all the waterpools and reinsert them into the object map
	for( int n = 0; n < m_vecWaterPools.size(); ++n )
	{
		reinterpret_cast< WaterPool* >( m_vecWaterPools[n].Get() )->Reset();
		m_qtObjectMap.Insert( m_vecWaterPools[n] );
	}// End for n

	// Clear out all the bugs
	map< string, vector< SmartPointer > >::iterator it;
	for( it = m_mapBugs.begin(); it != m_mapBugs.end(); ++it )
	{
		it->second.clear();
	}// End for it

	// Clear out the particle system
	m_psPSystem.RemoveAll();

	// If we where in the PLAY state
	if( m_esState == PLAY )
	{
		// Set the SmartPointer in the BugCam to an empty pointer
		m_bcCamera.SetFocus( SmartPointer() );
	}// End if
}// End CleanUpGame()


// Updates all the game objects.  Returns true if it is time to
// exit the game
MenuChoice SurvivalEngine::Update()
{
	// Clear the buffers and load the identity matrix
	glClearColor( 0, 0, 0, 0 );
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	glLoadIdentity();

	// Update the input system
	m_Input->Update();

	// Get the amount of time that has elapsed since the last update
	float elapsedSec = m_Timer->getElapsedSeconds();

	// If the escape key is down then we can quit
	if( m_Input->KeyDown( DIK_ESCAPE ) )
	{
		// Make sure that the user actually wanted to quit
		int BoxResult = MessageBox( NULL, "Do you want to quit this game?",
									"Quit?", MB_YESNO | MB_ICONQUESTION );

		// If the user selected yes
		if( BoxResult == IDYES )
		{
			// Clean up everything and return Menu to kick us back out to menu
			CleanUpGame();
			return MENU;
		}// End if
		else
		{
			// Otherwise, reset the counter so we don't count the time we
			// spent waiting on the user
			m_Timer->getElapsedSeconds();
		}// End else
	}// End if

	// Check for a pause
	// If the space bar is down
	if( m_Input->KeyDown( DIK_SPACE ) )
	{
		// If we haven't already logged this bar press
		if( ! m_bSpaceDown )
		{
			// Set the space down flag
			m_bSpaceDown = true;

			// Toggle the paused state
			m_bPaused = ! m_bPaused;
		}// End if
	}// End if
	else
	{
		// If we where in the middle of a space bar press
		if( m_bSpaceDown )
		{
			// Set the flag to show that we are ready for a new press
			m_bSpaceDown = false;
		}// End if
	}// End else

	// If we are playing the game
	if( m_esState == PLAY )
	{
		// Set the status of the current game
		m_gsStatus = IsGameOver();
	}// End if

	// If we are paused or if the game is over
	if( m_bPaused || m_gsStatus != GAME_ON )
	{
		// Set elapsedSec to zero
		elapsedSec = 0;
	}// End if

	// Set the frames per second
	m_iFPS = 1 / elapsedSec;

	// Update the camera and get the center of the scene based on the state
	float sx, sy, sz;
	switch( m_esState )
	{
	case PLAY:
		m_bcCamera.Update( elapsedSec );
		m_bcCamera.GetFocus()->GetPos( sx, sy, sz );
		break;
	case OBSERVE:
		m_scCamera.Update();
		m_scCamera.GetCenter( sx, sy, sz );
		break;
	default:
		break;
	};// End switch( m_esState )

	// Recalculate the view frustum
	viewFrustum::calculateFrustum();

	// Set the center of the scene on the terrain
	m_qtTerrain->SetCenter( sx, sy, sz );


	// Refine the terrain
	m_qtTerrain->RefineNode( QUAD_SIZE - 1, 0, QUAD_SIZE - 1, 0,
							 TERRAIN_DETAIL );

	// Get the total number of bugs in the game now
	int totalBugs = 0;
	map< string, vector< SmartPointer > >::iterator it;
	for( it = m_mapBugs.begin(); it != m_mapBugs.end(); ++it )
	{
		totalBugs += it->second.size();
	}// End for it

	// Update the fertility rate based on the number of bugs
	m_iFertilityRate = ( MAX_FERTILITY * totalBugs ) / MAX_BUGS;

	// An iterator to a vector of smartpointers to help with the updating
	vector< SmartPointer >::iterator obj;

	// Update all the bugs
	it = m_mapBugs.begin();

	// For each type of bug
	for( it; it != m_mapBugs.end(); ++it )
	{
		// For each bug in the current vector
		for( obj = it->second.begin(); obj != it->second.end(); )
		{
			// If it's time for this obj to die
			if( (*obj)->TimeToDie() )
			{
				// Copy obj
				SmartPointer copy = *obj;

				// Remove obj from the quad tree and the bug array
				m_qtObjectMap.Remove( copy );
				obj = it->second.erase( obj );

				// Create a carcus for the bug and add it to the vector
				SmartPointer car( new carcus( copy ) );
				m_vCarcus.push_back( car );

				// Delete the memory stored in copy
				copy.Delete();
			}// End if
			else
			{
				// Otherwise we can update obj and increment obj
				// Remove the bug from the quadtree
				m_qtObjectMap.Remove( *obj );
				// Update the bug
				(*obj)->Update( elapsedSec );
				// Reinsert the bug into the quadtree
				m_qtObjectMap.Insert( *obj );
				++obj;
			}// End else
		}// End for obj
	}// End for it

	// Update the plants
	for( obj = m_vPlants.begin(); obj != m_vPlants.end();  )
	{
		// If it is time for obj to die
		if( (*obj)->TimeToDie() )
		{
			// Destroy that plant
			// Copy the smartpointer
			SmartPointer copy = *obj;

			// Remove it from the quad tree and the plant vector
			m_qtObjectMap.Remove( copy );
			obj = m_vPlants.erase( obj );

			// Delete the memory stored in obj
			copy.Delete();
		}// End if
		else
		{
			// Otherwise, just update obj and increment obj
			(*obj)->Update( elapsedSec );
			++obj;
		}// End else
	}// End for obj

	// Update the carcus's
	for( obj = m_vCarcus.begin(); obj != m_vCarcus.end(); )
	{
		// If it is time for the carcus to "die"
		if( (*obj)->TimeToDie() )
		{
			// Copy the carcus
			SmartPointer copy = (*obj);

			// Remove the carcus from the vector
			obj = m_vCarcus.erase( obj );
		}// End if
		else
		{
			// Otherwise, just update the carcus
			(*obj)->Update( elapsedSec );
			++obj;
		}// End else
	}// End for obj


	// Update the water pools
	for( obj = m_vecWaterPools.begin(); obj != m_vecWaterPools.end(); ++obj )
	{
		(*obj)->Update( elapsedSec );
	}// End for obj

	// Update the Particle system
	m_psPSystem.Update( elapsedSec );

	// Now insert all the new objects that may have been created during the
	// last update
	for( obj = m_vecNewObjects.begin(); obj != m_vecNewObjects.end(); ++obj )
	{
		// If obj is a bug
		if( (*obj)->GetType() == "bug" )
		{
			// Get a pointer to the bug
			Bug* temp = reinterpret_cast< Bug* >( obj->Get() );

			// Put the new bug into the object map
			m_mapBugs.find( temp->GetSpecies() )->second.push_back( *obj );
			continue;
		}// End if

		// If obj is a plant
		if( (*obj)->GetType() == "plant" )
		{
			m_vPlants.push_back( *obj );
			continue;
		}// End if

		// If obj is a waterpool
		if( (*obj)->GetType() == "waterpool" )
		{
			m_vecWaterPools.push_back( *obj );
			continue;
		}// End if
	}// End for obj

	// Clear out the new objects
	m_vecNewObjects.clear();

	return GAME;
}// End SurvivalEngine::Update


// Renders all the game objects to the screen
void SurvivalEngine::Render()
{
	// Set up the OpenGL state variables
	glEnable( GL_SMOOTH );
	glEnable( GL_DEPTH_TEST );
	glEnable( GL_CULL_FACE );
	glFrontFace( GL_CCW );
	
	// Turn the texture to a mesh with the press of a button
	if( m_Input->KeyDown( DIK_Q ) )
		glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
	else
		glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );

	// Draw the terrain
	m_qtTerrain->Render( QUAD_SIZE - 1, 0, QUAD_SIZE - 1, 0 );

	// Turn on the lights
	glEnable( GL_LIGHTING );

	// Set up the lighting
	float LightAmbient[4]  = { 1, 1, 1, 1 }; 
	float LightDiffuse[4]  = { .5, .5, .5, 1 };
	float LightPosition[4] = { 0, 50, 14, 1};

	glLightfv( GL_LIGHT1, GL_AMBIENT,  LightAmbient );			
	glLightfv( GL_LIGHT1, GL_DIFFUSE,  LightDiffuse );			
	glLightfv( GL_LIGHT1, GL_POSITION, LightPosition );		
	glEnable( GL_LIGHT1 );

	// Enable point antialiasing
	glEnable( GL_POINT_SMOOTH );

	// Render all the bugs
	map< string, vector< SmartPointer > >::iterator it;
	vector< SmartPointer >::iterator obj;
	for( it = m_mapBugs.begin(); it != m_mapBugs.end(); ++it )
	{
		for( obj = it->second.begin(); obj != it->second.end(); ++obj )
		{
			(*obj)->Render();
		}// End for obj
	}// End for it

	// Disable point antialiasing
	glDisable( GL_POINT_SMOOTH );

	// Render the plants
	for( obj = m_vPlants.begin(); obj != m_vPlants.end(); ++obj )
	{
		(*obj)->Render();
	}// End for obj

	// Render the camera bug if we are in the PLAY state
	if( m_esState == PLAY )
	{
		m_bcCamera.Render();
	}// End if

	// Turn off the lights
	glDisable( GL_LIGHT1 );
	glDisable( GL_LIGHTING );

	// Render the particle system
	m_psPSystem.Render();

	// Render the carcus
	for( obj = m_vCarcus.begin(); obj != m_vCarcus.end(); ++obj )
	{
		(*obj)->Render();
	}// End for obj

	// Render the WaterPools
	obj = m_vecWaterPools.begin();
	for( obj; obj != m_vecWaterPools.end(); ++obj )
	{
		(*obj)->Render();
	}// End for obj

	// Render the mini map
	RenderMiniMap();

	// Write the number of each bug to the screen
	int textOffSet = 4;
	float color[3] = { 0, 1, 1 };
	int size = 200;
	for( it = m_mapBugs.begin(); it != m_mapBugs.end(); ++it )
	{
		// If it is the player species, then we have to display the number
		// of bugs in the array plus one for the camera bug
		if( it->first == PLAYER )
		{
			ScreenWriter::Render( size - 48, size - textOffSet, 
				color, "%s = %d", it->first.c_str(), it->second.size() + 1 );
		}// End if
		else
			ScreenWriter::Render( size - 48, size - textOffSet, 
				color, "%s = %d", it->first.c_str(), it->second.size() );

		textOffSet += 4;
	}// End for it

	// Write fertility rate to the screen
	ScreenWriter::Render( size - 48, size - textOffSet,
				color, "Fertility rate = %d", m_iFertilityRate );

	// Render the frame per second
	textOffSet += 4;
	ScreenWriter::Render( size - 48, size - textOffSet,
				color, "FPS: %i", m_iFPS );

	textOffSet += 4;
	// A variable for the printf formatted strings with no arguments
	int args = 0;

	// If we are paused
	if( m_bPaused )
	{
		// Render paused onto the screen
		ScreenWriter::Render( size - 48, size - textOffSet, 
							  color, "Paused%n", &args );
	}// End if

	// If the engine is in a playing state
	if( m_esState == PLAY )
	{
		float red[3] = { 1, 0, 0 };
		// If the player has won
		if( m_gsStatus == PLAYER_WON )
		{
			// Render the status to the screen
			ScreenWriter::Render( size / 4, size / 2, red,
								"You won. Press escape to continue%n", &args );
		}// End if

		// If the computer has won
		if( m_gsStatus == COMPUTER_WON )
		{
			// Render the status to the screen
			ScreenWriter::Render( size / 4, size / 2, red,
						"You have lost. Press escape to continue%n", &args );
		}// End if
	}// End if

	// Cause a buffer flush
	glFlush();
}// End SurvivalEngine::Render


// Renders the mini map to the top left of the screen
void SurvivalEngine::RenderMiniMap()
{
	// Turn on point antialiasing
	glEnable( GL_POINT_SMOOTH );
	// Save and reset the projection matrix stack
	glPushMatrix();
	glLoadIdentity();

	glMatrixMode( GL_PROJECTION );
	glPushMatrix();
	glLoadIdentity();

	// Scale the map so that it renders in the corrent way
	glScalef( -1, 1, 1 );

	// Scale and translate so that the map draws in the upper right corner
	glScalef( .25, .3, 1 );
	glTranslatef( 2.95, 2.3, 0 );

	// Set up an orthographic projection
	gluOrtho2D( 0, QUAD_SIZE, 0, QUAD_SIZE );

	// Select the modelview matrix stack
	glMatrixMode( GL_MODELVIEW );

	// Enable blending and set up the transparency
	glEnable( GL_BLEND );

	// Set the transparency up
	glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

	// Draw all the objects as points
	float tx = 0; float ty = 0; float tz = 0;
	map< string, vector< SmartPointer > >::iterator it;
	vector< SmartPointer >::iterator obj;

	glPointSize( 5 );
	glBegin( GL_POINTS );
		// Draw the water pools as a blue dot
		glColor4f( 0, 0, 1, 1 );
		for( obj = m_vecWaterPools.begin(); 
			 obj != m_vecWaterPools.end(); ++obj )
		{
			// Get the position of obj
			(*obj)->GetPos( tx, ty, tz );
			// Draw the dot
			glVertex2f( tx, tz );
		}// End for obj

		// Draw the food as a green dot
		glColor4f( 0, 1, 0, 1 );
		for( obj = m_vPlants.begin(); obj != m_vPlants.end(); ++obj )
		{
			// Get the position of obj
			(*obj)->GetPos( tx, ty, tz );
			// Draw the dot
			glVertex2f( tx, tz );
		}// End for obj

		// Draw a dot for each bug
		for( it = m_mapBugs.begin(); it != m_mapBugs.end(); ++it )
		{
			if( it->first == PLAYER )
			{
				glColor4f( 1, 1, 0, 1 );
			}// End if
			else
			{
				glColor4f( 1, 0, 0, 1 );
			}// End else

			for( obj = it->second.begin(); obj != it->second.end(); ++obj )
			{
				// Get the position of obj
				(*obj)->GetPos( tx, ty, tz );
				// Draw the dot
				glVertex2f( tx, tz );
			}// End for obj
		}// End for it

		// Render a white dot for the bug on the bugcam if we are in PLAY
		if( m_esState == PLAY )
		{
			glColor4f( 1, 1, 1, 1 );
			m_bcCamera.GetFocus()->GetPos( tx, ty, tz );
			glVertex3f( tx, tz, 0 );
		}// End if
	glEnd();
	glPointSize( 1 );

	// Draw the back ground
	glColor4f( 1, 1, 1, .3 );
	glBegin( GL_QUADS );
		glVertex3f( 0,		   0,		  0 );
		glVertex3f( 0,		   QUAD_SIZE, 0 );
		glVertex3f( QUAD_SIZE, QUAD_SIZE, 0 );
		glVertex3f( QUAD_SIZE, 0,		  0 );
	glEnd();

	// Reset the color
	glColor4f( 1, 1, 1, 1 );

	// Disable blending
	glDisable( GL_BLEND );

	// Select the projection matrix stack and restore the settings
	glMatrixMode( GL_PROJECTION );
	glPopMatrix();

	// Select the modelview matrix stack and restore the settings
	glMatrixMode( GL_MODELVIEW );
	glPopMatrix();

	// Turn off point antialiasing
	glDisable( GL_POINT_SMOOTH );
}// End SurvivalEngine::RenderMiniMap


// Creates a new plant from x,z and adds it to the map and the terrain
void SurvivalEngine::CreatePlant( float x, float z )
{
	// Make sure that x and z are on the map
	int size = m_qtTerrain->GetSize();
	if( x > size ) x = size;
	if( z > size ) z = size;
	if( x < 0 )    x = 0;
	if( z < 0 )    z = 0;

	// Create a new plant
	SmartPointer plant( new Plant( 
						x, m_qtTerrain->GetHeightAt( x, z ), z ) );

	// Add the plant to the map and to the update list
	m_qtObjectMap.Insert( plant );
	m_vecNewObjects.push_back( plant );
}// End SurvivalEngine::CreatePlant


// Creates a new bug from x,z and adds it to the map and terrain
void SurvivalEngine::CreateBug( const Bug* bug )
{
	// Create a new bug
	SmartPointer BUG( new Bug( *bug ) );
	m_qtObjectMap.Insert( BUG );
	m_vecNewObjects.push_back( BUG );
}// End SurvivalEngine::CreateBug


// Returns a player controlled bug for the player to take control of
SmartPointer SurvivalEngine::NewFocus()
{
	// A place to store the SmartPointer
	SmartPointer returnValue;

	// Get the player array
	map< string, vector< SmartPointer > >::iterator it;
	it = m_mapBugs.find( PLAYER );

	// If there is something in the array
	if( it->second.size() > 0 )
	{
		// Copy the last thing in the array
		returnValue = *( it->second.end() - 1 );

		// Erase the last thing in the array
		it->second.erase( it->second.end() - 1 );
	}// End if

	// Return the return value
	return returnValue;
}// End SurvivalEngine::NewFocus


// Returns the status of the current game
enum GameStatus SurvivalEngine::IsGameOver()
{
	// An iterator to the map structure to help us out
	map< string, vector< SmartPointer > >::iterator it;

	// Check to see if the player has lost
	it = m_mapBugs.find( PLAYER );

	// If the player has no bugs left and it is time for the camera bug
	// to die
	if( it->second.size() == 0 && m_bcCamera.GetFocus()->TimeToDie() )
	{
		// Return 1 
		return COMPUTER_WON;
	}// End if

	// Check to see if there are no more computer controlled bugs left
	// found is set to true when we find a computer that has some bugs
	bool found = false;
	for( it = m_mapBugs.begin(); it != m_mapBugs.end() &&
								 ( ! found )			  ; ++it )
	{
		// If this is not the player and it has some bugs
		if( it->first != PLAYER && it->second.size() > 0 )
		{
			// Set found to true
			found = true;
		}// End if
	}// End for it

	// If we didn't find a computer with some bugs
	if( ! found )
	{
		// Return that the player won
		return PLAYER_WON;
	}// End if

	// Return GAME_ON by default
	return GAME_ON;
}// End SurvivalEngine::IsGameOver