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

#include <math.h>

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

void Mustikka::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 Mustikka::renderScene(float pos, float alpha)
{
    int i;
    int j;
    cam->useCamera(0);

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


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

	glRotatef(14, -1,1,1);

	float time = dmsGetModulePosition();
	float sync = trigger->get(time);
	if(trigger->getChanged())
		pari = !pari;

    filter.init(true);

    glEnable(GL_BLEND);
    glLineWidth(2.0f);
    glEnable(GL_LINE_SMOOTH);
    glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);

    for (i = 0; i < vcount; i++)
    {
        const float varpu_t = sinf(Mathematics::calcPosFloat(pos, varvut[i]->st, varvut[i]->et)*3.141592f);
        const float varpu_t2 = sinf(Mathematics::calcPosFloat(pos, varvut[i]->st, varvut[i]->et)*3.141592f*0.5f);
        if (varpu_t >= 0.0001f && varpu_t <= 1.0000f)
        {
            Vector p = varvut[i]->p * (1 - varpu_t2) + varvut[i]->p2 * varpu_t2;
            glPushMatrix();
            glTranslatef(p.x, p.y, p.z);

            //rungot
            //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			glBlendFunc(GL_SRC_ALPHA, GL_ONE);
            glDisable(GL_TEXTURE_2D);
            glDisable(GL_DEPTH_TEST);
            for (j = 0; j < varvut[i]->splinecount; j++)
            {
                Vector c = varvut[i]->splinecolors[j];
                glColor4f(c.x, c.y, c.z,alpha*0.7f*varpu_t);

                const float spline_t = varpu_t;///////////Mathematics::calcPosFloat(varpu_t, varvut[i]->splinest[j], varvut[i]->splineet[j]);

                glBegin(GL_LINE_STRIP);
                for (float t = 0.0f; t < spline_t; t += 0.01f)
                {
                    Vector point = varvut[i]->splines[j]->getValue(t);
                    glVertex3fv((float *)&point);
                }
                glEnd();
            }
            //marjat
            float marja_alpha = 0.8f;
            glEnable(GL_TEXTURE_2D);
            glBlendFunc(GL_SRC_ALPHA, GL_ONE);
            glBindTexture(GL_TEXTURE_2D, dmsGetTexture("fireparticle.jpg")->getID());
            glColor4f(1,1,1,alpha*marja_alpha*varpu_t);
            glBegin(GL_QUADS);
            for (j = 0; j < varvut[i]->marjacount; j++)
            {
                Vector p = varvut[i]->marjat[j].pos;
                const float size = 0.03f + (pari == true ? 0 : sync * 0.0075f);
	            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();

            glEnable(GL_TEXTURE_2D);
            glBlendFunc(GL_SRC_ALPHA, GL_ONE);
            glBindTexture(GL_TEXTURE_2D, dmsGetTexture("purpleparticle.jpg")->getID());
            glColor4f(1,1,1,alpha*marja_alpha*varpu_t);
            glBegin(GL_QUADS);
            for (j = 0; j < varvut[i]->marjacount2; j++)
            {
                Vector p = varvut[i]->marjat2[j].pos;
                //const float size = 0.05f;
				const float size = 0.05f + (pari == false ? 0 : sync * 0.0055f);
	            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();

            glPopMatrix();
        }
    }
    glDisable(GL_LINE_SMOOTH);
    filter.glow(7, 0.006f, 0.006f, 0.915f, -1.0f, 1.0f);

}




Mustikka::Mustikka()
{	
    int i;
    int j;

    int k;

    float kuukulma1 = 0.1f;//0.7f;
    float kuukulma2 = 0.1f;//0.7f;

    float kul = 0.1f;
    float kuudist = 50;
/*
    k1 = Mathematics::sphereToCartesian(kuudist, kuukulma1 - kul*0.5f, kuukulma2-kul);
    k2 = Mathematics::sphereToCartesian(kuudist, kuukulma1 - kul*0.5f, kuukulma2+kul);
    k3 = Mathematics::sphereToCartesian(kuudist, kuukulma1 + kul*0.5f, kuukulma2+kul);
    k4 = Mathematics::sphereToCartesian(kuudist, kuukulma1 + kul*0.5f, kuukulma2-kul);

    dmsMsg("k1 = %f %f %f\n", k1.x, k1.y, k1.z);
    dmsMsg("k2 = %f %f %f\n", k2.x, k2.y, k2.z);
    dmsMsg("k3 = %f %f %f\n", k3.x, k3.y, k3.z);
    dmsMsg("k4 = %f %f %f\n", k4.x, k4.y, k4.z);
*/

    vcount = 65;
    varvut = new Varpu*[vcount];

    srand(10199);
    for (i = 0; i < vcount; i++)
    {
        varvut[i] = new Varpu();
        varvut[i]->st = Mathematics::randFloat();
        //lopussa kestävät hieman vähemmän
        varvut[i]->et = varvut[i]->st + 0.2f + 0.2f * Mathematics::randFloat() * (0.5f+0.5f*(1-varvut[i]->st));

        varvut[i]->p = Mathematics::randVectSphere() * powf(Mathematics::randFloat(), 0.6f)*3;
        varvut[i]->p2 = varvut[i]->p + Mathematics::randVectSphere() * powf(Mathematics::randFloat(), 0.6f)*0.2f;
        const float lowerlimit = 0.9f;
        if (varvut[i]->p.y < lowerlimit)
        {
            varvut[i]->p.y += 3.3f;//fabsf(varvut[i]->p.y)*1.7f;
            varvut[i]->p2.y += 3.3f;//fabsf(varvut[i]->p.y)*1.7f;
        }

/*
        const float color_t = Mathematics::randFloat();
        Vector color1 = Vector(0.4f, 0.7f, 0.54f);
        Vector color2 = Vector(0.2f, 0.8f, 0.14f);
*/
        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();
        varvut[i]->color = (c1 * (1-colort) + c2*colort)*coloralpha;

//        varvut[i]->color = color1 * color_t + color2 * (1-color_t);

        varvut[i]->splinecount = 20;

        varvut[i]->marjacount = varvut[i]->splinecount*4;
        varvut[i]->marjat = new Marja[varvut[i]->marjacount];
        varvut[i]->marjacount2 = varvut[i]->splinecount;
        varvut[i]->marjat2 = new Marja[varvut[i]->marjacount];

        varvut[i]->splines = new CatmullRom*[varvut[i]->splinecount];
        varvut[i]->splinecolors = new Vector[varvut[i]->splinecount];
        varvut[i]->splinest = new float[varvut[i]->splinecount];
        varvut[i]->splineet = new float[varvut[i]->splinecount];

        varvut[i]->splinest[0] = varvut[i]->st;
        varvut[i]->splineet[0] = varvut[i]->et;

        const int minsplinepoints = 15;
        const int maxsplinepoints = 20;

        for (j = 0; j < varvut[i]->splinecount; j++)
        {
            float jt = j / (float)varvut[i]->splinecount;
            varvut[i]->splinecolors[j] = varvut[i]->color * (1 - jt);
            
            const float mindelta = 0.2f + j*0.07f;
            const float maxdelta = 0.7f + j*0.07f;
            const float speed = (1.0f - j / (float)(varvut[i]->splinecount + 2))*0.27f;

            Vector point = Vector(0, 0, 0);
            float angle1 = 0;
            float angle2 = 0;
            float angledelta1 = mindelta + Mathematics::randFloat()*(maxdelta - mindelta);
            float angledelta2 = mindelta + Mathematics::randFloat()*(maxdelta - mindelta);

            //parent
            if (j == 0)
            {
                angle1 = Mathematics::randFloat()*2*3.141592f;
                angle2 = Mathematics::randFloat()*2*3.141592f;

                point = Vector(0, 0, 0);
            }
            else if (j == 1)
            {
                angle1 = Mathematics::randFloat()*2*3.141592f;
                angle2 = Mathematics::randFloat()*2*3.141592f;

                float point_t = 0.2f+0.6f*Mathematics::randFloat();
                point = varvut[i]->splines[0]->getValue(point_t);
                varvut[i]->splinest[j] = Mathematics::calcPosFloat(point_t, varvut[i]->st, varvut[i]->et);
            }
            else
            {
                int splineIndex = rand() % j; //j > 2 

                float point_t = 0.2f+0.6f*Mathematics::randFloat();
                point = varvut[i]->splines[splineIndex]->getValue(point_t);
                varvut[i]->splinest[j] = Mathematics::calcPosFloat(point_t, varvut[i]->splinest[splineIndex], varvut[i]->splineet[splineIndex]);
                varvut[i]->splineet[j] = varvut[i]->splinest[j] + 0.74f;

                const float epsilon = 0.03f;
                Vector suunta = (varvut[i]->splines[splineIndex]->getValue(point_t + epsilon) - point).normalize();
                Vector temp = Mathematics::cartesianToSphere(suunta.x, suunta.y, suunta.z);

                angle1 = temp.y;
                angle2 = temp.z;

            }

            const int splinepoints = minsplinepoints + (rand()%(maxsplinepoints - minsplinepoints)); //>maxsplinepoints -> crash
            varvut[i]->splines[j] = new CatmullRom(splinepoints);

            if (j == 0)
            {
                for (k = 0; k < splinepoints; k++)
                {
                    const float kt = k / (float)splinepoints;
                    varvut[i]->splines[j]->addPoint(point);

                    angle1 += angledelta1;
                    angle2 += angledelta2;

                    point += Mathematics::sphereToCartesian(speed, angle1, angle2);

                }
            }
            else
            {
                varvut[i]->splines[j]->addPoint(point);
                for (k = 1; k < splinepoints; k++)
                {
                    const float kt = k / (float)splinepoints;
                    varvut[i]->splines[j]->addPoint(point);

                    angle1 += angledelta1;
                    angle2 += angledelta2;

                    point += Mathematics::sphereToCartesian(speed, angle1, angle2);
                }

            }
        }

        for (j = 0; j < varvut[i]->marjacount; j++)
        {
            int splineIndex = rand() % varvut[i]->splinecount;
            float marja_t = Mathematics::randFloat();
            varvut[i]->marjat[j].pos = varvut[i]->splines[splineIndex]->getValue(marja_t);

        }
        for (j = 0; j < varvut[i]->marjacount2; j++)
        {
            int splineIndex = j;//varvut[i]->splinecount;
            varvut[i]->marjat2[j].pos = varvut[i]->splines[splineIndex]->getValue(1.0f); //TÄMÄ RIVI KAATAA VITTU
			// LOL :-)	
        }
    }

	pari = false;
	trigger = new TriggerSystem();		
/*	trigger->add(21751,21901);
	trigger->add(22963,23113);
	trigger->add(24290,24440);
	trigger->add(25151,25301);
	trigger->add(26012,26162);
	trigger->add(27757,27907);
*/
	const int LISAA_AIKAA = 450;
	trigger->add(28595,28745+LISAA_AIKAA);
	trigger->add(29503,29653+LISAA_AIKAA);
	trigger->add(31132,31282+LISAA_AIKAA);
	trigger->add(32073,32223+LISAA_AIKAA);
	trigger->add(32887,33037+LISAA_AIKAA);
	trigger->add(33693,33843+LISAA_AIKAA);
	trigger->add(34158,34308+LISAA_AIKAA);
	trigger->add(33317,33467+LISAA_AIKAA);
	trigger->add(34597,34747+LISAA_AIKAA);
	trigger->add(35460,35610+LISAA_AIKAA);
	trigger->add(36400,36550+LISAA_AIKAA);
	trigger->add(37089,37239+LISAA_AIKAA);
	trigger->add(38053,38203+LISAA_AIKAA);
	trigger->add(39798,39948+LISAA_AIKAA);
	trigger->add(38858,39008+LISAA_AIKAA);
	trigger->add(40557,40707+LISAA_AIKAA);
	trigger->add(42302,42452+LISAA_AIKAA);
	trigger->add(44001,44151+LISAA_AIKAA);
	trigger->add(45677,45827+LISAA_AIKAA);

	trigger->add(48400,48550+LISAA_AIKAA);
	trigger->add(49249,50299+LISAA_AIKAA);
	trigger->add(41509,41659+LISAA_AIKAA);
	trigger->add(43208,43358+LISAA_AIKAA);

	trigger->add(44883,45033+LISAA_AIKAA);
	trigger->add(46606,46756+LISAA_AIKAA);
	trigger->add(56034,57084+LISAA_AIKAA);
	trigger->add(62799,63849+LISAA_AIKAA);
}

Mustikka::~Mustikka()
{
    int i;
    int j;

    for (i = 0; i < vcount; i++)
    {

		delete [] varvut[i]->marjat;
		delete [] varvut[i]->marjat2;


        for (j = 0; j < varvut[i]->splinecount; j++)
        {
            delete varvut[i]->splines[j];
        }
		
        delete [] varvut[i]->splines;
        delete [] varvut[i]->splinecolors;
        delete [] varvut[i]->splinest;
        delete [] varvut[i]->splineet;
		

        delete varvut[i];
    }
    delete [] varvut;

}


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

