// Author : Chris Tolley
// Date   : 8/29/2004
// MenuOption.h contains the class declaration for a menu option to use in 
// the game Survival

#include <windows.h>
#include <gl/gl.h>
#include <vector>
using namespace std;

#include "MenuOption.h"
#include "texture.h"
#include "logger.h"

// The distance away from the starting position we translate each mixel
const float TRANSLATE_DIST = 500;
// A basic unit of time
const float	TOTAL_TIME	   = 1;

// Constructor
MenuOption::MenuOption() 
: m_fPercent( 0 ), m_iDirection( 1 ), m_mosState( SCATTERED )
{
}


// Constructor with arguments
MenuOption::MenuOption( const char* bmpFile ) 
: m_fPercent( 0 ), m_iDirection( 1 ), m_mosState( SCATTERED )
{
	// Load the bmp file and generate the mixel data
	Load( bmpFile );
}// End MenuOption::Constructor


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


// Loads all the data for this mixel
void MenuOption::Load( const char* bmpFile )
{
	// Load the texture
	texture text( bmpFile );

	// Now we need to generate the mixel's
	// Get the height and width of the texture we just loaded
	int height = text.GetHeight();
	int width  = text.GetWidth();

	// Some variables to keep track of the current point of each mixel
	float xPos = 0;
	float yPos = 0;

	// A pointer the to current pixel
	unsigned char* pixel = NULL;

	// The value to mod by
	float modValue = 100;

	// For each pixel in the picture
	for( int x = 0; x < width; ++x )
	{
		for( int y = 0; y < height; ++y )
		{
			// Get a pointer to the x,yth pixel
			pixel = text.At( x, y );
			
			// Create a mixel
			mixel temp;

			// Set the colors of the mixel
			temp.Color_[0] = float( pixel[0] ) / 255.0f;
			temp.Color_[1] = float( pixel[1] ) / 255.0f;
			temp.Color_[2] = float( pixel[2] ) / 255.0f;

			// Create 3 values between 0 and 1
			float rx = float( rand() % 100 ) / 100;
			float ry = float( rand() % 100 ) / 100;
			float rz = 0;//float( rand() % 100 ) / 100;

			// Translate those 3 values outward
			rx *= TRANSLATE_DIST;
			ry *= TRANSLATE_DIST;
//			rz *= TRANSLATE_DIST;

			// Make them negative based on a coin toss
			if( rand() % 2 == 0 )
				rx = -rx;
			if( rand() % 2 == 0 )
				ry = -ry;
//			if( rand() % 2 == 0 )
//				rz = -rz;

			// Set the end position
			temp.EndPos_[0] = x;
			temp.EndPos_[1] = y;
			temp.EndPos_[2] = 0;
			
			// Store those values
			temp.StartPos_[0] = rx + temp.EndPos_[0];
			temp.StartPos_[1] = ry + temp.EndPos_[1];
			temp.StartPos_[2] = rz + temp.EndPos_[2];



			// Set the current position to start position
			temp.Position_[0] = temp.StartPos_[0];
			temp.Position_[1] = temp.StartPos_[1];
			temp.Position_[2] = temp.StartPos_[2];

			// Add the mixel to the array
			m_vMixels.push_back( temp );

			// Increment yPos
			yPos += .01f;
		}// End for y

		// Reset yPos
		yPos = 0;

		// Increment xPos
		xPos += .01f;
	}// End for x
}// End MenuOption::Load


