#include "Navicella.h"

Navicella::Navicella( String p_name, SceneManager * p_sceneMgr, Overlay * p_Overlay, bool p_MissionObjects[] ) {
			
	m_Name				= p_name;
	m_sceneMgr			= p_sceneMgr;

	m_MissionObjects = & p_MissionObjects[0];

	// variabili di navigazione
	m_Status			= Navigator; // la modalità di input iniziale è quella di navigazione
			
	// variabili per gestire il movimento
	m_Accellerating		= false; // parte da ferma
	m_Vel				= 0;
	m_IncrVel			= 10;
	m_MaxVel			= 1200;

	m_VerticalVel		= 200;

	m_Retromarcia		= false;
	m_RetroVel			= 0;
	m_IncrRetroVel		= 10;
	m_MaxRetroVel		= 200;

	m_Breaking			= false;
	m_Frenata			= 20;
	m_Deriva			= 0;

	m_PitchStrenght		= 2;
	m_RollStrenght		= 2;
	m_YawStrenght		= 2;

	m_StatusToggle		= 0.0;
	m_LBToggle			= 0.0;
	m_CassaPresa		= false; // si parte senza cassa
	m_CassaPresaDaSparire= false;
	m_CassaLasciataDaSparire=false;
	m_CassaBonusDaSparire= false;
	m_ScaleRate			= 10;


	m_ActualPitch		= 0.0; // parto con orientamento corretto
	m_ActualRoll		= 0.0; // parto con orientamento corretto
	m_ActualPitchInt	= 0;
	m_ActualRollInt		= 0;

	// BonusMalus disattivati all'inizio
	m_BonusMalus		= false;
	m_TurboEnabled		= false;
	m_SlowMotionEnabled	= false;
	m_PigEnabled		= false;
	m_InvertedEnabled	= false;
	m_InvisibleEnabled	= false;
	m_NoControl			= false;
	m_Victory			= false;
	
	m_SphereRange		= 300;
	m_OverlayToggle		= 0;	

	// salvo le variabili per gestire i nodi principali
	m_navicella = m_sceneMgr->getRootSceneNode()->createChildSceneNode( "NodoNavicella" );
	m_naviDir = m_navicella->createChildSceneNode( m_Name + "_sight", Vector3 (0, 0, 100 ) );
	m_cameraNode = m_navicella->createChildSceneNode( m_Name + "_camera", Vector3 (0, 50, -150 ) );

	// creo il maiale per il malus Pig e lo nascondo
	m_Pig = m_navicella->createChildSceneNode("maiale", Vector3::ZERO );
	m_PigEntity = m_sceneMgr->createEntity( "PigEntity", "maiale.mesh" );
	m_Pig->attachObject( m_PigEntity );
	m_Pig->setVisible(false);

	// creo la navicella
	m_entity = m_sceneMgr->createEntity( m_Name, "SFighter.mesh" );
	m_navicella->attachObject( m_entity );

	
	// creo il nodo del teletrasporto casse 
	m_TeleCassa = m_navicella->createChildSceneNode( Vector3(0, -90, 40) );
	Entity * Cassa_Fantasma = m_sceneMgr->createEntity( "Cassa_Fantasma", "cassa.mesh" );
	Cassa_Fantasma->setMaterialName( "cassa/cassa" );
	m_GhostCassa = m_TeleCassa->createChildSceneNode( Vector3::ZERO );
	m_GhostCassa->attachObject( Cassa_Fantasma );
	m_GhostCassa->setVisible(false);
	m_TeleCassa->scale(10, 10, 10);
	
	m_TelePort2 = m_sceneMgr->createParticleSystem("cassa", "ringFire2"); 
	m_TelePort1 = m_sceneMgr->createParticleSystem("cassa2", "ringFire2"); 

	// inizializza i ParticleSystem per i motori
	m_motore_sx1 = m_sceneMgr->createParticleSystem("motoresx1", "scia"); 
	m_motore_sx2 = m_sceneMgr->createParticleSystem("motoresx2", "scia");
	m_motore_sx3 = m_sceneMgr->createParticleSystem("motoresx3", "scia");
	m_motore_sx4 = m_sceneMgr->createParticleSystem("motoresx4", "scia");

	m_motore_dx1 = m_sceneMgr->createParticleSystem("motoredx1", "scia"); 
	m_motore_dx2 = m_sceneMgr->createParticleSystem("motoredx2", "scia");
	m_motore_dx3 = m_sceneMgr->createParticleSystem("motoredx3", "scia");
	m_motore_dx4 = m_sceneMgr->createParticleSystem("motoredx4", "scia");
		
		// e per il turbo
		m_TurboSx = m_sceneMgr->createParticleSystem("turbosx", "scia");
		m_TurboDx = m_sceneMgr->createParticleSystem("turbodx", "scia");
		// e i rispettivi nodi
		m_TurboDxNode = m_navicella->createChildSceneNode( Vector3(20, -2, -110) );
		m_TurboSxNode = m_navicella->createChildSceneNode( Vector3(-20, -2, -110) );

		
	// attacca i ParticleSystem al nodo della navicella nella posizione dei motori
	m_Nodemotore_sx1 = m_navicella->createChildSceneNode( Vector3(30, 22, -140) );
	m_Nodemotore_sx2 = m_navicella->createChildSceneNode( Vector3(30, 22, -144) );
	m_Nodemotore_sx3 = m_navicella->createChildSceneNode( Vector3(30, 22, -146) );
	m_Nodemotore_sx4 = m_navicella->createChildSceneNode( Vector3(30, 22, -142) );

	m_Nodemotore_sx1->attachObject(m_motore_sx1);
	m_Nodemotore_sx2->attachObject(m_motore_sx2);
	m_Nodemotore_sx3->attachObject(m_motore_sx3);
	m_Nodemotore_sx4->attachObject(m_motore_sx4);

	m_Nodemotore_dx1 = m_navicella->createChildSceneNode( Vector3(-30, 22, -140) );
	m_Nodemotore_dx2 = m_navicella->createChildSceneNode( Vector3(-30, 22, -144) );
	m_Nodemotore_dx3 = m_navicella->createChildSceneNode( Vector3(-30, 22, -146) );
	m_Nodemotore_dx4 = m_navicella->createChildSceneNode( Vector3(-30, 22, -142) );

	m_Nodemotore_dx1->attachObject(m_motore_dx1);
	m_Nodemotore_dx2->attachObject(m_motore_dx2);
	m_Nodemotore_dx3->attachObject(m_motore_dx3);
	m_Nodemotore_dx4->attachObject(m_motore_dx4);

	// Creo lo SphereSceneQuery
	m_SphereSQ = m_sceneMgr->createSphereQuery( Ogre::Sphere( Vector3(0,0,0), m_SphereRange ) );

	m_RealeseCassaRQ = m_sceneMgr->createRayQuery( Ray() );
	m_RealeseCassaRQ->setSortByDistance( true );
	m_RayDistance = 1000;
	
}
		
