#include "Engine.h"

#include "Model.h"

#include "ShipEntity.h"
#include "RocketEntity.h"
#include "Controller.h"
#include "AsteroidsEvents.h"

#include "coll2d.h"

namespace asteroids {

Engine::Variable ShipEntity::VarAcceleration ("ship_acceleration", "10");
Engine::Variable ShipEntity::VarMaxSpeed ("ship_maxspeed", "10");
Engine::Variable ShipEntity::VarRotationSpeed ("ship_rotationspeed", "180");
Engine::Variable ShipEntity::VarMaxAttackRate ("ship_maxattackrate", "10");

void ShipEntity::Update (float delta_sec) {
	if (!mPhysicState || !mControllerState)
		return;

	mState = Idle;

	// the local velocity
	vector3d local_velocity = mPhysicState->mVelocity;
	mPhysicState->LocalizeRotation (local_velocity);

	// set the local velocity as the current state of the keys are
	if (mControllerState->GetKey (EntityKeyStateForward)) {
		local_velocity[0] += delta_sec * ShipEntity::VarAcceleration.GetFloatValue();
		mState = Accelerating;
	}

	// now transform these to global velocities
	mPhysicState->GlobalizeRotation (local_velocity);

	// now we can update the new global velocity
	mPhysicState->SetVelocity(local_velocity);

	if (mControllerState->GetKey (EntityKeyStateTurnLeft)) {
		mPhysicState->mOrientation[1] += delta_sec * ShipEntity::VarRotationSpeed.GetFloatValue();
	}
	if (mControllerState->GetKey (EntityKeyStateTurnRight)) {
		mPhysicState->mOrientation[1] -= delta_sec * ShipEntity::VarRotationSpeed.GetFloatValue();
	}

	// Check for the maximum speed
	float speed = mPhysicState->mVelocity.length();
	if (speed > ShipEntity::VarMaxSpeed.GetFloatValue()) {
		mPhysicState->mVelocity *= ShipEntity::VarMaxSpeed.GetFloatValue() / speed;
	}

	// update the attack timer if neccessary
	if (mAttackTimer > 0.)
		mAttackTimer -= delta_sec;
}

bool ShipEntity::CollisionEvent (Engine::EntityBase* entity, vector3d point, vector3d normal) {
	GameEntityType other_type = (GameEntityType) entity->mType;

	if (other_type == GameEntityTypeAsteroid) {
		Engine::LogMessage ("You died!");

		mPhysicState->mStatic = true;
		mState = Dying;

		Engine::EventBasePtr explode_event (new Engine::EventBase());
		explode_event->mEventType = EventShipExplode;
		explode_event->mEventUnsignedInt = mId;
		explode_event->mVector3d = mPhysicState->mVelocity - entity->mPhysicState->mVelocity;
		QueueEvent (explode_event);

		return true;
	} else if (other_type == GameEntityTypeRocket) {
		Engine::LogMessage ("You just killed yourself!");

		mPhysicState->mStatic = true;
		mState = Dying;

		Engine::EventBasePtr explode_event (new Engine::EventBase());
		explode_event->mEventType = EventShipExplode;
		explode_event->mEventUnsignedInt = mId;
		explode_event->mVector3d = mPhysicState->mVelocity - entity->mPhysicState->mVelocity;
		QueueEvent (explode_event);

		return true;
	}

	return false;
}

void ShipEntity::Attack () {
	if (!mAlive)
		return;

	// skip the attack if we still have to wait
	if (mAttackTimer > 0.)
		return;

	mAttackTimer = 1. / ShipEntity::VarMaxAttackRate.GetFloatValue();

	Engine::EntityPhysicState* entity_physic = Engine::GetEntityPhysicState (mId);
	vector3d attack_dir (1., 0., 0.);

	entity_physic->GlobalizeRotation (attack_dir);

	RocketEntity *rocket_entity = (RocketEntity*) Engine::CreateEntity (GameEntityTypeRocket);

	rocket_entity->mSecToLive = RocketEntity::VarTimeToLive.GetFloatValue();

	RocketEntityPhysicState *rocket_physics = (RocketEntityPhysicState*) rocket_entity->mPhysicState;
	rocket_physics->mPosition = attack_dir;
	rocket_physics->mPosition *= mPhysicState->mRadius;
	rocket_physics->mPosition += entity_physic->mPosition;
	rocket_physics->mOrientation = entity_physic->mOrientation;
	rocket_physics->mVelocity = attack_dir.normalize();
	rocket_physics->mVelocity *= RocketEntity::VarSpeed.GetFloatValue();

	Engine::PlaySound (Engine::GetResourceFullPath("/data/sounds/laser.wav"));	
}

}