// Sets this menu's state
void MenuOption::SetState( enum MenuOptionState state )
{
	// A case switch for the current state
	switch( m_mosState )
	{
	case SCATTERED:
		// If the new state if GATHERING
		if( state == GATHERING )
		{
			// Set the direction and reset the time
			m_iDirection = 1;
			m_fPercent = 0;
		}// End if
		break;
	case GATHERING:
		// If the new state is SCATTERING
		if( state == SCATTERING )
		{
			// Set the direction and the time
			m_iDirection = -1;
			m_fPercent = TOTAL_TIME - m_fPercent;
		}// End if
		break;
	case GATHERED:
		// If the new state if SCATTERING
		if( state == SCATTERING )
		{
			// Set the direction and the time
			m_iDirection = -1;
			m_fPercent = TOTAL_TIME;
		}// End if
		break;
	case SCATTERING:
		// If the new state is GATHERING
		if( state == GATHERING )
		{
			m_iDirection = 1;
			m_fPercent = TOTAL_TIME - m_fPercent;
		}// End if
		break;
	default:
		break;
	};// End switch( m_mosState )

	// Set the state
	m_mosState = state;
}// End MenuOption::SetState


// Updates each mixel in this menu option
void MenuOption::Update( float elapsedSec )
{
	// If the current state is SCATTERED or GATHERED
	if( m_mosState == SCATTERED || m_mosState == GATHERED )
	{
		// Then we can just return cause we don't need do anything
		return;
	}// End if

	// Increase the percentage
	m_fPercent += ( elapsedSec * m_iDirection );

	// For each pixel
	vector< mixel >::iterator mix;
	for( mix = m_vMixels.begin(); mix != m_vMixels.end(); ++mix )
	{
		// Set the position of its mixel
		mix->Position_[0] = mix->StartPos_[0] +
		( m_fPercent * ( mix->EndPos_[0] - mix->StartPos_[0] ) ) / TOTAL_TIME;

		mix->Position_[1] = mix->StartPos_[1] +
		( m_fPercent * ( mix->EndPos_[1] - mix->StartPos_[1] ) ) / TOTAL_TIME;

		mix->Position_[2] = mix->StartPos_[2] +
		( m_fPercent * ( mix->EndPos_[2] - mix->StartPos_[2] ) ) / TOTAL_TIME;
	}// End for mix

	// Check to see if we need to make a state change

	// If m_fPercent is equal to TOTAL_TIME and we are in the
	// GATHERING state
	if( m_fPercent > TOTAL_TIME && m_mosState == GATHERING )
	{
		// Set the current state to GATHERED
		m_mosState = GATHERED;

		// Set each mixel to it's end point
		for( mix = m_vMixels.begin(); mix != m_vMixels.end(); ++mix )
		{
			mix->Position_[0] = mix->EndPos_[0];
			mix->Position_[1] = mix->EndPos_[1];
			mix->Position_[2] = mix->EndPos_[2];
		}// End for mix
	}// End if

	// If m_fPercent is equal to zero and we are in the the
	// SCATTERING state
	if( m_fPercent < 0 && m_mosState == SCATTERING )
	{
		// Set the current state to SCATTERED
		m_mosState = SCATTERED;
	}// End if
}// End MenuOption::Update


// Renders this MenuOption to the screen
void MenuOption::Render()
{
	// Don't render this MenuOption if it is completely scattered
	if( m_mosState != SCATTERED )
	{

		// Set the point size
		glPointSize( 5 );
		// Enable antialising
		glEnable( GL_POINT_SMOOTH );

		// Enable vertex arrays
		glEnableClientState( GL_COLOR_ARRAY );
		glEnableClientState( GL_VERTEX_ARRAY );

		// Set up the color array
		glColorPointer( 3, GL_FLOAT, sizeof( mixel ), &m_vMixels[0] );

		// A pointer used to get to the 12th bite of the first mixel
		char* ptr = reinterpret_cast< char* >( &m_vMixels[0] );
		
		// Set up the vertex array
		glVertexPointer( 3, GL_FLOAT, sizeof( mixel ), &ptr[12] );

		// Draw each element in the arrays
		glDrawArrays( GL_POINTS, 0, m_vMixels.size() );

		// Disable vertex arrays
		glDisableClientState( GL_COLOR_ARRAY );
		glDisableClientState( GL_VERTEX_ARRAY );

		// Disable antialising
		glDisable( GL_POINT_SMOOTH );
		// Reset the point size
		glPointSize( 1 );

		// Reset the color
		glColor3f( 1, 1, 1 );
	}// End if
}// End MenuOption::Render