Navicella::~Navicella () {
	m_navicella->detachAllObjects();
	delete m_entity;
	m_navicella->removeAndDestroyAllChildren();
	m_sceneMgr->destroySceneNode( m_Name );
}

bool Navicella::update( Real elapsedTime, OIS::Keyboard * p_keyboard, OIS::Mouse * p_mouse ) {

	// non sto frenando, accellerando o altro
	// questi valori possono venir modificati
	// successivamente
	ResetStates();

	ms = p_mouse->getMouseState();
	
	// decremento i toggles 
	DecreaseToggles( elapsedTime );

	// creo l'OverlayElement dove piazzare le scritte in futuro
	if ( m_OverlayToggle < 0 ) OverlayManager::getSingleton().getOverlayElement("MalusPanel")->setCaption("");

	//controllo per l'esecuzione dell'animazione per la vittoria
	if( m_Victory ) {
		SetOverlay( "Mission Accomplished!!!", 4 );
		OverlayManager::getSingleton().getOverlayElement("MalusTimer")->setCaption("Asteroid Cargo By Drowne&Telivyel");
	}


	// codice per i limiti dell'area utilizzabile
	if( ( m_navicella->getPosition().x > 11000 ) || ( m_navicella->getPosition().x < -11000 ) ) {
		m_navicella->setPosition( -m_navicella->getPosition().x, m_navicella->getPosition().y, m_navicella->getPosition().z );

	} else if( ( m_navicella->getPosition().y > 11000 ) || ( m_navicella->getPosition().y < -11000 ) ) {
		m_navicella->setPosition( m_navicella->getPosition().x, -m_navicella->getPosition().y, m_navicella->getPosition().z );

	} else if( ( m_navicella->getPosition().z > 11000 ) || ( m_navicella->getPosition().z < -11000 ) ) {
		m_navicella->setPosition( m_navicella->getPosition().x, m_navicella->getPosition().y, -m_navicella->getPosition().z );
	}

	// piazza la sfera intorno alla navicella per gestire gli eventi
	m_SphereSQ->setSphere( Ogre::Sphere( m_navicella->getPosition(), m_SphereRange) );

	if(m_CassaPresaDaSparire) {
		// se c'è una cassa da far sparire, porta avanti l'animazione
		m_Cassa->scale( 0.95, 0.95, 0.95 );	
		m_TeleCassa->scale( 1.05, 1.05, 1.05 );
		
		if( m_Cassa->getScale() < Vector3(10, 10, 10) ) { 
			m_CassaPresaDaSparire = false;
			m_sceneMgr->getRootSceneNode()->removeChild( m_Cassa );
			m_Cassa->setVisible(false);
			DetachParticle( m_Cassa, m_TelePort1 );
			DetachParticle( m_TeleCassa, m_TelePort2 );
		}
			
	}

	if(m_CassaLasciataDaSparire) {
	
		if(m_TeleCassa->getScale() > Vector3(10, 10, 10)) { 
			
			m_TeleCassa->scale( 0.95, 0.95, 0.95 );
			
		} else {
			EntSphere->setMaterialName( "green" );
			m_CassaLasciataDaSparire = false; // animazione finita
			m_CassaPresa = false; // e si può prendere un'altra cassa
			m_TeleCassa->setVisible(false);
			DetachParticle( m_TeleCassa, m_TelePort2 );
			if ( m_Victory ) return true;
		}
	
	}

	if(m_CassaBonusDaSparire) {
		
		m_Cassa->scale( 0.95, 0.95, 0.95 );
		
		if( m_Cassa->getScale() < Vector3(10, 10, 10) ) {
			m_CassaBonusDaSparire = false;
			m_CassaPresa = false;
			m_Cassa->setVisible(false);
			DetachParticle( m_Cassa, m_TelePort1 );
			m_sceneMgr->getRootSceneNode()->removeChild( m_Cassa );
		}
	}

	// codice per la deriva
	if ( m_Vel>0 ) {
		// decellera lentamente se la velocità è maggiore di 0 e non sto accellerando
		if (m_Vel>m_Deriva) {
			m_Vel -= m_Deriva;
			if(!m_Retromarcia) m_navicella->translate( m_navicella->getOrientation() * Vector3( 0, 0, m_Vel * elapsedTime ) );
		} else m_Vel = 0;
	}

	if( m_toRoll || m_toPitch ) Raddrizza( elapsedTime );

	if ( (m_StatusToggle < 0) &&( p_keyboard->isKeyDown( OIS::KC_SPACE )) ) SwitchStatus();

	if(m_BonusMalus) {
		if( (m_BonusMalusToggle > 0 ) && (m_BonusMalusToggle > 10*elapsedTime)) {
			OverlayManager::getSingleton().getOverlayElement("MalusTimer")->setCaption("Tempo Rimanente: " + StringConverter::toString( int( (m_BonusMalusToggle / 10)+1 ) ));
			m_BonusMalusToggle -= 10*elapsedTime;
		} else {
			AzzeraBonusMalus();
			OverlayManager::getSingleton().getOverlayElement("MalusTimer")->setCaption("");
		}
	}

	switch(m_Status) {
		case Navigator:
			if( m_StatusChanged && !m_BonusMalus ) {
				// imposto le variabili di navigazione
				setNavigationValues();
				m_StatusChanged = false;
			}

			if(m_BonusMalus && m_BonusMalusToggle>0 && m_StatusChanged) { 
				if(m_TurboEnabled)			SetBonusTurbo();
				if(m_SlowMotionEnabled)		SetSlowMotion();
				if(m_PigEnabled)			SetPigMalus();
				if(m_InvertedEnabled)		SetInvertedMalus();
				if(m_InvisibleEnabled)		SetInvisibleMode();

			}
				
			// accelera con il tasto SX del mouse
			if( ms.buttonDown( OIS::MB_Left ) && !m_NoControl  ){
				m_Accellerating = true; // sto accellerando
				increaseVel(); // quindi aumenta la velocità
				m_navicella->translate( m_navicella->getOrientation() * Vector3( 0, 0, getVel() * elapsedTime ) );
			}

			if( ms.buttonDown(OIS::MB_Right ) && !m_NoControl  ) {
				m_Breaking = true; // sto frenando
				decreaseVel(); // quindi diminuisci la velocità
			}

			if ( p_keyboard->isKeyDown( OIS::KC_W ) && !m_NoControl  ) m_navicella->pitch( Radian( m_PitchStrenght * elapsedTime ) );
							
			if ( p_keyboard->isKeyDown( OIS::KC_S ) && !m_NoControl  ) m_navicella->pitch( Radian( - m_PitchStrenght * elapsedTime ) );
							
			if ( p_keyboard->isKeyDown( OIS::KC_A ) && !m_NoControl  ) m_navicella->roll( Radian( - m_RollStrenght * elapsedTime ), Node::TS_LOCAL );
							
			if ( p_keyboard->isKeyDown( OIS::KC_D ) && !m_NoControl  ) m_navicella->roll( Radian( m_RollStrenght * elapsedTime ), Node::TS_LOCAL );

			if ( p_keyboard->isKeyDown( OIS::KC_H ) && (!m_BonusMalus) ) SetBonusTurbo();

			if ( p_keyboard->isKeyDown( OIS::KC_J ) && (!m_BonusMalus) ) SetInvertedMalus();
			
			if ( p_keyboard->isKeyDown( OIS::KC_L ) && (!m_BonusMalus) ) SetPigMalus();

			if ( p_keyboard->isKeyDown( OIS::KC_K ) && (!m_BonusMalus) ) SetSlowMotion();

			if ( p_keyboard->isKeyDown( OIS::KC_G ) && (!m_BonusMalus) ) SetInvisibleMode();

			break;
		
		case Precision:
			if( m_StatusChanged && !m_BonusMalus ) {
				// imposto le variabili di movimento
				setPrecisionValues();
				m_StatusChanged = false;
			}

			if(m_BonusMalus && m_BonusMalusToggle>0 && m_StatusChanged) { 
				if(m_TurboEnabled)			SetBonusTurbo();
				if(m_SlowMotionEnabled)		SetSlowMotion();
				if(m_PigEnabled)			SetPigMalus();
				if(m_InvertedEnabled)		SetInvertedMalus();
				if(m_InvisibleEnabled)		SetInvisibleMode();

			}
			
			if( !m_toRoll || !m_toPitch ) {
				if ( p_keyboard->isKeyDown( OIS::KC_W )  && !m_NoControl  )  { 
					m_Accellerating = true; // sto accellerando
					increaseVel(); // quindi aumenta la velocità
					m_navicella->translate( m_navicella->getOrientation() * Vector3( 0, 0, getVel() * elapsedTime ) );
				}
									
				if ( p_keyboard->isKeyDown( OIS::KC_S )  && !m_NoControl  )  { 
					m_Retromarcia = true;
					increaseRetroVel(); 
					m_navicella->translate( m_navicella->getOrientation() * Vector3( 0, 0, - m_RetroVel * elapsedTime ) );
				}	

				if(m_Retromarcia) {

					// se sono in retromarcia, inverti i comandi per girare
					if ( p_keyboard->isKeyDown( OIS::KC_A )  && !m_NoControl  ) m_navicella->yaw( Radian( - m_YawStrenght * elapsedTime ), Node::TS_WORLD );
										
					if ( p_keyboard->isKeyDown( OIS::KC_D )  && !m_NoControl  ) m_navicella->yaw( Radian( m_YawStrenght * elapsedTime ), Node::TS_WORLD );
				
				} else {
				
					if ( p_keyboard->isKeyDown( OIS::KC_A )  && !m_NoControl  ) m_navicella->yaw( Radian( m_YawStrenght * elapsedTime ), Node::TS_WORLD );
										
					if ( p_keyboard->isKeyDown( OIS::KC_D )  && !m_NoControl ) m_navicella->yaw( Radian( - m_YawStrenght * elapsedTime ), Node::TS_WORLD );
				}
				
				if ( p_keyboard->isKeyDown( OIS::KC_Q )  && !m_NoControl  ) m_navicella->translate( m_navicella->getOrientation() * Vector3( 0, m_VerticalVel * elapsedTime, 0 ) );
								
				if ( p_keyboard->isKeyDown( OIS::KC_E )  && !m_NoControl  ) m_navicella->translate( m_navicella->getOrientation() * Vector3( 0, - m_VerticalVel * elapsedTime, 0 ) );

				if ( p_keyboard->isKeyDown( OIS::KC_H ) && (!m_BonusMalus) ) SetBonusTurbo();

				if ( p_keyboard->isKeyDown( OIS::KC_J ) && (!m_BonusMalus) ) SetInvertedMalus();

				if ( p_keyboard->isKeyDown( OIS::KC_L ) && (!m_BonusMalus) ) SetPigMalus();

				if ( p_keyboard->isKeyDown( OIS::KC_K ) && (!m_BonusMalus) ) SetSlowMotion();

				if ( p_keyboard->isKeyDown( OIS::KC_G ) && (!m_BonusMalus) ) SetInvisibleMode();

				if( ( m_LBToggle<0 ) && ( ms.buttonDown( OIS::MB_Left )) && (!m_CassaPresa) && ( !m_NoControl ) ) {
					// accetta il comando solo se è passato un tempo sufficiente
					// e non si ha già una cassa addosso...
					m_LBToggle = 3;

					SceneQueryResult & m_ResultSQ = m_SphereSQ->execute(); 

					SceneQueryResultMovableList::iterator it = m_ResultSQ.movables.begin();
					for( ; it != m_ResultSQ.movables.end(); it++ ) {

						if( ( ( *it )->getQueryFlags() == MOVABLE_OBJECT ) && (!m_CassaPresa) ) {
							std::cout << "Cassa" << std::endl;
							m_CassaPresa = true;
							m_CassaPresaDaSparire = true;
							m_Cassa = ( *it )->getParentSceneNode();
							
							// attiva il teletrasporto
							AttachParticle( m_TeleCassa, m_TelePort2 );
							m_TempCassa = m_Cassa->createChildSceneNode(Vector3::ZERO);
							AttachParticle( m_Cassa, m_TelePort1 );

							// fai apparire la cassa nel teletrasporto davanti la navicella
							m_GhostCassa->setVisible(true);
										
						}

						if( ( ( *it )->getQueryFlags() == TURBO_MALUS ) && (!m_CassaPresa) ) {
							std::cout << "Turbo" << std::endl;
							m_BonusMalusToggle = 100;
							
							if(!m_BonusMalus) SetBonusTurbo();
							else {
								AzzeraBonusMalus();
								SetBonusTurbo();
							}

							m_CassaBonusDaSparire = true;
							m_CassaPresa = true;
							m_Cassa = ( *it )->getParentSceneNode();

							m_TempCassa = m_Cassa->createChildSceneNode(Vector3::ZERO);
							AttachParticle( m_Cassa, m_TelePort1 );

							
						}

						if( ( ( *it )->getQueryFlags() == SLOWMOTION_MALUS ) && (!m_CassaPresa) ) {
							std::cout << "Slow" << std::endl;
							m_BonusMalusToggle = 100;
														
							if(!m_BonusMalus) SetSlowMotion();
							else {
								AzzeraBonusMalus();
								SetSlowMotion();
							}

							m_CassaBonusDaSparire = true;
							m_CassaPresa = true;
							m_Cassa = ( *it )->getParentSceneNode();

							m_TempCassa = m_Cassa->createChildSceneNode(Vector3::ZERO);
							AttachParticle( m_Cassa, m_TelePort1 );

									
						}

						if( ( ( *it )->getQueryFlags() == PIG_MALUS ) && (!m_CassaPresa) ) {
							std::cout << "Pig" << std::endl;
							m_BonusMalusToggle = 100;
																					
							if(!m_BonusMalus) SetPigMalus();
							else {
								AzzeraBonusMalus();
								SetPigMalus();
							}

							m_CassaBonusDaSparire = true;
							m_CassaPresa = true;
							m_Cassa = ( *it )->getParentSceneNode();

							m_TempCassa = m_Cassa->createChildSceneNode(Vector3::ZERO);
							AttachParticle( m_Cassa, m_TelePort1 );

								
						}

						if( ( ( *it )->getQueryFlags() == INVERTED_MALUS ) && (!m_CassaPresa) ) {
							std::cout << "Inverted" << std::endl;
							m_BonusMalusToggle = 100;

							if(!m_BonusMalus) SetInvertedMalus();
							else {
								AzzeraBonusMalus();
								SetInvertedMalus();
							}
							
							m_CassaBonusDaSparire = true;
							m_CassaPresa = true;
							m_Cassa = ( *it )->getParentSceneNode();

							m_TempCassa = m_Cassa->createChildSceneNode(Vector3::ZERO);
							AttachParticle( m_Cassa, m_TelePort1 );

									
						}

						if( ( ( *it )->getQueryFlags() == INVISIBLE_MALUS ) && (!m_CassaPresa) ) {
							
							std::cout << "Invisible" << std::endl;
							m_BonusMalusToggle = 100;

							if(!m_BonusMalus) SetInvisibleMode();
							else {
								AzzeraBonusMalus();
								SetInvisibleMode();
							}

							m_CassaBonusDaSparire = true;
							m_CassaPresa = true;
							m_Cassa = ( *it )->getParentSceneNode();

							m_TempCassa = m_Cassa->createChildSceneNode(Vector3::ZERO);
							AttachParticle( m_Cassa, m_TelePort1 );

							
						}
									
					}

				}
				//routine per il deposito di una cassa
				if( ( ms.buttonDown( OIS::MB_Right ) ) && ( m_CassaPresa ) && ( !m_CassaLasciataDaSparire ) && ( !m_NoControl ) ) {
					
					m_RealeseCassaRQ->setRay( Ogre::Ray( m_navicella->getPosition(), m_navicella->getOrientation().zAxis() ));

					RaySceneQueryResult &result = m_RealeseCassaRQ->execute();

					RaySceneQueryResult::iterator itr = result.begin();
						//scorro la lista di risultati della query
					for( ; itr != result.end(); itr++ ) {
						//controllo il flag della query
						if( ( * itr ).movable->getQueryFlags() == MISSION_OBJECT ) {

							//verifico la distanza dall'oggetto intersecato dal raggio
							float distance;
							distance = m_navicella->getWorldPosition().distance( ( * itr ).movable->getParentSceneNode()->getWorldPosition() );
							std::cout << distance << std::endl;
							if( distance < m_RayDistance ) {
								String NodeName = ( * itr ).movable->getParentSceneNode()->getName();
								EntSphere = m_sceneMgr->getEntity( "SphereEnt" + NodeName );
								m_CassaLasciataDaSparire = true;

								AttachParticle( m_TeleCassa, m_TelePort2 );
								//EntSphere->setMaterialName( "green" ); // ora fa parte dell'animazione

								EntSphere->removeQueryFlags( MISSION_OBJECT );
								m_MissionObjects[ Ogre::StringConverter().parseInt( NodeName ) ] = false;;
								//std::cout << Ogre::StringConverter().parseInt( NodeName ) << std::endl;	

								//controllo se ho riportato tutte le casse
								checkVictory();
							}
						}
						

					}
				}

			}
			break;
		
		default:
			break;
	}
	
	return false;
		
}
//routine per il controllo della vittoria
void Navicella::checkVictory() {
	bool check = true;
	for( int i = 0; i < 24; i++ ) {
		if( m_MissionObjects[i] ) 
			check = false;
	}
	if( check )
		m_Victory = true;
}


