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

#include <math.h>

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

void Elokuva::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);

	renderScene(pos, alpha);
}

void Elokuva::renderScene(float pos, float alpha)
{
	// Partin vaihdot
	float sync = trigger->get(dmsGetModulePosition());

	glLoadIdentity();
/*
	glTranslatef(0, 0, -5.0f);
	glRotatef(30-pos*60, 0, 1, 0);
*/

	Vector cam = kamera->getValue(pos) * (1.0f);//  + 0.4f*sinf(sync * 3.141592f));
	Vector tar = Vector(cam.x, cam.y, 0) * 0.13f + path->getValue(pos)*0.27f;
	Vector up = Vector(0,1,0);

	glLoadIdentity();
	gluLookAt(cam.x, cam.y, cam.z, tar.x, tar.y, tar.z, up.x, up.y, up.z);



	//kuva xy-tasossa

	float xs = -16.0f;
	float ys = xs * 480 / 640.0f;

	glEnable(GL_TEXTURE_2D);
	glDisable(GL_BLEND);
	glBindTexture(GL_TEXTURE_2D, dmsGetTexture("ck_tex.jpg")->getID());
	
	float ka = alpha*0.45f*(1-sync);
	glColor4f(ka, ka, ka, alpha);
	glBegin(GL_QUADS);
	glTexCoord2f(0, 0);
	glVertex3f(-xs, -ys, 0);
	glTexCoord2f(1, 0);
	glVertex3f( xs, -ys, 0);
	glTexCoord2f(1, 1);
	glVertex3f( xs, ys, 0);
	glTexCoord2f(0, 1);
	glVertex3f(-xs, ys, 0);
	glEnd();

	//valo
    float analval = anal->get()*0.20f;
    filter.init(true);

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

	float end_t = 0.2f + pos * 0.8f;

	glLineWidth(3.0f);
	glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
	glEnable(GL_LINE_SMOOTH);
	glBegin(GL_LINE_STRIP);
	for (float t = 0.0f; t < end_t; t += 0.001f)
	{
		//glColor4f(0.9f, 0.7f, 0.2f, alpha*0.3f);
		glColor4f(0.15f, 0.79f, 0.9f, alpha*0.3f);
		Vector v1 = path->getValue(t);
		glVertex3fv((float *)&v1);
	}
	glEnd();
	glDisable(GL_LINE_SMOOTH);


	glBegin(GL_QUAD_STRIP);
	for (t = 0.0f; t < end_t; t += 0.001f)
	{
		float fadefunc = 0.7f+0.3f * (0.7f * cosf(t*90+pos*151) + 0.3f*sinf(t * 161-pos*210));

		fadefunc *= Mathematics::randBetween(fadefunc-0.1f, 1.0f);
		float fade = analval * fadefunc  * alpha;
		Vector v1 = path->getValue(t);
		Vector v2 = v1 * 1.05f - Vector(0, 0, 0.2f*fadefunc);

//		glColor4f(1,Mathematics::randBetween(0.5f, 0.85f),0.2f,fade*0.6f);
		glColor4f(0.2f, Mathematics::randBetween(0.5f, 0.85f),1,fade*0.6f);
		glVertex3fv((float *)&v1);
		//glColor4f(0.8f,0.4f,0.2f,0);//fade*0.1f);
		glColor4f(0.25f, 0.75f, 0.85f, 0);
		glVertex3fv((float *)&v2);
	}
	glEnd();

	for (int i = 0; i < count; i++)
	{
		splinet[i]->draw(pos, analval, alpha*0.7f);

	}

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

	glLineWidth(3.0f);
	glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
	glEnable(GL_LINE_SMOOTH);

	if(trigger->getChanged())
		triggersHit++;

	const int maxtriggers = 5;
	int vc = (vcount*triggersHit)/maxtriggers;

	
	vc = 0.2*vcount + (int)(0.8f*Mathematics::calcPosFloat(pos, 0.2f, 0.5f)*vcount);
	
	float fadeout = (1-Mathematics::calcPosFloat(pos, 0.95f, 0.98f));
	if(vc > vcount) vc = vcount;

	for (i = 0; i < vc; i++)
	{
		viivat[i].draw(pos, sync, analval, (alpha+sync)*fadeout);
	}
	glDisable(GL_LINE_SMOOTH);
	
    filter.glow(8, 0.007f, 0.007f, 0.92f, -1.0f, 1.0f);

}


