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

#include <math.h>

#include "Kliimaksi.hpp"
#include "Myrsky.hpp"
#include "../mathematics.hpp"
#include "../primitives.hpp"

void Kliimaksi::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.97f;
	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 KliimaksiSpline::draw(float pos, float sync, float alpha)
{
/*
	glEnable(GL_TEXTURE_2D);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
	glDisable(GL_DEPTH_TEST);
	glBindTexture(GL_TEXTURE_2D, dmsGetTexture("fireparticle.jpg")->getID());
*/
	Vector x, y, z;
	Mathematics::antiRotate(&x, &y, &z);
    
    float t = Mathematics::calcPosFloat(pos, this->st, this->et);

    float fade = Mathematics::calcPosFloat(pos, 0.15f, 0.3f);
    float a = sinf(fmodf(this->aphase + pos*this->aspeed, 1)*3.141592f);
    alpha *= ((0.7f+0.3f*a) * fade + 1 * (1-fade));

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

    float retreat = 1 - Mathematics::calcPosFloat(pos, 0.86f, 0.97f);

    alpha *= this->fade;

	for (int j = 0; j < pcount; j ++)
	{
		KliimaksiParticle *p = &particles[j];
        if (p->pos < t && p->pos < retreat)
        {
            Vector position = spline->getValue(p->pos);
            
        	glBegin(GL_LINE_STRIP);
            for (int j = 0; j < p->positioncount; j++)
            {
                float jt = j / (float)p->positioncount;
                Vector position2 = p->positions[j];

		        float size = 0.1f;//*(1-a*a*a);
                if (j == p->positioncount - 1)
                {
		            glColor4f(this->color.x, this->color.y, this->color.z, jt*alpha);
                }
                else
                {
		            glColor4f(this->color.x, this->color.y, this->color.z, jt*alpha*0.7f);
                }
                glVertex3fv((float *)&position2);
            }
            glEnd();
        }
	}


}

void KliimaksiSpline::updateParticles(float pos, float sync)
{
    int i;

    for (i = 0; i < splinepointcount; i++)
    {
//        spline->points[i] += this->deltapoints[i]*0.01f;
        


    }

    for (i = 0; i < pcount; i++)
    {
        KliimaksiParticle *p = &this->particles[i];

        //liikutus
        p->pos += p->positionspeed * 0.002f;

        //klippaus
        if (p->pos >= 1.000f)
        {
            p->pos = 0.0f;
            Vector base = spline->getValue(p->pos);
            for (int j = 0; j < p->positioncount; j++)
            {
                p->positions[j] = base;
            }
        }
        else 
        {
            //lasketaan paikka
		    float movet1 = fmodf(p->movephase1 + p->movespeed1*p->pos, 1);
		    float movet2 = fmodf(p->movephase2 + p->movespeed2*p->pos, 1);
		    float movet3 = fmodf(p->movephase3 + p->movespeed3*p->pos, 1);

            float morffi = sinf(fmodf(pos*this->morffispeed , 1)*3.141592f);
			
			morffi += sync*0.2f;

			if (morffi > 1.0f)
				morffi = 1.0f;

            Vector splinevalue = spline->getValue(p->pos)*(1-morffi) + spline2->getValue(p->pos)*morffi;

	        Vector displace = Vector(cosf(movet1*3.141592f*2), sinf(movet2*3.141592f*2), cosf(movet3*3.141592f*2));
		    Vector position = splinevalue + displace*(0.3f+0.7f*p->pos)*0.5f*(0.7f+0.5f*cosf(p->pos*19));//*cosf(colort*3.141592f*2);

            for (int j = 0; j < p->positioncount - 1; j++)
            {
                p->positions[j] = p->positions[j + 1];
            }
            p->positions[p->positioncount - 1] = position;
        }
    }
}