void Navicella::increaseVel() {
	// se sono in accellerazione, controlla di non aver superato il limite e accellera
	if( m_Vel<m_MaxVel ) { 
		m_Vel += m_IncrVel; 
	} else {
	// se ho superato il limite imposta la massima velocità possibile
	m_Vel = m_MaxVel; 
	}
}

void Navicella::decreaseVel() {	
	if ( m_Vel>m_Frenata ) {
		m_Vel -= m_Frenata;
	}
	else 
		m_Vel = 0;			
}

void Navicella::increaseRetroVel() {
	if( m_RetroVel<m_MaxRetroVel) { 
		m_RetroVel += m_IncrRetroVel; 
	} else {
	// se ho superato il limite imposta la massima velocità possibile
	m_RetroVel = m_MaxRetroVel; 
	}
}

double Navicella::Approssimate( double d ) {
	
	if( d >= 0 ) {
		
		if( (int)((d-(int)d)*10)<=4 ) return Math::Floor( d );
		else return Math::Ceil( d );

	} else { 
		
		if( ((int)((d-(int)d)*10))>=-4 ) return Math::Ceil( d );
		else return Math::Floor( d );
					
	}
		
}

void Navicella::Raddrizza( Real elapsedTime ) {

	// slerp interpolation

	m_ActualPitch = ( m_navicella->getOrientation().getPitch() ).valueDegrees();
	m_ActualRoll = ( m_navicella->getOrientation().getRoll() ).valueDegrees();

	// calcola i valori approssimati
	m_ActualPitchInt = Approssimate( m_ActualPitch );
	m_ActualRollInt = Approssimate( m_ActualRoll );

	if( m_toRoll ) {
		if( m_ActualRoll < 0 ) {
			m_navicella->roll( Radian( m_RollStrenght * elapsedTime ), Node::TS_LOCAL );
			if( m_navicella->getOrientation().getRoll().valueDegrees() >= 0 ) {
				m_toRoll = false;
			}
		} else {
			m_navicella->roll( Radian( - m_RollStrenght * elapsedTime ), Node::TS_LOCAL );
			if( m_navicella->getOrientation().getRoll().valueDegrees() <= 0 ) {
				m_toRoll = false;
			}
		}
	}

	if( m_toPitch && !m_toRoll ) {
		if ( ( m_navicella->getOrientation().getRoll().valueDegrees() <= -176 ) || ( m_navicella->getOrientation().getRoll().valueDegrees() >= 176 ) ) {
			if( (m_ActualPitch < 0) ) {
				m_navicella->pitch( Radian( - m_PitchStrenght * elapsedTime ), Node::TS_LOCAL );
				if( m_navicella->getOrientation().getPitch().valueDegrees() >= 0 ){
					m_toPitch = false;
				}
			} else {
				m_navicella->pitch( Radian( m_PitchStrenght * elapsedTime ), Node::TS_LOCAL );
				if( m_navicella->getOrientation().getPitch().valueDegrees() <= 0 ) {
					m_toPitch = false;
				}
			}
		} else {
			if( (m_ActualPitch < 0) ) {
				m_navicella->pitch( Radian( m_PitchStrenght * elapsedTime ), Node::TS_LOCAL );
				if( m_navicella->getOrientation().getPitch().valueDegrees() >= 0 ){
					m_toPitch = false;
				}
			} else {
				m_navicella->pitch( Radian( - m_PitchStrenght * elapsedTime ), Node::TS_LOCAL );
				if( m_navicella->getOrientation().getPitch().valueDegrees() <= 0 ) {
					m_toPitch = false;
				}
			}
		}
	}

	if( !m_toPitch && !m_toRoll) m_NoControl = false;	
}