void PikkuSpline::draw(float pos, float analval, float alpha)
{
	float t = Mathematics::calcPosFloat(pos, this->st, this->et);

	if (t > 0.0001f && t < 1.0000f)
	{
		glPushMatrix();
		Vector trans = this->direction * t;
		glTranslatef(trans.x, trans.y, trans.z);

		alpha *= Mathematics::calcSaturate(t, 0, 1, 3.4f);

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

		glLineWidth(3.0f);
		glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
		glEnable(GL_LINE_SMOOTH);
		glBegin(GL_LINE_STRIP);
		for (float u = 0.0f; u < t; u += 0.001f)
		{
			glColor4f(0.9f, 0.7f, 0.2f, alpha*0.3f);
			Vector v1 = path->getValue(u);
			glVertex3fv((float *)&v1);
		}
		glEnd();
		glDisable(GL_LINE_SMOOTH);


		glBegin(GL_QUAD_STRIP);
		for (u = 0.0f; u < t; u += 0.001f)
		{
			float fadefunc = 0.7f+0.3f * (0.7f * cosf(u*90+pos*151) + 0.3f*sinf(u * 161-pos*210));

			fadefunc *= Mathematics::randBetween(fadefunc-0.1f, 1.0f);
			float fade = analval * fadefunc  * alpha;
			Vector v1 = path->getValue(u);
			Vector v2 = v1 * 1.05f - Vector(0, 0, 0.2f * t * fadefunc);

			glColor4f(1,Mathematics::randBetween(0.5f, 0.85f),0.2f,fade*0.6f);
			glVertex3fv((float *)&v1);
			glColor4f(0.8f,0.4f,0.2f,0);//fade*0.1f);
			glVertex3fv((float *)&v2);
		}
		glEnd();
		glPopMatrix();
	}
}

void Viiva::draw(float pos, float sync, float analval, float alpha)
{
	float t = fmodf(pos * this->speed + this->phase, 1);

	float a = this->a1 * (1-t) + this->a2 * t;
	float r = Mathematics::calcSaturate(t, 0, 1, 1.5f) * this->rad;

	Vector keskus = this->p1 * (1-t) + this->p2 * t;
	Vector k1 = keskus + Vector(cosf(a), sinf(a), 0) * r;
	Vector k2 = keskus - Vector(cosf(a), sinf(a), 0) * r;

	alpha *= Mathematics::calcSaturate(t, 0, 1, 1.4f)*0.7f;

	glBegin(GL_LINES);
	glColor4f(0.9f, 0.7f, 0.2f, alpha*0.3f);
	glVertex3fv((float *)&k1);
	glVertex3fv((float *)&k2);
	glEnd();


	Vector stripcolor2 = Vector(0.8f, 0.4f, 0.2f) * (1-sync) + Vector(0.2f, 0.7f, 0.9f)*sync;

	glBegin(GL_QUAD_STRIP);
	for (float u = 0.0f; u < 1.0f; u += 0.05f)
	{
		float fadefunc = 0.7f+0.3f * (0.7f * cosf(u*90+pos*151) + 0.3f*sinf(u * 161-pos*210));

		fadefunc *= Mathematics::randBetween(fadefunc-0.1f, 1.0f);
		float fade = analval * fadefunc  * alpha;
		Vector v1 = k1 * (1-u) + k2 * u;
		Vector v2 = v1 * 1.05f - Vector(0, 0, 0.2f * t * fadefunc);

		Vector color1 = Vector(1,Mathematics::randBetween(0.5f, 0.85f),0.2f) * (1-sync) + 
						Vector(Mathematics::randBetween(0.5f, 0.85f),1,1) * sync;//0.2f);

		glColor4f(color1.x, color1.y, color1.z, fade*0.6f + sync*0.2f);
//		glColor4f(1,Mathematics::randBetween(0.5f, 0.85f),0.2f,fade*0.6f);
		glVertex3fv((float *)&v1);
//		glColor4f(0.8f,0.4f,0.2f,0);//fade*0.1f);
		glColor4f(stripcolor2.x, stripcolor2.y, stripcolor2.z,0);//fade*0.1f);
		glVertex3fv((float *)&v2);
	}
	glEnd();
}