void KliimaksiSpline::initParticles(int count)
{
    this->pcount = count;

    this->particles = new KliimaksiParticle[this->pcount];

    for (int i = 0; i < this->pcount; i++)
    {
        this->particles[i].colorphase = Mathematics::randFloat();
        this->particles[i].colorspeed = 5.3f + 7.5f * Mathematics::randFloat();
        this->particles[i].positionphase = Mathematics::randFloat();
        this->particles[i].positionspeed = 3.0f + 5.0f * Mathematics::randFloat();
        this->particles[i].movephase1 = Mathematics::randFloat();
        this->particles[i].movephase2 = Mathematics::randFloat();
        this->particles[i].movephase3 = Mathematics::randFloat();
        //xyz
        this->particles[i].movespeed1 = 1 + 0.8f * Mathematics::randFloat();
        this->particles[i].movespeed2 = 2 + 0.6f * Mathematics::randFloat();
        this->particles[i].movespeed3 = 1 + 1.1f * Mathematics::randFloat();
        this->particles[i].moveradius = 0.15f + 0.30f*Mathematics::randFloat();
        this->particles[i].pos = Mathematics::randFloat();
        this->particles[i].positioncount = 5 + rand()%10;
        this->particles[i].positionindex = 0;

        this->particles[i].positions = new Vector[this->particles[i].positioncount];
        for (int j = 0; j < this->particles[i].positioncount; j++)
        {
            this->particles[i].positions[j] = Vector(0,0,0);
        }

    }
    Vector c1, c2;
    switch(rand()%4)
    {
        case 0:
        {
            //vihreä
//            c1 = Vector(0.15f, 0.5f, 0.25f);
//            c2 = Vector(0.14f, 0.8f, 0.24f);
            c1 = Vector(0.15f, 0.7f, 0.9f);
            c2 = Vector(0.14f, 0.9f, 1.0f);
        } break;
        case 1:
        {
            //keltainen
            c1 = Vector(0.9f, 0.7f, 0.3f);
            c2 = Vector(1.0f, 0.8f, 0.3f);

        } break;
        case 2:
        {
            //oranssi
            c1 = Vector(0.8f, 0.4f, 0.1f);
            c2 = Vector(1.0f, 0.5f, 0.1f);
        } break;

        case 3:
        {
            //punainen
            c1 = Vector(0.8f, 0.2f, 0.1f);
            c2 = Vector(1.0f, 0.3f, 0.1f);
        } break;
    }

    float coloralpha = 0.5f;
    float colort = Mathematics::randFloat();
    this->color = (c1 * (1-colort) + c2*colort)*coloralpha;

}


void Kliimaksi::renderSky(float pos, float alpha)
{
	//glCullFace(GL_BACK);
	//glEnable(GL_CULL_FACE);

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

	int i;
	
	glEnable(GL_TEXTURE_2D);

	//////////////////
	// isoin katto
	//////////////////

	T3D *object1 = dmsGetObject("sp.t3d");
	int objectvertexcount = object1->getVertexCount();
	int objectfacecount = object1->getFaceCount();
	T3DFace *objectfaces = object1->getFaceArray();
	T3DVertex *objectvertices = object1->getVertexArray();

	//////////////////
	// taivas/pilvet
	//////////////////
/*
	Vector clearcol = Vector(0.3f, 0.4f,0.4f);
	glClearColor(clearcol.x,clearcol.y,clearcol.z,0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
*/

	float coloradd = Mathematics::calcPosFloat(pos, 0.5f, 1.0f);
	float r = 0.6f + 0.4f*coloradd;
	float g = 0.6f + 0.1f*coloradd;
	float b = 0.6f + 0.0f*coloradd;
	glPushMatrix();
	
		glColor4f(r*alpha,g*alpha,b*alpha,alpha);
		//glColor4f(1,1,1, 0.65f*alpha);
		glScalef(11, 6.25f, 11);
		//glRotatef(175.0f+pos*-55,0.1f,0.2f,1); 
		glRotatef(180, 0, 0, 1);
		glRotatef(175.0f+pos*-55, 0,1,0); 
		
		glBindTexture(GL_TEXTURE_2D, dmsGetTexture("sky4.jpg")->getID());
		
		glBegin(GL_TRIANGLES);
		for (i=0;i<objectfacecount;i++)
		{
			//glNormal3fv((float *)&objectfaces[i].normal);
			glTexCoord2f(objectvertices[objectfaces[i].a].u, objectvertices[objectfaces[i].a].v);
			 glVertex3fv((float *)&objectvertices[objectfaces[i].a].position);
			//glNormal3fv((float *)&objectfaces[i].normal);
			glTexCoord2f(objectvertices[objectfaces[i].b].u, objectvertices[objectfaces[i].b].v);
			 glVertex3fv((float *)&objectvertices[objectfaces[i].b].position);
			//glNormal3fv((float *)&objectfaces[i].normal);
			glTexCoord2f(objectvertices[objectfaces[i].c].u, objectvertices[objectfaces[i].c].v);
			 glVertex3fv((float *)&objectvertices[objectfaces[i].c].position);
		}
		glEnd();

	glPopMatrix();

	glPushMatrix();
	
	    //glColor4f(1,1,1, 0.305f*alpha);
		glColor4f(0.8f*alpha,0.89f*alpha,1*alpha, 0.4621305f*alpha);

	    glScalef(10, 5.5f, 10);
	    glRotatef(180, 0, 0, 1);
		
		glBindTexture(GL_TEXTURE_2D, dmsGetTexture("hmap.jpg")->getID());
		glBegin(GL_TRIANGLES);
		for (i=0;i<objectfacecount;i++)
		{
			//glNormal3fv((float *)&objectfaces[i].normal);
			glTexCoord2f(objectvertices[objectfaces[i].a].u, objectvertices[objectfaces[i].a].v);
			 glVertex3fv((float *)&objectvertices[objectfaces[i].a].position);
			//glNormal3fv((float *)&objectfaces[i].normal);
			glTexCoord2f(objectvertices[objectfaces[i].b].u, objectvertices[objectfaces[i].b].v);
			 glVertex3fv((float *)&objectvertices[objectfaces[i].b].position);
			//glNormal3fv((float *)&objectfaces[i].normal);
			glTexCoord2f(objectvertices[objectfaces[i].c].u, objectvertices[objectfaces[i].c].v);
			 glVertex3fv((float *)&objectvertices[objectfaces[i].c].position);
		}
		glEnd();

	glPopMatrix();

	//glDisable(GL_CULL_FACE);
}


