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

#define DECOY_LIFESPAN 300
#define DECOY_RADIUS_RANGE 10.0f
/* Size of decoy model */
#define DECOY_RADIUS 0.3f 
#define DECOY_TRAVEL_SPEED 0.2f

typedef struct Decoy Decoy;

struct Decoy
{
    unsigned int ref_count;
    int age;
    
    float radius;

    CLvertex position;
    CLnormal direction;
};

static ZfSmartPointer smart_pointer0; 
static ZfSmartPointer smart_pointer1; 
static ZfDynamicCollider dynamic_collider;

static bool
is_valid(Decoy* decoy)
{
    return decoy->age < DECOY_LIFESPAN;
}

static bool
explode_is_valid(Decoy* decoy)
{
    return decoy->radius < DECOY_RADIUS_RANGE;
}

static void
reference(Decoy* decoy)
{
    decoy->ref_count++;
}

static void
release(Decoy* decoy)
{
    decoy->ref_count--;

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


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

static void
collision_response(Decoy* decoy,
		   const void* collider_data,
		   ZfType collider_type,
		   const CLvertex* collision_position,
		   const CLnormal* collision_force)
{

    /* Do nothing?*/
    
}

static bool
query_collision(Decoy* decoy,
		const CLUsphere* sphere,
		const CLnormal* force,
		CLvertex* collision_position,
		CLnormal* collision_force_perp,
		CLnormal* collision_force_tan)
{
    float dist;

    dist = cluVertexDistance(&sphere->origin,
			     &decoy->position);
    if(dist < (sphere->radius + DECOY_RADIUS_RANGE))
    {
	return true;
    }
    return false;
}

static void
step(Decoy* decoy)
{
    decoy->radius+=0.2f;
}

static void
render_explode(Decoy* decoy)
{
    float t;

    glPushAttrib(GL_ALL_ATTRIB_BITS);

    glDisable(GL_LIGHTING);
    glDisable(GL_TEXTURE_2D);
    glEnable(GL_DEPTH_TEST);

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    t = 1.0f - (float)decoy->radius/DECOY_RADIUS_RANGE;
    
    glColor4f(0.8f + 0.2f * t, 
	      0.2f,
	      0.2,
	      t);
	
    /*glColor3f(0.0f, 0.5f*t, 0.5f*t);*/
    glPushMatrix();
    glTranslatef(decoy->position.x,
		 decoy->position.y,
		 decoy->position.z);
    
    glutSolidSphere(decoy->radius, 8, 8); 
        
    glPopMatrix();
    
    glPopAttrib();
}

static void
animate(Decoy* decoy)
{
    decoy->age++;
    if(!is_valid(decoy))
    {
	zf_animation_system_add(decoy,
				&smart_pointer1,
				(ZfAnimate*)step);
	
	zf_render_system_add_translucent(decoy,
					 &smart_pointer1,
					 (ZfRender*)render_explode);

	zf_collision_system_add_static(decoy,
				       &smart_pointer1,
				       (ZfQueryCollision*)query_collision,
				       ZF_DECOY_EXPLODED); 
    } 
    else
	cluVertexAdd(&decoy->position, &decoy->direction);
}

static void
render(Decoy* decoy)
{
    glPushAttrib(GL_ALL_ATTRIB_BITS);

    glDisable(GL_LIGHTING); 
    glEnable(GL_DEPTH_TEST);

    glColor3f(0.5f, 0.8f, 0.4f);
    glPushMatrix();
    glTranslatef(decoy->position.x,
		 decoy->position.y,
		 decoy->position.z);
    
    glutSolidSphere(DECOY_RADIUS, 8, 8); 
    glutWireSphere(DECOY_RADIUS_RANGE, 8, 8); 
    
    glPopMatrix();
    
    glPopAttrib();
}


void
zf_decoy_init(void)
{
    smart_pointer0.is_valid = (ZfIsValid*) is_valid;
    smart_pointer0.reference = (ZfReference*) reference;
    smart_pointer0.release = (ZfRelease*) release;

    smart_pointer1.is_valid = (ZfIsValid*) explode_is_valid;
    smart_pointer1.reference = (ZfReference*) reference;
    smart_pointer1.release = (ZfRelease*) release;

    dynamic_collider.query_position = (ZfQueryPosition*) query_position;
    dynamic_collider.collision_response = (ZfCollisionResponse*) collision_response;
}

void
zf_decoy_close(void)
{
    /* nothing atm - texture later? */
}


void
zf_decoy_new(CLvertex* ship_pos,
	     CLnormal* direction)
{
    Decoy* decoy;

    decoy = g_new(Decoy, 1);

    decoy->ref_count = 0;
    decoy->age = 0;
    decoy->radius = 0;

    clCopyVertex(&decoy->position, ship_pos);
    clCopyNormal(&decoy->direction, direction);
    cluNormalScale(&decoy->direction, DECOY_TRAVEL_SPEED);
    
    zf_animation_system_add(decoy,
			    &smart_pointer0,
			    (ZfAnimate*)animate);
	
    zf_render_system_add_opaque(decoy,
				&smart_pointer0,
				(ZfRender*)render);
#if 1
    zf_collision_system_add_dynamic(decoy,
				    &smart_pointer0,
				    &dynamic_collider,
				    ZF_DECOY,
				    1.0f, /* mass */
				    DECOY_RADIUS_RANGE); /* radius */
#endif
    
}
