// Author : Chris Tolley
// Date   : 8/18/2004
// Targeter.cpp contains the class decfinition for a class that will highlight
// the target of the bug targeted by the player controlled bug

#pragma warning ( disable : 4305 )

#include <windows.h>
#include <gl/gl.h>

#include "BugCam.h"
#include "Targeter.h"
#include "logger.h"
#include "ms3d.h"

// Some constants to help out
// The basic unit of rotation
const float		ANGLE_BASE = 45;
// The basic unit of time
const float		TIME_BASE  = 1;

// Constructor
Targeter::Targeter()
: m_uiList( 0 ), m_fAngle( 0 )
{}// End Targeter::Constructor


// Destructor
Targeter::~Targeter()
{}


// Initializes the display list
void Targeter::Initialize( const char* ms3dFile )
{
	// Load the ms3f file
	ms3d myModel( ms3dFile );

	// Create a new display list
	m_uiList = glGenLists( 1 );

	// Make sure that the list is a valid list
	if( m_uiList == 0 )
	{
		logger::event( "Targeter::Constructor", 
					   "Error in creating display list.", 0 );
		return;
	}// End if

	// Put the commands into the list to draw the model
	glNewList( m_uiList, GL_COMPILE );
		glMatrixMode( GL_TEXTURE );
		glPushMatrix();
		glRotatef( 180, 1, 0, 0 );
		myModel.DrawTexturedMesh();
		glPopMatrix();
		glMatrixMode( GL_MODELVIEW );
	glEndList();
}// End Targeter::Initialize


// Updates the targeter
void Targeter::Update( float elapsedSec )
{
	// Calculate the angle of rotation based on the amount of 
	// time that has elapsed since the last update
	float angle = ( ANGLE_BASE * elapsedSec ) / TIME_BASE;

	// Add that to m_fAngle
	m_fAngle += angle;

	// Make sure that m_fAngle is still in range
	if( m_fAngle >= 360 )
	{
		m_fAngle = m_fAngle - 360;
	}// End if
}// End Targeter::Update


// Renders the targeter
void Targeter::Render( BugCam* camera )
{
	// Enable blending
	glEnable( GL_BLEND );

	// Disable the cull facing
	glDisable( GL_CULL_FACE );

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

	// Store the modelview matrix stack settings
	glPushMatrix();

	// Get the bug that is in focus of the camera
	Bug* focus  = reinterpret_cast< Bug* >( camera->GetFocus().Get() );

	// A place to store the position of stuff
	float x = 0; float y = 0; float z = 0;

	// The alpha value for the targeter when the focus is not at the target
	float alpha = .3;
	// The alpha value for the targeter when the focus is at the target
	float atAlpha = .6;

	// Set the color based on the state of the bug cam
	BugState state = focus->GetState();
	switch( state )
	{
	case FIGHTING:
		// If the focus has a valid target
		if( focus->GetTarget().isValid() )
		{
			// Set up the matrix stack with the targets coord system
			focus->GetTarget()->GetPos( x, y, z );

			// Move the targeter to x,z and rotate it by angle
			glTranslatef( x, y, z );
			glRotatef( m_fAngle, 0, 1, 0 );

			// If the camera's focus is at it's target
			if( camera->IsAtTarget() )
				glColor4f( 1, 0, 0, atAlpha );
			else
				glColor4f( 1, 0, 0, alpha );

			// Call the list storing the drawing commands
			glCallList( m_uiList );

			// Reset the modelview matrix stack
			glPopMatrix();
		}// End if
		break;
	case RESTING:
		glColor4f( .5, .5, .5, atAlpha );

		// Set up the matrix stack with the focus's coord system
		focus->GetPos( x, y, z );

		// Move the targeter to x,z and rotate it by angle
		glTranslatef( x, y, z );
		glRotatef( m_fAngle, 0, 1, 0 );

		// Call the list storing the drawing commands
		glCallList( m_uiList );

		// Reset the modelview matrix stack
		glPopMatrix();
		break;
	case DRINKING:
		// If the focus has a valid target
		if( focus->GetTarget().isValid() )
		{
			// Set up the matrix stack with the targets coord system
			focus->GetTarget()->GetPos( x, y, z );

			// Move the targeter to x,z and rotate it by angle
			glTranslatef( x, y, z );
			glTranslatef( 0, 1, 0 );
			glRotatef( m_fAngle, 0, 1, 0 );

			// Expand the targeter a little so we can see it
			glScalef( 2, 2, 2 );

			// If the camera's focus is at it's target
			if( camera->IsAtTarget() )
				glColor4f( 0, 0, 1, atAlpha );
			else
				glColor4f( 0, 0, 1, alpha );

			// Call the list storing the drawing commands
			glCallList( m_uiList );

			// Reset the modelview matrix stack
			glPopMatrix();
		}// End if
		break;
	case EATING:
		// If the focus has a valid target
		if( focus->GetTarget().isValid() )
		{
			// Set up the matrix stack with the targets coord system
			focus->GetTarget()->GetPos( x, y, z );

			// Move the targeter to x,z and rotate it by angle
			glTranslatef( x, y, z );
			glRotatef( m_fAngle, 0, 1, 0 );

			// Expand the targeter a little so we can see it
			glScalef( 1.5, 1.5, 1.5 );

			// If the camera's focus is at it's target
			if( camera->IsAtTarget() )
				glColor4f( 1, 1, 0, atAlpha );
			else
				glColor4f( 1, 1, 0, alpha );

			// Call the list storing the drawing commands
			glCallList( m_uiList );

			// Reset the modelview matrix stack
			glPopMatrix();
		}// End if
		break;
	case REPRODUCING:
		glColor4f( 0, 1, 0, alpha );
		
		// Set upthe matrix stack with the focus's coord system
		focus->GetPos( x, y, z );

		// Move the targeter to x,z and rotate it by angle
		glTranslatef( x, y, z );
		glRotatef( m_fAngle, 0, 1, 0 );

		// Call the list storing the drawing commands
		glCallList( m_uiList );

		// Reset the modelview matrix stack
		glPopMatrix();		
	default:
		break;
	};// End switch( state )

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

	// Enable cull facing again
	glEnable( GL_CULL_FACE );

	// Disable blending
	glDisable( GL_BLEND );
}// End Targeter::Render