void Kliimaksi::renderScene(float pos, float alpha)
{
    int i; 

	cam->useCamera(2);

	float sync = triggers->get(dmsGetModulePosition());

    static int prevtime = 0;
    static int particlecumultime = 0;
    static int particleindex = 0;

    int currenttime = dmsGetModulePosition();
    int dt = currenttime - prevtime;
    prevtime = currenttime;

    if (dt < 0)
        dt = -dt; 

    particlecumultime += dt;
    const int maxcycles = 20;

    const int particleupdatelimit = 40; //100 fps = 2-3 krt/frame
    if (particlecumultime > maxcycles*particleupdatelimit)
        particlecumultime = maxcycles*particleupdatelimit;

    while (particlecumultime > particleupdatelimit)
    {
        //päivitetään particleja
        for (int j = 0; j < splinecount; j++)
        {
            splinet[j]->updateParticles(pos, sync);
        }
        particlecumultime -= particleupdatelimit;
    }
    

    if (pos < 0.5f)
    {
        renderSky(pos, 1);
    }
    else
    {
        renderSky(pos, alpha);
    }


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

	const float fadelattia = Mathematics::calcPosFloat(pos, 0.165f, 0.2f) * alpha;

	//glColor4f(0.79f,0.79f,0.79f,1*alpha);

	float multiplier = 68.0f;

	Vector p1 = Vector(-2, 0,-2)*multiplier;
	Vector p2 = Vector( 2, 0,-2)*multiplier;
	Vector p3 = Vector( 2, 0, 2)*multiplier;
	Vector p4 = Vector(-2, 0, 2)*multiplier;

	float lattiay = -3;
	p1.y = lattiay;
	p2.y = lattiay;
	p3.y = lattiay;
	p4.y = lattiay;
	
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, dmsGetTexture("maatesti.jpg")->getID());

	Primitives::renderTexturedPlaneWithFadeOut(p1,p2,p3,p4, 25, 20, Vector(fadelattia*1,fadelattia*1,fadelattia*1), Vector(), 5.0f, 22.0f, 0.7f*fadelattia);

	glDisable(GL_DEPTH_TEST);
	glDisable(GL_TEXTURE_2D);

	glLoadIdentity();
	cam->useCamera(2);

	const int tilpecount = 4;
	for (i = 0; i < tilpecount; i++)
	{
		float it = i  / (float)tilpecount;
		float r = 4.5f + powf(i*1.0f+1.0f, 1.3f);

		int points = 100;
		glColor4f(0.9f, 0.6f, 0.2f, (1 - it)*alpha*0.6f*Mathematics::calcPosFloat(pos, 0.2f, 0.4f));
		glBegin(GL_QUAD_STRIP);
		for (int j = 0; j < points; j++)
		{
			float jt = j / (float)(points-1);
			float a = jt * 2 * 3.141592f;
			float r1 = r;
			float r2 = r + 0.2f;

			Vector v1 = Vector(cosf(a), 0, sinf(a))*r1;
			Vector v2 = Vector(cosf(a), 0, sinf(a))*r2;

			float yp = -2 - i*0.15f;
			v1.y = yp;
			v2.y = yp;

			glVertex3fv((float *)&v1);
			glVertex3fv((float *)&v2);
		}
		glEnd();
	}


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


    int realcount = (int)(Mathematics::calcPosFloat(pos, 0.3f, 0.8f)*count);

    glEnable(GL_LINE_SMOOTH);
    glHint(GL_LINE_SMOOTH_HINT, GL_FASTEST);
    glLineWidth(1.5f);
    glBegin(GL_LINES);
    for (i = 0; i < realcount; i++)
    {
        float t = 1-fmodf(pos*particles[i].speed + particles[i].phase, 1);
        float a = cosf(t*3.141592f*0.5f)*0.3f*alpha;

        Vector v1 = particles[i].startpos + (particles[i].endpos - particles[i].startpos) * t;
        Vector v2 = v1 - Vector(0, particles[i].length, 0);

        if (v2.y < 0)
            v2.y = 0;

        glColor4f(particles[i].color.x, particles[i].color.y, particles[i].color.z, a);
        glVertex3fv((float *)&v1);
        glColor4f(1,1,1,0);//particles[i].color.x, particles[i].color.y, particles[i].color.z, 0);
        glVertex3fv((float *)&v2);
    }
    glEnd();
    glDisable(GL_LINE_SMOOTH);



    filter.init();
