#include <iostream>

#include "EntityBase.h"
#include "coll2d.h"

#include "EntityFactory.h"
#include "ShipEntity.h"
#include "RocketEntity.h"
#include "AsteroidEntity.h"

namespace asteroids {

int EntityFactory::OnInit (int argc, char* argv[]) {
	Engine::LogMessage ("Initializing EntityFactory");

	return 0;
}

Engine::EntityPhysicState* EntityFactory::CreateEntityPhysicState (int type) {
	// In this simple factory the type is simply seen as the EntityBaseType.
	// However to prevent errors we do a simple check vor validity.
	if (type < 0 || type > GameEntityTypeLast ) {
		Engine::LogError ("Cannot create Entity with type %d: invalid type!", type);
	}

	// Create the Entity
	Engine::EntityPhysicState* entity_physics = NULL;

	// type specific initialization
	if (type == GameEntityTypeShip) {
		entity_physics = new ShipEntityPhysicState ();
		if (!entity_physics) {
			Engine::LogError ("Could not allocate enough memory for EntityPhysicState of type '%d'", type);
		}
		entity_physics->mRadius = 0.5;
		entity_physics->mShape = new coll2d::Sphere (entity_physics->mRadius);

		assert (entity_physics->mShape);
	} else if (type == GameEntityTypeAsteroid) {
		entity_physics = new AsteroidEntityPhysicState ();
		if (!entity_physics) {
			Engine::LogError ("Could not allocate enough memory for EntityPhysicState of type '%d'", type);
		}
		
		entity_physics->mRadius = 1.;
		entity_physics->mShape = new coll2d::Sphere (entity_physics->mRadius);

		assert (entity_physics->mShape);
	} else if (type == GameEntityTypeRocket) {
		entity_physics = new RocketEntityPhysicState();
		if (!entity_physics) {
			Engine::LogError ("Could not allocate enough memory for EntityPhysicState of type '%d'", type);
		}
		entity_physics->mRadius = 0.1;
		entity_physics->mShape = new coll2d::Sphere (entity_physics->mRadius);
	} else if (type == GameEntityTypeShipPart) {
		entity_physics = new RocketEntityPhysicState();
		entity_physics->mBaseType = Engine::EntityBaseTypeBlock;
		if (!entity_physics) {
			Engine::LogError ("Could not allocate enough memory for EntityPhysicState of type '%d'", type);
		}
		entity_physics->mRadius = 0.1;
		entity_physics->mShape = new coll2d::Sphere (entity_physics->mRadius);
	} else {
		Engine::LogError ("No EntityPhysicState defined for GameEntity type '%d'", type);
	}

	entity_physics->mType = type;

	return entity_physics;
}

Engine::EntityControllerState* EntityFactory::CreateEntityControllerState (int type) {
	// In this simple factory the type is simply seen as the EntityBaseType.
	// However to prevent errors we do a simple check vor validity.
	if (type < 0 || type >> Engine::EntityBaseTypeLast ) {
		Engine::LogError ("Cannot create Entity with type %d: invalid type!", type);
	}
	
	// Create the Entity
	Engine::EntityControllerState* entity_controller = NULL;

	// specific values for each type
	if (type == GameEntityTypeShip) {
		entity_controller = new Engine::EntityControllerState ();
		if (!entity_controller) {
			Engine::LogError ("Could not allocate enough memory for EntityControllerState of type '%d'", type);
		}
	}

	return entity_controller;
}

Engine::EntityBase* EntityFactory::CreateEntity (int type) {
	// In this simple factory the type is simply seen as the EntityBaseType.
	// However to prevent errors we do a simple check vor validity.
	if (type < 0 || type > GameEntityTypeLast ) {
		Engine::LogError ("Cannot create Entity with type %d: invalid type!", type);
	}

	// Create the Entity
	Engine::EntityBase *entity;

	if (type == GameEntityTypeShip) {
		entity = new ShipEntity;
	} else if (type == GameEntityTypeAsteroid) {
		entity = new AsteroidEntity;
	} else if (type == GameEntityTypeRocket) {
		entity = new RocketEntity;
	} else if (type == GameEntityTypeShipPart) {
		entity = new Engine::EntityBase;
		entity->mBaseType = Engine::EntityBaseTypeBlock;
	}

	entity->mType = type;

	if (!entity) {
		Engine::LogError ("Could not allocate enough memory for EntityVisualState of type '%d'", type);
	}

	entity->mPhysicState = CreateEntityPhysicState (type);
	entity->mControllerState = CreateEntityControllerState (type);

	return entity;
}

}


