#include <GL/glut.h>
#include <cmath>
#include <list>
#include <vector>

#include "globale.h"
#include "Temps.h"
#include "CVector3.h"
#include "CCamera.h"
#include "CCube.h"
#include "CBloc.h"
#include "CJeu.h"




// Début de la rotation

void CBloc::BeginRotation(short AxeX, short AxeY, short AxeZ)
{
	// Copie temporaire
	CBloc BlocTemp = *this;
	
	EstMouvement = ROTATION;
	Temps0Mouv = GetTemps();
	RotX = AxeX; RotY = AxeY; RotZ = AxeZ;
	Rotate(AxeX, AxeY, AxeZ);

	if (!gJeu.PeutEtreLa(*this))
		*this = BlocTemp;
	else
		gJeu.CreeBlocGuide();
}




// Rotation d'un cube autour d'un axe

void CBloc::Rotate(short AxeX, short AxeY, short AxeZ)
{
	float NouvX, NouvY, NouvZ;

	for (int i = 0; i < LesCubes.size(); i++)
	{
		NouvX  = (AxeX * AxeX)			* LesCubes[i].x;
		NouvX += (AxeX * AxeY - AxeZ)	* LesCubes[i].y;
		NouvX += (AxeX * AxeZ + AxeY)	* LesCubes[i].z;
		
		NouvY  = (AxeX * AxeY + AxeZ)	* LesCubes[i].x;
		NouvY += (AxeY * AxeY)			* LesCubes[i].y;
		NouvY += (AxeY * AxeZ - AxeX)	* LesCubes[i].z;
		
		NouvZ  = (AxeX * AxeZ - AxeY)	* LesCubes[i].x;
		NouvZ += (AxeY * AxeZ + AxeX)	* LesCubes[i].y;
		NouvZ += (AxeZ * AxeZ)			* LesCubes[i].z;
		
		LesCubes[i].x = NouvX;
		LesCubes[i].y = NouvY;
		LesCubes[i].z = NouvZ;

		LesCubes[i].Sens ^= true;
	}
}




// Début de la translation

void CBloc::BeginTranslation(type_direction Direction)
{
	// Copie temporaire
	CBloc BlocTemp = *this;

	EstMouvement = TRANSLATION;
	Temps0Mouv = GetTemps();
	MouvDir = Direction;
	AncienX = x;
	AncienY = y;
	Translate(Direction);

	if (!gJeu.PeutEtreLa(*this))
		*this = BlocTemp;
	else
		gJeu.CreeBlocGuide();
}




// Translation d'un bloc dans une direction

void CBloc::Translate(type_direction Direction)
{
	switch (Direction)
	{
	case AVANT : y = AncienY + 1; break;
	case DROITE : x = AncienX + 1; break;
	case ARRIERE : y = AncienY - 1; break;
	case GAUCHE : x = AncienX - 1; break;
	}
}




// Dessin du bloc