Elokuva::Elokuva()
{

	triggersHit=0;
	trigger = new TriggerSystem();
	trigger->add(104028, 105078);
	trigger->add(124545, 125595);
	trigger->add(116804, 116954);
	trigger->add(117271, 117421);
	trigger->add(117686, 118736);

	const int points = 300;
	const int kamerapoints = 14;

    anal = new Analyzer(2);
	path = new CatmullRom(points);

	srand(199);

	for (int i = 0; i < points; i++)
	{
		float it =  2 * i / (float)points;

//		it = sinf(it*3.141592f);

		float r1 = powf(it, 1.5f)*2;
		float a1 = it * 2 * 3.141592f * 6;//11;
		Vector p1 = Vector(0, 0, 0);

		float r2 = powf(it, 1.2f)*1.5f;
		float a2 = it * 2 * 3.141592f * 5;//9.0f;
		Vector p2 = Vector(-2, 0, 0);

		Vector v1 = p1 + Vector(cosf(a1), sinf(a1), 0) * r1;
		Vector v2 = p2 + Vector(cosf(a2), sinf(a2), 0) * r2;

		Vector p = v1 * (1-it) + v2 * it;//Vector(cosf(a), sinf(a), 0) * r;

		path->addPoint(p);
	}

	kamera = new CatmullRom(kamerapoints);
	for (i = 0; i < kamerapoints; i++)
	{
		float it = 2 * i / (float)kamerapoints;
/*
		Vector displace = Mathematics::randVectSphere()*1.8f;
		displace.z = fabsf(displace.z) + 1.7f;
		Vector p = path->getValue(it)*0.3f - displace;
*/
		Vector displace = Mathematics::randVectSphere()*1.8f;
		displace.z = fabsf(displace.z) + 0.0f + powf(it, 2) * 6.0f; //??????
		Vector p = path->getValue(it)*0.9f - displace;
		kamera->addPoint(p);
	}

	count = 70;
	splinet = new PikkuSpline*[count];


	for (i = 0; i < count; i++)
	{
		splinet[i] = new PikkuSpline();
		splinet[i]->st = Mathematics::randBetween(0.0f, 0.9f);
		splinet[i]->et = splinet[i]->st + Mathematics::randBetween(0.04f, 0.18f);

		bool dir = (rand()%2)==0;

		const int points = 20 + (rand()%50);

		splinet[i]->path = new CatmullRom(points);

		Vector p = Mathematics::randVectSphere()*6;
		p.z = 0;

		Vector d = Mathematics::randVectSphere()*1.7f;
		d.z = 0;
		splinet[i]->direction = d;

		float kierroksia = Mathematics::randBetween(3, 7);
		float rad = Mathematics::randBetween(0.7f, 1.6f);
		float power = Mathematics::randBetween(1.5f, 2.4f);

		for (int j = 0; j <points; j++)
		{
			float jt = j / (float)points;
			float a = jt * (dir?1:-1) * 2 * 3.1415922f * kierroksia;
			float r = powf(jt, power) * rad;

			Vector v = p + Vector(cosf(a), sinf(a), 0) * r;
			splinet[i]->path->addPoint(v);
		}
	}

	vcount = 700;
	viivat = new Viiva[vcount];

	for (i = 0; i < vcount; i++)
	{
		float x1 = -19;
		float x2 = 19;
		float y = Mathematics::randBetween(-8.0f, 8.0f);

		viivat[i].p1 = Vector(x1, y, 0);
		viivat[i].p2 = Vector(x2, y, 0);

		viivat[i].phase = Mathematics::randFloat();
		viivat[i].speed = Mathematics::randBetween(3, 4);

		viivat[i].a1 = Mathematics::randFloat()*2*3.141592f;
		viivat[i].a2 = Mathematics::randFloat()*2*3.141592f;

		viivat[i].rad = Mathematics::randBetween(0.04f, 0.1f);
	}
}

Elokuva::~Elokuva()
{
}


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

