#ifdef _DEBUG
	#include <stdlib.h>
	#include "../mmgr.h"
#endif

#include <math.h>

#include "Jytky2.hpp"
#include "../mathematics.hpp"
#include "../primitives.hpp"

const float maxlifetime = 3500;

void Jytky2::draw()
{
	const float pos = (time - startTime) / (endTime - startTime);
	float alpha = 1.0f;

	const float fadeinstart = 0.0f;
	const float fadeinstop = 0.1f;
	const float fadeoutstart = 0.90f;
	const float fadeoutstop = 1.0f;

	if (pos >= fadeinstart && pos <= fadeinstop)
		alpha *= (pos-fadeinstart) / (fadeinstop-fadeinstart);
	if (pos >= fadeoutstart && pos <= fadeoutstop)
		alpha *= 1-(pos-fadeoutstart) / (fadeoutstop-fadeoutstart);

//    filter.init(true);
	renderScene(pos, alpha);
//    filter.glow(8, 0.005f, 0.005f, 0.92f, -1.0f, 1.0f);
}

void Jytky2::renderScene(float pos, float alpha)
{

    int i;

	// calc times

	float dt;
	if(lastTime < 0)
	{
		lastTime = (float)dmsGetModulePosition();
		lastAdd = 0.0f;
		dt = 0;
	} else {
		dt = dmsGetModulePosition() - lastTime;
		lastTime = (float)dmsGetModulePosition();
	}
/**/	

	// ------------------
	// Camera


	int index=1;
    float campos = (time - cam->cameras[index].st) / (1.0f*(cam->cameras[index].et - cam->cameras[index].st));
    if (campos < 0.0f)
        campos = 0.0f;
    if (campos > 1.0f)
        campos = 1.0f;

    Vector p = cam->cameras[index].path->getValue(campos);
    Vector t = cam->cameras[index].target->getValue(campos);
    Vector u = Vector(0,1,0);  //todo

    glLoadIdentity();
    gluLookAt(p.x, p.y, p.z, t.x, t.y, t.z, u.x, u.y, u.z);

	const float analval = powf(anal->get(), 2.6f);
	
	glEnable(GL_DEPTH_TEST);
	glDisable(GL_BLEND);

/*
	// ---------
	// Ruuvi
	
	glColor3f(1,1,1);

	glEnable(GL_TEXTURE_2D);

	glBindTexture(GL_TEXTURE_2D, dmsGetTexture("organic01.jpg")->getID());

	glPushMatrix();
		glRotatef(5000*pos, 0, 1, 0);
		glTranslatef(0,pos*12-6, 0);
		glScalef(0.005f,0.005f,0.005f);
		ruuvi->renderVBO();
	glPopMatrix();



	// ---------
	// Isomodeli


	glEnable(GL_TEXTURE_2D);

	glBindTexture(GL_TEXTURE_2D, dmsGetTexture("organic01.jpg")->getID());

	glPushMatrix();
		glScalef(0.01f,0.01f,0.01f);
		model->renderVBO();
	glPopMatrix();


	glColor3f(0.14f, 0.9f, 1.0f);
/**/
	// ---------
	// Particletykki

	// add & run
	const float addinterval = 25.0f; // milliseconds

	int n;
	if(lastAdd-dt<0) 
	{
		for(i=0; i<splinecount; i++)
			for(n=0; n<4; n++) 
			{
				list->add(new JytkyP(splinet[i]->getValue(pos), (splinet[0]->getTangent(pos)).normalize(), maxlifetime));
			}
		lastAdd = addinterval;

	} else lastAdd-=dt;

	
	//float analyser = anal->get();
	float analyser = anal->get_balanced();
	float trig = platessync->get(dmsGetModulePosition());

	
	Vector x, y, z;
	Mathematics::antiRotate(&x, &y, &z);


	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
	glDisable(GL_DEPTH_TEST);

	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, dmsGetTexture("fireparticle.jpg")->getID());

	JytkyP *part = 0;
	list->goToStart();
	do 
	{
		part = 0;
		part = (JytkyP *)(list->getCurrent());
		
		if(part!=0)
		 if( part->update(x,y,z, dt, 1+trig+analyser*0.25) == false ) 
			list->remove();

	}
	while(list->goForward());

/**/