/*
    glColor4f(1,0,0,alpha);
    Primitives::wireCube(15);
    glColor4f(0,1,0,alpha);
    Primitives::wireCube(10);
    glColor4f(0,0,1,alpha);
    Primitives::wireCube(4);
*/


/*


    Vector x, y, z;
	Mathematics::antiRotate(&x, &y, &z);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);
    glDisable(GL_DEPTH_TEST);
    glBindTexture(GL_TEXTURE_2D, dmsGetTexture("particle3.jpg")->getID());

    const float particlealpha = 1.0f;
    glBegin(GL_QUADS);
    for (i = 0; i < realcount; i++)
    {
        float t = fmodf(pos*particles[i].speed + particles[i].phase, 1);
        float a = cosf(t*3.141592f*0.5f)*0.5f*alpha;

        Vector p = particles[i].startpos + (particles[i].endpos - particles[i].startpos) * t;

        const float size = a*0.7f;
        glColor4f(particles[i].color.x, particles[i].color.y, particles[i].color.z, a*0.3f);
	    Vector v1 = p - x*size - y*size;
	    Vector v2 = p + x*size - y*size;
	    Vector v3 = p + x*size + y*size;
	    Vector v4 = p - x*size + y*size;

        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();
*/
    float analval = anal->get()*0.15f;
    static int fadeindex = 0;

    fades[fadeindex] = analval;

    fadeindex++;
    fadeindex %= splinecount;
    glLineWidth(2.0f);

    for (i = 0; i < splinecount; i++)
    {
        splinet[i]->draw(pos, sync, alpha*(0.1f+analval));//fades[i]);
    }


    filter.glow(5, 0.006f, 0.006f, 0.92f, -1.0f, 1.0f, 0);


}


