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

#define TRITOR_MASS 0.5
#define TRITOR_RADIUS 0.9f
#define TOR_RADIUS 0.1f
#define TRITOR_ROTATION_RATE 2.0f

#define TRITOR_FLUX_LENGTH 4.0f

typedef struct Tritor Tritor;

struct Tritor
{
    unsigned int ref_count;

    CLmatrix flux_frame;
    CLvertex position;

    double flux_t;
    double flux_end_t;
    float roll;

    bool valid;
};

static ZfSmartPointer smart_pointer; /* interface for tritors */
static ZfDynamicCollider dynamic_collider; /* interface for tritors */

static CLvertex top, left, right;

static bool
is_valid(const Tritor* tritor)
{
    return tritor->valid;
}

static void
reference(Tritor* tritor)
{
    tritor->ref_count++;
}

static void
release(Tritor* tritor)
{
    tritor->ref_count--;

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

static void
animate(Tritor* tritor)
{
    zf_flux_update_frame(&tritor->flux_frame, 
			 tritor->flux_t);

    cluSetVertexMatrixOrigin(&tritor->position, &tritor->flux_frame);

    tritor->flux_t = zf_flux_query_next_t_given_distance(tritor->flux_t,
							  0.22f); /*HACK - MAGIC number - slighting faster than ship*/

    if(tritor->flux_t >= tritor->flux_end_t)
	tritor->valid = false;
    else
	tritor->roll -= TRITOR_ROTATION_RATE;

}

static void
query_frame(Tritor* tritor, 
	    CLmatrix* frame)
{
    CLnormal offset;
    CLvertex origin;
    
    static const CLnormal axis = {0.0f, 0.0f, 1.0f};
    CLUquaternion quaternion;
    CLmatrix matrix;

    /* for the rotation */
    cluSetQuaternionAxisAngle(&quaternion, &axis, tritor->roll);
    cluQuaternionNormalise(&quaternion);
    clDefaultMatrix(&matrix);
    cluSetMatrixOrientation(&matrix, &quaternion);

    cluMatrixTransform(&matrix, &tritor->flux_frame);
    clCopyMatrix(frame, &matrix);
}


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

static void
collision_response(Tritor* tritor,
		   const void* collider_data,
		   ZfType collider_type,
		   const CLvertex* collision_position,
		   const CLnormal* collision_force_perp,
		   const CLnormal* collision_force_tan)
{
    CLmatrix tritor_frame;
    CLvertex glob_top;
    CLvertex glob_right;
    CLvertex glob_left;

    if(collider_type & ZF_ENEMY)
    {
	query_frame(tritor, &tritor_frame);
	clCopyVertex(&glob_top, &top);
	clCopyVertex(&glob_right, &right);
	clCopyVertex(&glob_left, &left);

	cluVertexTransform(&glob_top, &tritor_frame);
	cluVertexTransform(&glob_right, &tritor_frame);
	cluVertexTransform(&glob_left, &tritor_frame);

/*	zf_explosion_new(&tritor->position, 1.5f);*/
	zf_explosion_new(&glob_top, 1.5f);
	zf_explosion_new(&glob_right, 1.5f);
	zf_explosion_new(&glob_left, 1.5f);

	tritor->valid = false; 
    }
}

static void
render(Tritor* tritor)
{
    CLmatrix frame;
    glPushAttrib(GL_ALL_ATTRIB_BITS);

    query_frame(tritor, &frame); /* Need this to get the tritor frame */

    glDisable(GL_LIGHTING);
    glPushMatrix();
    glMultMatrixf((GLfloat*)&frame);

    glColor3f(1.0f, 0.0f, 1.0f);
    glutSolidSphere(TOR_RADIUS, 8, 8);

    /*    glutWireSphere(TRITOR_RADIUS, 8, 8);*/

    glPushMatrix();
    glTranslatef(top.x, top.y, top.z);
    glutSolidSphere(TOR_RADIUS, 8, 8);
    glPopMatrix();

    glPushMatrix();
    glTranslatef(left.x, left.y, left.z);
    glutSolidSphere(TOR_RADIUS, 8, 8);
    glPopMatrix();

    glPushMatrix();
    glTranslatef(right.x, right.y, right.z);
    glutSolidSphere(TOR_RADIUS, 8, 8);
    glPopMatrix();

    glPopMatrix();

    glPopAttrib();
}

void
zf_tritor_close(void)
{
/*    clDeleteContext(context);*/
}

void
zf_tritor_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;

    cluSetVertex(&top, 0.0f, 0.8f, 0.0f);
    cluSetVertex(&left, -0.69f, -0.4f, 0.0f);
    cluSetVertex(&right, 0.69f, -0.4f, 0.0f);

}

void
zf_tritor_new(const CLmatrix* flux_frame,
	      float flux_t,
	      float roll)
{
    Tritor* tritor;

    tritor = g_new(Tritor, 1);
    
    tritor->ref_count = 0;
    clCopyMatrix(&tritor->flux_frame, flux_frame);
    cluSetVertexMatrixOrigin(&tritor->position, &tritor->flux_frame);
    tritor->valid = true;
    tritor->flux_t = flux_t;
    tritor->flux_end_t = flux_t + TRITOR_FLUX_LENGTH;
    tritor->roll = roll;

    zf_animation_system_add(tritor,
			    &smart_pointer,
			    (ZfAnimate*) animate);
    
    zf_collision_system_add_dynamic(tritor,
				    &smart_pointer,
				    &dynamic_collider,
				    ZF_TRITOR,
				    TRITOR_MASS, /* mass */
				    TRITOR_RADIUS); /* radius */
    
    zf_render_system_add_opaque(tritor,
				&smart_pointer,
				(ZfRender*) render);
}