void Navicella::setNavigationValues() {
		
	m_IncrVel		= 10;
	m_MaxVel		= 1200;
	m_MaxRetroVel	= 200;
	m_VerticalVel	= 200;
	m_Frenata		= 20;
	m_Deriva		= 0;
	m_PitchStrenght = 2;
	m_RollStrenght	= 2;
	m_YawStrenght	= 2;

}

void Navicella::setPrecisionValues() {

	m_IncrVel		= 50;
	m_MaxVel		= 100;
	m_MaxRetroVel	= 100;
	m_VerticalVel	= 200;
	m_Frenata		= 20;
	m_Deriva		= 30;
	m_PitchStrenght = 2;
	m_RollStrenght	= 2;
	m_YawStrenght	= 2;

}

void Navicella::SetBonusTurbo() {

	if(!m_TurboEnabled) {

	   	SetOverlay( "TURBO!", 10 );
	   	// attiva i secondi particle per il turbo

		AttachParticle( m_TurboSxNode, m_TurboSx );
		AttachParticle( m_TurboDxNode, m_TurboDx );

	}

	m_BonusMalus = true;
	m_TurboEnabled = true;

	if(m_BonusMalusToggle == 0) m_BonusMalusToggle = 100;

	switch(m_Status) {
		case Navigator:
			setMaxVel(2000);
			setMaxRetroVel(600);
			m_PitchStrenght = 4;
			m_RollStrenght = 4;
			m_YawStrenght = 4;
			break;
		
		case Precision:
			setMaxVel(400);
			setMaxRetroVel(300);
			m_YawStrenght = 4;
			setVerticalVel(400);
			break;
		
		default:
			break;
	}

}