void CBloc::Draw(void)
{
	static long TempsLast = GetTemps();
	glPushMatrix();

	if (!EstEnBas)
	{
		if (EstDescenteRapide)
		{
			Temps0 -= SPEEDFAST*(GetTemps() - TempsLast);
		}

		z = MAX_Z - (GetTemps() - Temps0) * (gJeu.Niveau + 1) / 1000.0f;

		if (!gJeu.PeutEtreLa(*this))
		{
			z = gJeu.BlocGuide.z;
			EstEnBas = true;
			Temps0Arret = GetTemps();
		}
	}
	else if ( (GetTemps() - Temps0Arret > TEMPSARRET) && (!EstMouvement) )
	{
		gJeu.AjouterBloc(*this);
		return;
	}
	

	if (EstMouvement == ROTATION)
	{
		glTranslatef(x + offX, y + offY, z + offZ);

		float Angle = 90.0f * (GetTemps() - Temps0Mouv) / TEMPSMOUV;

		if (Angle > 90)
		{
			EstMouvement = IMMOBILE;

			if (EstEnBas)
			{
				z -= 1;
				if (gJeu.PeutEtreLa(*this))
				{
					z = gJeu.BlocGuide.z;
					EstEnBas = false;
					Temps0 += GetTemps() - Temps0Arret;
				}
				else
					z = gJeu.BlocGuide.z;
			}
		}
		else
		{
			glRotatef(Angle-90, RotX, RotY, RotZ);
		}
	}
	else if (EstMouvement == TRANSLATION)
	{
		float Deplacement = (float)(GetTemps() - Temps0Mouv) / TEMPSMOUV;

		if (Deplacement > 1)
		{
			EstMouvement = IMMOBILE;

			if (EstEnBas)
			{
				z -= 1;
				if (gJeu.PeutEtreLa(*this))
				{
					z = gJeu.BlocGuide.z;
					EstEnBas = false;
					Temps0 += GetTemps() - Temps0Arret;
				}
				else
					z = gJeu.BlocGuide.z;
			}
		}
		else
		{
			switch (MouvDir)
			{
			case AVANT : AncienY = y - 1 + Deplacement; break;
			case DROITE : AncienX = x - 1 + Deplacement; break;
			case ARRIERE : AncienY = y + 1 - Deplacement; break;
			case GAUCHE : AncienX = x + 1 - Deplacement; break;
			}
		}

		glTranslatef(AncienX + offX, AncienY + offY, z + offZ);
	}
	else
	{
		glTranslatef(x + offX, y + offY, z + offZ);
	}

	for (int i = 0; i < LesCubes.size(); i++)
		LesCubes[i].Draw();

	glPopMatrix();

	TempsLast = GetTemps();
}




// Dessin du bloc pour le bloc guide

void CBloc::DrawGuide(void)
{
	glPushMatrix();
	glTranslatef(x + offX, y + offY, z + offZ);

	for (int i = 0; i < LesCubes.size(); i++)
		LesCubes[i].DrawGuide();

	glPopMatrix();
}




// S'arrange pour que le bloc soit rendu en bas

void CBloc::DropBloc(void)
{
	Temps0 = static_cast<long> (GetTemps() - (MAX_Z - gJeu.BlocGuide.z) * 1000 / (gJeu.Niveau + 1));
	z = gJeu.BlocGuide.z;
}




// Fonctions pour la couleur du bloc

void CBloc::Couleur01() { r1 = 1.0f; g1 = 0.0f; b1 = 0.0f;
						  r2 = 0.7f; g2 = 0.0f; b2 = 0.0f; }
void CBloc::Couleur02() { r1 = 0.0f; g1 = 0.0f; b1 = 1.0f;
						  r2 = 0.0f; g2 = 0.0f; b2 = 0.7f; }
void CBloc::Couleur03() { r1 = 0.0f; g1 = 1.0f; b1 = 0.0f;
						  r2 = 0.0f; g2 = 0.5f; b2 = 0.0f; }
void CBloc::Couleur04() { r1 = 1.0f; g1 = 1.0f; b1 = 0.0f;
						  r2 = 0.7f; g2 = 0.7f; b2 = 0.0f; }
void CBloc::Couleur05() { r1 = 1.0f; g1 = 0.0f; b1 = 1.0f;
						  r2 = 0.7f; g2 = 0.0f; b2 = 0.7f; }
void CBloc::Couleur06() { r1 = 0.0f; g1 = 1.0f; b1 = 1.0f;
						  r2 = 0.0f; g2 = 0.7f; b2 = 0.7f; }
void CBloc::Couleur07() { r1 = 1.0f; g1 = 1.0f; b1 = 1.0f;
						  r2 = 0.7f; g2 = 0.7f; b2 = 0.7f; }
void CBloc::Couleur08() { r1 = 0.0f; g1 = 0.0f; b1 = 0.0f;
						  r2 = 0.3f; g2 = 0.3f; b2 = 0.3f; }