Kliimaksi::Kliimaksi()
{	
    int i;

    anal = new Analyzer(2);

    splinecount = 70;
    splinet = new KliimaksiSpline*[splinecount];
    srand(16117);

    fades = new float[splinecount];

    for (i = 0; i < splinecount; i++)
    {
        fades[i] = 0.0f;


        splinet[i] = new KliimaksiSpline();

        splinet[i]->fade = Mathematics::randBetween(0.5f, 0.95f);
        splinet[i]->st = Mathematics::randBetween(0.04f, 0.45f);
        splinet[i]->et = splinet[i]->st + 0.05f+Mathematics::randFloat()*0.05f;
        splinet[i]->aphase = Mathematics::randFloat();
        splinet[i]->aspeed = Mathematics::randBetween(35, 50);
        splinet[i]->morffispeed = Mathematics::randBetween(1, 2.5f);
        
        const int points = 16 + rand() % 10;

        splinet[i]->spline = new CatmullRom(points);
        splinet[i]->spline2 = new CatmullRom(points);
        splinet[i]->deltapoints = new Vector[points];
        splinet[i]->splinepointcount  = points;

        float r = Mathematics::randFloat()*1.5f;
        float a = Mathematics::randFloat()*2*3.141592f;

        Vector p = Vector(cosf(a), 0, sinf(a))*r;
        Vector p2 = Vector(cosf(a), 0, sinf(a))*r;

        bool ylos = splinet[i]->st < 0.15f;

        for (int j = 0; j < points; j++)
        {
            splinet[i]->spline->addPoint(p);
            splinet[i]->spline2->addPoint(p2);
            splinet[i]->deltapoints[j] = Mathematics::randVectSphere()*Mathematics::randFloat();//Vector[points];

            Vector delta = Vector(0, 0, 0);
            Vector delta2 = Vector(0, 0, 0);
            do
            {
                delta = Mathematics::randVectSphere()*(0.5f+0.5f*Mathematics::randFloat())*2;
                delta2 = Mathematics::randVectSphere()*(0.5f+0.5f*Mathematics::randFloat())*2;

                if (ylos)
                {
                    Matrix scale;
                    scale.data[0][0] = 0.5f;
                    scale.data[1][1] = 1.0f;
                    scale.data[2][2] = 0.5f;
                    delta *= scale;
                    delta2 *= scale;
                    if (delta.y < 0.8f)
                        delta.y = 0.8f;
                    if (delta2.y < 0.8f)
                        delta2.y = 0.8f;
                }

            } while (delta.length() < 1.0f && delta2.length() < 1.0f);

            p += delta;
            p2 += delta2;
        }

        splinet[i]->initParticles(60);
    }



    count = 2200;
    particles = new KliimaksiHohde[count];

    for (i = 0; i < count; i++)
    {
        float r = 3 + Mathematics::randFloat()*8.5f;
        float a = Mathematics::randFloat()*2*3.141592f;
        
        float height = 15 + Mathematics::randFloat()*5.0f;
        particles[i].startpos = Vector(cosf(a), 0, sinf(a))*r;
        particles[i].endpos = particles[i].startpos + Vector(0, height, 0);
        particles[i].length = Mathematics::randBetween(0.3f, 0.5f);
        particles[i].speed = Mathematics::randBetween(25, 35);
        particles[i].phase = Mathematics::randFloat();
        Vector c1, c2;
        switch(rand()%4)
        {
            case 0:
            {
                //vihreä
                c1 = Vector(0.2f, 0.7f, 0.3f);
                c2 = Vector(0.3f, 0.8f, 0.3f);
            } break;
            case 1:
            {
                //keltainen
                c1 = Vector(0.9f, 0.7f, 0.3f);
                c2 = Vector(1.0f, 0.8f, 0.3f);

            } break;
            case 2:
            {
                //oranssi
                c1 = Vector(0.8f, 0.4f, 0.1f);
                c2 = Vector(1.0f, 0.5f, 0.1f);
            } break;

            case 3:
            {
                //punainen
                c1 = Vector(0.8f, 0.2f, 0.1f);
                c2 = Vector(1.0f, 0.3f, 0.1f);
            } break;
        }

        float coloralpha = Mathematics::randBetween(0.25f, 0.5f);//0.5f;
        float colort = Mathematics::randFloat();
        particles[i].color = (c1 * (1-colort) + c2*colort)*coloralpha;
    }

	triggers = new TriggerSystem();
	triggers->add(186317, 187367);
	triggers->add(199184, 200234);
	triggers->add(193140, 193290);
	triggers->add(199649, 200699);
	triggers->add(200138, 201188);
	triggers->add(206938, 207988);
	triggers->add(213733, 214783);

	// TODO: plugaa nää johonki
}

Kliimaksi::~Kliimaksi()
{
}


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