void Navicella::SetInvertedMalus() {

	if(!m_InvertedEnabled) SetOverlay( "DRUNK MODE!", 10 );
	
	m_BonusMalus = true;
	m_InvertedEnabled = true;

	if(m_BonusMalusToggle == 0) m_BonusMalusToggle = 100;

		switch(m_Status) {
			case Navigator:
				setMaxVel(1200);
				setMaxRetroVel(200);
				m_PitchStrenght = -2;
				m_RollStrenght = -2;
				m_YawStrenght = -2;
				break;
			
			case Precision:
				setMaxVel(100);
				setMaxRetroVel(100);
				m_YawStrenght = -2;
				setVerticalVel(200);
				break;
			
			default:
				break;
	}

		
}

void Navicella::SetPigMalus() {
	
	if(!m_PigEnabled) {
				
		SetOverlay( "SEI STATO MAIALATO!", 10 );
		m_navicella->setVisible( false );
		m_Pig->setVisible(true);
	
	}
		
	m_BonusMalus = true;
	m_PigEnabled = true;
	m_NoControl	 = true;

	switch(m_Status) {
		case Navigator:
			setMaxVel(1200);
			setMaxRetroVel(200);
			m_PitchStrenght = 2;
			m_RollStrenght = 2;
			m_YawStrenght = 2;
			break;
		
		case Precision:
			setMaxVel(100);
			setMaxRetroVel(100);
			m_YawStrenght = 2;
			setVerticalVel(200);
			break;
		
		default:
			break;
	}
		
	if(m_BonusMalusToggle == 0) m_BonusMalusToggle = 100;
}