/*

	Vector movement = Vector(0,0,1) * fmodf((pos*2000.0f), luolalen);
	//Vector movement = cameraSpline->getValue(pos);

	Vector cp = Vector(0,	2,		-4.0) + movement;
	Vector ct = Vector(0,	0,		18.0f) + movement;
	Vector up = Vector(0,	1,		0);

   	glLoadIdentity();
    gluLookAt(cp.x, cp.y, cp.z, ct.x, ct.y, ct.z, up.x, up.y, up.z);

	

    const float viewdist = 100;
    const float foglength = 15;

	float fogcol[] = {0,0,0,1};
	glFogi(GL_FOG_MODE, GL_LINEAR); //EXP, EXP2, LINEAR
	glFogfv(GL_FOG_COLOR, fogcol);
	glFogf(GL_FOG_DENSITY, 0.4f);//+0.4f*(float)cos(aika*10));
	glHint(GL_FOG_HINT, GL_DONT_CARE);
	glFogf(GL_FOG_START, viewdist-foglength);
	glFogf(GL_FOG_END, viewdist);
//	glEnable(GL_FOG);

    glEnable(GL_TEXTURE_2D);
    glEnable(GL_DEPTH_TEST);
    glDisable(GL_BLEND);
//	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
//	glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
//	glEnable(GL_TEXTURE_GEN_S);
//	glEnable(GL_TEXTURE_GEN_T);

    glBindTexture(GL_TEXTURE_2D, dmsGetTexture("fastmusicpart-mood.jpg")->getID());

	glColor3f(1,1,1);
      
    Matrix normrot;
    normrot.makeRotation(pos*5, pos*8,-pos*4);

		glBegin(GL_TRIANGLES);
		for (i=0;i<truefacecount;i++)
		{
			
			//	glNormal3fv((float *)&(faces[i].normal*normrot));
				//glTexCoord2f(vertices[faces[i].a].u, vertices[faces[i].a].v);
				glVertex3fv((float *)&(vertices[faces[i].a].position));
				//glTexCoord2f(vertices[faces[i].b].u, vertices[faces[i].b].v);
				glVertex3fv((float *)&(vertices[faces[i].b].position));
				//glTexCoord2f(vertices[faces[i].c].u, vertices[faces[i].c].v);
				glVertex3fv((float *)&(vertices[faces[i].c].position));
			
		}	
		glEnd();

	// Tunnel should be redrawn if we are far..

	glDisable(GL_TEXTURE_GEN_S);
	glDisable(GL_TEXTURE_GEN_T);

	glDisable(GL_FOG);
/**/
}




