#include "../include/zf.h"

#define PICKUP_RADIUS 0.2f
#define PICKUP_SPEED 0.4f

typedef enum {HEALTH1, HEALTH2, LIFE, INVINCIBLE} PickupType;

typedef struct Pickup Pickup;

struct Pickup
{
    unsigned int ref_count;
    CLvertex position;

    PickupType type;
    
    bool valid;
};

static ZfSmartPointer smart_pointer; 
static ZfDynamicCollider dynamic_collider;

static CLcontext* context;
static CLmodel* model_battery;

static bool
is_valid(const Pickup* pickup)
{
   return pickup->valid;
}

static void
reference(Pickup* pickup)
{
    pickup->ref_count++;
}

static void
release(Pickup* pickup)
{
    pickup->ref_count--;

    if (pickup->ref_count == 0)
	g_free(pickup);
}


static void
animate(Pickup* pickup)
{
    CLvertex ship_pos;
    CLnormal velocity;
    
    zf_ship_query_position(&ship_pos);
    
    cluNormalDifference(&velocity, &ship_pos, &pickup->position);
    cluNormalNormalise(&velocity);
    
    cluNormalScale(&velocity, PICKUP_SPEED); /* speed hack */
    
    cluVertexAdd(&pickup->position, &velocity);
}

static void
render(Pickup* pickup)
{
    /* render the model here?*/
    glPushAttrib(GL_ALL_ATTRIB_BITS);
    glDisable(GL_LIGHTING);

    glPushMatrix();
    glTranslatef(pickup->position.x,
		 pickup->position.y,
		 pickup->position.z);

    switch(pickup->type)
    {
    case HEALTH1:
	glColor3f(0.8f, 0.4f, 0.3f);
	glEnable(GL_LIGHTING);
	glEnable(GL_COLOR_MATERIAL);
	clRenderModel(model_battery);
	break;
    case HEALTH2:
	glColor3f(0.4f, 0.3f, 0.8f);
	glEnable(GL_LIGHTING);
	glEnable(GL_COLOR_MATERIAL);
	clRenderModel(model_battery);
	break;
    case LIFE:
	glColor3f(0.4f, 0.7f, 0.8f);
	glutSolidSphere(PICKUP_RADIUS, 8, 8);
	break;
    case INVINCIBLE:
	glColor3f(0.4f, 0.7f, 0.8f);
	glutSolidSphere(PICKUP_RADIUS, 8, 8);
	break;
    }

    glPopMatrix();

    glPopAttrib();
}

static void
query_position(Pickup* pickup,
	       CLvertex* position)
{
    clCopyVertex(position, &pickup->position);
}

static void
collision_response(Pickup* pickup,
		   const void* collider_data,
		   ZfType collider_type,
		   const CLvertex* collision_position,
		   const CLnormal* collision_force_perp,
		   const CLnormal* collision_force_tan)
{
    if(collider_type & ZF_SHIP)
    {
	pickup->valid = false;
	switch(pickup->type)
	{
	case HEALTH1:
	    zf_ship_increase_power(0.25f);
	    break;
	case HEALTH2:
	    zf_ship_increase_power(0.5f);
	    break;
	case LIFE:
	    zf_ship_increment_life();
	    break;
	case INVINCIBLE:
	    zf_ship_super_battery_mode();
	    break;
	}
    }
}

void
zf_drone_pickup_init(void)
{
    smart_pointer.is_valid = (ZfIsValid*) is_valid;
    smart_pointer.reference = (ZfReference*) reference;
    smart_pointer.release = (ZfRelease*) release;

    dynamic_collider.query_position = 
	(ZfQueryPosition*) query_position;

    dynamic_collider.collision_response =
	(ZfCollisionResponse*)collision_response;
 

    context = clDefaultContext(clNewContext());
    model_battery = clioLoadModel(context, "../data/models/battery/battery.3DS");

    /* not clean to just exit, but use this until we have a good error
       system */
    if (!model_battery)
    {
	printf("could not load drone model\n");
	exit(1);
    }

    cluModelCentre(model_battery); 
    cluModelScaleUnitCube(model_battery);
    clUpdateContext(context);
}

void
zf_drone_pickup_close(void)
{
    /* model later maybe ?*/
}


/*! \todo remove magic numbers! (type = 0, 1, 2, 3) */
void
zf_drone_pickup_new(int type, const CLvertex* position)
{
    Pickup* pickup;
    
    pickup = g_new(Pickup, 1);
    
    pickup->ref_count = 0;
    pickup->valid = true;
    clCopyVertex(&pickup->position, position);
    
    switch(type)
    {
    case 0:
	pickup->type = HEALTH1;
	break;
    case 1:
	pickup->type = HEALTH2;
	break;
    case 2:
	pickup->type = LIFE;
	break;
    case 3:
	pickup->type = INVINCIBLE;
	break;
    }
    
    
    zf_animation_system_add(pickup,
			    &smart_pointer,
			    (ZfAnimate*) animate);
    
    zf_collision_system_add_dynamic(pickup,
				    &smart_pointer,
				    &dynamic_collider,
				    ZF_DRONE_PICKUP,
				    1.0f, /* mass */
				    PICKUP_RADIUS); /* radius */

    zf_render_system_add_opaque(pickup,
				&smart_pointer,
				(ZfRender*) render);
}