void Navicella::SetSlowMotion() {
	
	if(!m_SlowMotionEnabled) {
		
		SetOverlay( "POWER LOSS!", 10 );
		m_Nodemotore_dx2->setVisible(false);
		m_Nodemotore_dx3->setVisible(false);
		m_Nodemotore_dx4->setVisible(false);

		m_Nodemotore_sx2->setVisible(false);
		m_Nodemotore_sx3->setVisible(false);
		m_Nodemotore_sx4->setVisible(false);
   
	}

	m_BonusMalus = true;
	m_SlowMotionEnabled = true;
		
	if(m_BonusMalusToggle == 0)	m_BonusMalusToggle = 100;

 	
	switch(m_Status) {
		case Navigator:
			setMaxVel(400);
			setMaxRetroVel(100);
			m_PitchStrenght = 1;
			m_RollStrenght = 1;
			m_YawStrenght = 1;
			break;
		
		case Precision:
			setMaxVel(50);
			setMaxRetroVel(50);
			m_YawStrenght = 1;
			setVerticalVel(50);
			break;						 
		
		default:
			break;

	}
}

void Navicella::SetInvisibleMode() {
	
	if(!m_InvisibleEnabled) { 
		m_navicella->rotate( Vector3( 0, 0, 1), Radian ( Degree(180) )); 
		SetOverlay( "CRAZY BLINDNESS!", 10 );
		m_navicella->setVisible(false);
	}
	
	m_BonusMalus = true;
	m_InvisibleEnabled = true;
	
	if(m_BonusMalusToggle == 0)	m_BonusMalusToggle = 100;

		switch(m_Status) {
			case Navigator:
				setMaxVel(1200);
				setMaxRetroVel(200);
				m_PitchStrenght = 2;
				m_RollStrenght = 2;
				m_YawStrenght = 2;
				break;
			
			case Precision:
				setMaxVel(100);
				setMaxRetroVel(100);
				m_YawStrenght = 2;
				setVerticalVel(200);
				break;
			
			default:
				break;
	}



}