Jytky2::Jytky2()
{
	
	int i;
/**/

	ruuvi = new T3DVBO(dmsGetObject("3djytky3.t3d"));
	ruuvi->createVBO();


	model = new T3DVBO(dmsGetObject("3djytky.t3d"));
	model->createVBO();

	T3DVertex *verts	= model->model->getVertexArray();
	int modelverts		= model->model->getVertexCount();
	T3DFace   *faces	= model->model->getFaceArray();
	int modelfaces		= model->model->getFaceCount();

    srand(1611);


	this->splinecount = 3;
	splinet = new CatmullRom*[splinecount];
	
	const int splinepoints = 25;
	for(i=0; i<splinecount; i++)
	{
		splinet[i] = new CatmullRom(splinepoints);
		
		for(int n=0; n<splinepoints; n++)
		{

                float r = 1.9f + 1.7f*cosf(n*0.31f);
                    
				splinet[i]->addPoint(Mathematics::randVectSphere()*r);

		}
	}
/**/

	list = new Lista2();
	lastTime = -1;
	lastAdd = -1;

	// ---------------
	// Luola
/*
    int x, y;
    xres = 40;
    yres = 150;
    vertexcount = xres*yres;
    facecount = xres*yres*2;

    vertices = new T3DVertex[vertexcount];
    faces = new T3DFace[facecount];

    for (y=0;y<yres;y++)
    {
        const float ykohta = y / (float)yres;
        for (x=0;x<xres;x++)
        {
            const float xkohta = x / (float)xres;
            const float angle = xkohta * 2*3.141592f;

            const float plasmaval =  (float)sin(ykohta*3.141592f*2*11*(0.8f+0.2f*sin(xkohta*5+ykohta*3))) 
                                   + (float)cos(xkohta*3.141592f*2*4*(0.7f+0.3f*sin(ykohta*7))+ykohta*8);

            const float radius = 8 + Mathematics::randFloat()*0.2f+plasmaval*1.5f;

            Vector p = Vector((float)sin(angle)*radius, (float)cos(angle)*radius, ykohta*200);
            vertices[x+y*xres].position = p;
			
        }
    }

/*	y=yres-1; 
        for (x=0;x<xres;x++)
        {
			vertices[x+y*xres].position.x = vertices[x].position.x;
			vertices[x+y*xres].position.y = vertices[x].position.y;
        }
*/
/*
	luolalen = 200;

    int index = 0;
    truefacecount = 0;
    for (y=0;y<yres-1;y++)
    {
        for (x=0;x<xres;x++)
        {
            faces[index].a = x+y*xres;
            faces[index].b = ((x+1)%xres)+y*xres;
            faces[index].c = x+((y+1)%yres)*xres;
            index++;
            truefacecount++;

            faces[index].a = ((x+1)%xres)+y*xres;
            faces[index].b = ((x+1)%xres)+((y+1)%yres)*xres;
            faces[index].c = x+((y+1)%yres)*xres;
            index++;
            truefacecount++;
        }
    }

    for (i=0;i<truefacecount;i++)
    {
        Vector v1 = vertices[faces[i].a].position;
        Vector v2 = vertices[faces[i].b].position;
        Vector v3 = vertices[faces[i].c].position;

        Vector normal = (v1-v3).crossProduct(v1-v2).normalize();
        faces[i].normal = normal;
    }


/*
    //verteksinormaalit
	for (i=0;i<vertexcount;i++)
	{
		vertices[i].normal = Vector(0, 0, 0);
		
	}

	for (i=0;i<truefacecount;i++)
	{
		Vector normal = faces[i].normal;
		vertices[faces[i].a].normal += normal;
		vertices[faces[i].b].normal += normal;
		vertices[faces[i].c].normal += normal;
	}
	for (i=0;i<vertexcount;i++)
	{
		vertices[i].normal.normalize();
	}

	const float scale = 1.0f;
	for (i=0;i<vertexcount;i++)
    {
        Vector n = vertices[i].normal;
        n.normalize();
        vertices[i].u = n.x*scale;
        vertices[i].v = n.y*scale;
    }

/**/

	// ----------------
	// Sync sys

	anal = new Analyzer(1);
	
	platessync = new TriggerSystem();
	platessync->add(104014, 105064);
	platessync->add(110856, 111906);//smaller
	platessync->add(116942, 117282); //smaller 
	platessync->add(117482, 117731); //smaller
	platessync->add(117931, 118981);
	platessync->add(124552, 125602);
	platessync->add(131441, 132491);



	// -----------
	// kamera
/*
	cameraSpline = new CatmullRom(150);
	for(i=0; i<150; i++)
	{
		float r = Mathematics::randFloat(5.0f);
		float a = Mathematics::randFloat(6.28f);

		cameraSpline->addPoint(Vector(cosf(a)*r, sinf(a)*r, i));
	}
*/

	

}


Jytky2::~Jytky2()
{

	list->destroy();
	delete list;

    delete [] vertices;
    delete [] faces;
    delete [] radial;

}


bool Jytky2::init(unsigned long s, unsigned long e)
{
	startTime = s;
	endTime = e;
	return true;
}


JytkyP::JytkyP() 
{
	pos = Vector();
	dir = Vector();
	lifetime = lifetime;
}

// use this 
JytkyP::JytkyP(Vector pos, Vector dir, float lifetime)
{
	this->pos = pos + Mathematics::randVector()*0.5f;
	this->dir = dir + Mathematics::randVector();
	this->lifetime = lifetime;
}

// antirotate vektori
bool JytkyP::update(Vector x, Vector y, Vector z, float dt, float scalemod)
{
	this->lifetime -= dt;

	// move

	this->pos += this->dir * dt*0.001f;
	// vähennetään nopeutta
	this->dir -= this->dir * dt*0.0001f;

	// draw


	const float size = this->lifetime/maxlifetime;

	//Primitives::drawBillboard(pos, x, y, z, size*0.4f);
	Vector point = pos;
	float siz = size*0.1f*scalemod;
	glBegin(GL_QUADS);

	Vector v1 = point - x*siz - y*siz;
	Vector v2 = point + x*siz - y*siz;
	Vector v3 = point + x*siz + y*siz;
	Vector v4 = point - x*siz + y*siz;

	glTexCoord2f(0, 0);
	glVertex3fv((float *)&v1);
	glTexCoord2f(1, 0);
	glVertex3fv((float *)&v2);
	glTexCoord2f(1, 1);
	glVertex3fv((float *)&v3);
	glTexCoord2f(0, 1);
	glVertex3fv((float *)&v4);

    glEnd();

	// check lifetime

	if(this->lifetime < 0) 
		return false;
	else 
		return true;

}