void Navicella::SwitchStatus() {
			
	m_StatusToggle = 2;
	m_StatusChanged = true;
		
	if(m_Status==Navigator) {

		m_Status				= Precision;
		m_toRoll				= true;
		m_toPitch				= true;
		// non accettare altri imput fino alla fine del riposizionamento
		m_NoControl = true;
		SetOverlay( "Precision Mode", 2 );
					
		} else {
			m_Status = Navigator;
			SetOverlay( "Navigator Mode", 2 );
		}
}

void Navicella::AzzeraBonusMalus() {
	
	m_BonusMalusToggle = 0;
	
	if(m_TurboEnabled) {
		m_TurboEnabled = false;
		DetachParticle( m_TurboDxNode, m_TurboDx  );
		DetachParticle( m_TurboSxNode, m_TurboSx );
	} 
	
	if(m_PigEnabled) {
		m_PigEnabled = false;
		m_navicella->setVisible(true);
		m_Pig->setVisible(false);
		m_NoControl = false;

		if(!m_CassaPresa) m_TeleCassa->setVisible(false);
	}

	if(m_SlowMotionEnabled) {
		m_SlowMotionEnabled = false;
	
		m_Nodemotore_dx2->setVisible(true);
		m_Nodemotore_dx3->setVisible(true);
		m_Nodemotore_dx4->setVisible(true);

		m_Nodemotore_sx2->setVisible(true);
		m_Nodemotore_sx3->setVisible(true);
		m_Nodemotore_sx4->setVisible(true);
	}

	if(m_InvisibleEnabled) {
		m_navicella->setVisible(true);
		m_Pig->setVisible(false);
		
		if(!m_CassaPresa) m_GhostCassa->setVisible(false);
		
		m_InvisibleEnabled = false;
	}
	
	m_InvertedEnabled		= false;
	m_BonusMalus			= false;
	m_StatusChanged			= true;

}

void Navicella::ResetStates() {
	m_Accellerating		= false;	
	m_Breaking			= false;
	m_Retromarcia		= false;
}

void Navicella::DecreaseToggles( Real e ) {
	m_StatusToggle	-= e;
	m_LBToggle		-= e;
	m_OverlayToggle -= e;
}

void Navicella::AttachParticle( SceneNode * n, ParticleSystem * p) {

	n->detachAllObjects();
	n->attachObject(p);
	n->setVisible(true);
}

void Navicella::DetachParticle( SceneNode * n, ParticleSystem * p ) {
	
	p->clear();
	n->detachObject( p );
	
}

void Navicella::SetOverlay( String s, Real r ) {
	OverlayManager::getSingleton().getOverlayElement("MalusPanel")->setCaption(s);
	m_OverlayToggle = r;
}

// metodi per il get&set delle variabili della classe

int Navicella::getVel() {
	return m_Vel; 
}

void Navicella::setVel( int v ) {
	m_Vel = v;
}

int Navicella::getDeriva() {
	return m_Deriva;
}

void Navicella::setDeriva( int d ) {
	m_Deriva = d;
}

bool Navicella::getAccellerating() {
	return m_Accellerating;
}

void Navicella::setAccellerating(bool a) {
	m_Accellerating = a;
}

int Navicella::getIncrVel() {
	return m_IncrVel;
}

void Navicella::setIncrVel(int i) {
	m_IncrVel = i;
}

int Navicella::getMaxVel() {
	return m_MaxVel;
}

void Navicella::setMaxVel(int i) {
	m_MaxVel = i;
}

bool Navicella::getBreaking() {
	return m_Breaking;
}

void Navicella::setBreaking(bool b) {
	m_Breaking = b;
}

int Navicella::getBreakStrenght() {
	return m_Frenata;
}

void Navicella::setBreakStrenght(int b) {
	m_Frenata = b;
}

int Navicella::getPitchStrenght() {
	return m_PitchStrenght;
}

void Navicella::setPitchStrenght(int p) {
	m_PitchStrenght = p;
}

int Navicella::getRollStrenght() {
	return m_RollStrenght;
}

void Navicella::setRollStrenght(int r) {
	m_RollStrenght = r;
}

int Navicella::getYawStrenght() {
	return m_YawStrenght;
}

void Navicella::setYawStrenght(int y) {
	m_YawStrenght = y;
}

int Navicella::getVerticalVel() {
	return m_VerticalVel;
}

void Navicella::setVerticalVel(int v) {
	m_VerticalVel = v;
}

bool Navicella::getRetro() {
	return m_Retromarcia;
}

void Navicella::setRetro(bool r) {
	m_Retromarcia = r;
}

int Navicella::getRetroVel() {
	return m_RetroVel;
}

void Navicella::setRetroVel(int r) {
	m_RetroVel = r;
}

int Navicella::getIncrRetroVel() {
	return m_IncrRetroVel;
}

void Navicella::setIncrRetroVel(int i) {
	m_IncrRetroVel = i;
}

int Navicella::getMaxRetroVel() {
	return m_MaxRetroVel;
}

void Navicella::setMaxRetroVel(int m) {
	m_MaxRetroVel = m;
}