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

#pragma warning(disable: 4305)

#include <math.h>

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


//#define KUKKADEBUG

void BezierKukka::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.86f;
	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 Kukkaspiraali::draw(float pos, float alpha)
{
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);
    glDisable(GL_TEXTURE_2D);
    glColor4f(this->color.x, this->color.y, this->color.z, alpha*0.56f);
    glDisable(GL_DEPTH_TEST);

    Vector p = this->movedelta * pos;
    glBegin(GL_LINE_STRIP);
    for (int i = 0; i < this->count; i++)
    {
        glVertex3fv((float *)&(p + this->vertices[i]));
    }
    glEnd();
}

void BezierKukka::renderScene(float pos, float alpha)
{
    int i;
    cam->useCamera(5);

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

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

	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;

    glDepthMask(0);
	glBindTexture(GL_TEXTURE_2D, dmsGetTexture("dirt5.jpg")->getID());
	Primitives::renderTexturedPlaneWithFadeOut(p1,p2,p3,p4, 25, 60, Vector(0.541f*alpha,0.541f*alpha,0.541f*alpha), Vector(), 5.0f, 12.0f, alpha*0.7f);

    int realtime = dmsGetModulePosition();
    float kuva1alpha = (1-Mathematics::calcPosFloat(pos, 0.986f, 1.0f))*(Mathematics::calcPosFloat(realtime*1.0f, 249000, 250000));

	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glDepthMask(1);
    filter.init(true);

    glLineWidth(3.0f);  
    glEnable(GL_LINE_SMOOTH);
    for (i = 0; i < spiraalicount; i++)
    {
        spiraalit[i]->draw(pos, alpha*kuva1alpha);
    }
    glDisable(GL_LINE_SMOOTH);
    glLineWidth(1.0f);  


    for (i = 0; i < flowercount; i++)
    {
        float t = Mathematics::calcPosFloat(pos, flowers[i]->st, flowers[i]->et);
        if (t > 0.00001f && t <= 1.0000f)
        {
            flowers[i]->draw(alpha, t);
        }
    }
    filter.glow(5, 0.005f, 0.005f, 0.92f, -1.0f, 1.0f);
}

ParticleBezier::ParticleBezier(int particlecount, int maxpoints)
{
    int i = 0;
    this->bezierpoints = maxpoints;
    this->curve = new Bezier(maxpoints);
    this->usedcurve = new Bezier(maxpoints);
    this->pcount = particlecount;
    this->particles = new StreamParticle[particlecount];

    const float globalspeed = 1.2f;
    for (i = 0; i < this->pcount; i++)
    {
        this->particles[i].colorphase = (Mathematics::randFloat())*globalspeed;
        this->particles[i].colorspeed = (5.3f + 7.5f * Mathematics::randFloat())*globalspeed;
        this->particles[i].positionphase = (Mathematics::randFloat())*globalspeed;
        this->particles[i].positionspeed = (1.0f + 2.0f * Mathematics::randFloat())*globalspeed;
        this->particles[i].movephase1 = (Mathematics::randFloat())*globalspeed;
        this->particles[i].movephase2 = (Mathematics::randFloat())*globalspeed;
        this->particles[i].movephase3 = (Mathematics::randFloat())*globalspeed;
        this->particles[i].movespeed1 = (3 + 4.0f * Mathematics::randFloat())*globalspeed;
        this->particles[i].movespeed2 = (3 + 4.0f * Mathematics::randFloat())*globalspeed;
        this->particles[i].movespeed3 = (1 + 2.0f * Mathematics::randFloat())*globalspeed;
        this->particles[i].moveradius = 0.05f + 0.10f*Mathematics::randFloat();
    }
}

void ParticleBezier::draw(float pos, float alpha, Vector &color)
{
    int i = 0;
	Vector x, y, z;
	Mathematics::antiRotate(&x, &y, &z);

    float bezier_t = powf(sinf(pos*3.141592f*0.5f), 0.4f);
/*
    if (bezier_t > 1.0f)
    {
        bezier_t = 1.0f;
    }
*/
    for (i = 0; i < this->bezierpoints; i++)
    {
        Vector point = this->curve->points[i]*bezier_t;
        Vector tangent = this->curve->tangents[i]*bezier_t;
        this->usedcurve->setPoint(i, point, tangent);
    }

//    dmsMsg("draw()\n");
#ifdef KUKKADEBUG
    glDisable(GL_TEXTURE_2D);
    glColor4f(1,0,0,1);
    glBegin(GL_LINE_STRIP);

    for (float t = 0.0f; t < 1.0f; t += 0.01f)
    {
        glVertex3fv((float *)&this->usedcurve->getValue(t));
    }
    glEnd();
    glEnable(GL_TEXTURE_2D);
#endif

    
    glDisable(GL_TEXTURE_2D);
    glColor4f(color.x, color.y, color.z, alpha*0.3f);
    glBegin(GL_LINE_STRIP);

    for (float t = 0.0f; t < 1.0f; t += 0.01f)
    {
        glVertex3fv((float *)&this->usedcurve->getValue(t));
    }
    glEnd();
    glEnable(GL_TEXTURE_2D);
    glBegin(GL_QUADS);
    for (i = 0; i < this->pcount; i ++)
    {
        StreamParticle *p = &this->particles[i];
        float post = fmodf(p->positionphase + p->positionspeed*pos, 1);

        float colort = fmodf(p->colorphase + p->colorspeed*pos, 1);
        float movet1 = fmodf(p->movephase1 + p->movespeed1*pos, 1);
        float movet2 = fmodf(p->movephase2 + p->movespeed2*pos, 1);
        float movet3 = fmodf(p->movephase3 + p->movespeed3*pos, 1);

        const float a = powf(sinf(colort*3.141592f), 3) * sinf(post*3.141592f)*alpha;
        Vector displace = Vector(cosf(movet1*3.141592f*2), sinf(movet2*3.141592f*2), cosf(movet3*3.141592f*2));

        Vector position = this->usedcurve->getValue(post) + displace*0.04f*cosf(colort*3.141592f*2);
        Vector actualposition = Vector(position.x, position.y, position.z);

        glColor4f(1, 1, 1, a*0.8f);
        float size = 0.01f + 0.08f*(1-a);

	    Vector v1 = actualposition - x*size - y*size;
	    Vector v2 = actualposition + x*size - y*size;
	    Vector v3 = actualposition + x*size + y*size;
	    Vector v4 = actualposition - 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();
}

void ParticleBezier::addPoint(Vector &point, Vector &tangent)
{
    this->curve->addPoint(point, tangent);
}
void ParticleBezier::setPoint(int index, Vector &point, Vector &tangent)
{
    this->curve->setPoint(index, point, tangent);
}

Petal::Petal(float kulma, float lehdenkulma, float yla, Matrix &rot, Vector &petalcolor)
{
    left = new ParticleBezier(20, 2);
    right = new ParticleBezier(20 , 2);

    float ylospain = yla;//0.15f;
    float lehdenpituus = Mathematics::randBetween(0.6f, 0.8f);
    float tangentinpituus = 0.4f;
    
    Vector startpoint = Vector(0, 0, 0);
    Vector endpoint = Vector(cosf(kulma)*lehdenpituus, ylospain, sinf(kulma)*lehdenpituus)*rot;
    Vector endtangent = endpoint*0.2f;

    this->edgecolor = Vector(1.0f, 0.5f, 0.2f);
    this->petalcolor = petalcolor;

    this->start = startpoint;
    this->end = endpoint;

    Vector tangentleft = (Vector(cosf(kulma-lehdenkulma), 0, sinf(kulma-lehdenkulma))*tangentinpituus)*rot; 
    Vector tangentright = (Vector(cosf(kulma+lehdenkulma), 0, sinf(kulma+lehdenkulma))*tangentinpituus)*rot; 

    left->addPoint(startpoint, tangentleft);
    left->addPoint(endpoint, endtangent);
    right->addPoint(startpoint, tangentright);
    right->addPoint(endpoint, endtangent);
}

void Petal::draw(float pos, float alpha)
{
    //reunaviivat + particlet
    glDisable(GL_DEPTH_TEST);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);
    left->draw(pos, alpha, this->edgecolor);
    right->draw(pos, alpha, this->edgecolor);

    //terälehdet
    glDisable(GL_TEXTURE_2D);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glBegin(GL_TRIANGLE_STRIP);
    for (float t = 0.0f; t < 1.0f; t += 0.1f)
    {
        glColor4f(this->petalcolor.x, this->petalcolor.y,this->petalcolor.z,alpha*0.35f*(1-t));
		//glColor4f(this->petalcolor.x, this->petalcolor.y,this->petalcolor.z,alpha*1.0f*(1-t));
        glVertex3fv((float *)&left->usedcurve->getValue(t));
        glVertex3fv((float *)&right->usedcurve->getValue(t));
    }
    glEnd();


#ifdef KUKKADEBUG
    glDisable(GL_TEXTURE_2D);
    glColor4f(0,1,1,1);
    glBegin(GL_LINES);
    glVertex3fv((float *)&this->start);
    glVertex3fv((float *)&this->end);
    glEnd();
    glEnable(GL_TEXTURE_2D);
#endif

}

Flower::Flower(int petalcount)
{
    int i;
    const int bezierpoints = 2;
//    this->beziercount = petalcount*2;

    this->st = Mathematics::randBetween(0.01f, 0.96f);
    this->et = this->st + 0.59f+powf(Mathematics::randFloat(), 3.0f)*0.18f;//(randBetween(0.04f, 0.06f);

    this->petalcount = petalcount;
    petals = new Petal*[petalcount];

    Matrix rotation;
    rotation.makeRotation(Mathematics::randBetween(0.0f, 0.4f), 
                          Mathematics::randFloat()*2*3.141592f, 
                          Mathematics::randBetween(0.0f, 0.4f));

    Vector petalcolor = Vector(0,0,0);
    switch(rand()%3)
    {
        case 0: this->textureID = dmsGetTexture("fireparticle.jpg")->getID(); break;
        case 1: this->textureID = dmsGetTexture("redparticle.jpg")->getID(); break;
        case 2: this->textureID = dmsGetTexture("blueparticle.jpg")->getID(); break;
    }

    switch(rand()%3)
    {
        case 0: petalcolor = Vector(0.3f, 0.4f, 0.7f); break;
        case 1: petalcolor = Vector(0.7f, 0.4f, 0.3f); break;
        case 2: petalcolor = Vector(0.7f, 0.55f, 0.3f); break;
    }
    
    float lehdenkulma = Mathematics::randBetween(0.8f, 1.2f);
    float yla = Mathematics::randBetween(0.15f, 0.3f);
    for (i = 0; i < petalcount; i++)
    {
        float it = i / (float)petalcount;
        petals[i] = new Petal(it*2*3.141592f, lehdenkulma, yla, rotation, petalcolor);
    }

    this->pos = Mathematics::randVectPlane()*Mathematics::randBetween(0.16f, 3.0f);
    this->pos.y = Mathematics::randBetween(0.3f, 1.8f);

    Vector maapos = Vector(0, 0, 0);
    maapos.y = -1.2f;

    //varsi = new ParticleBezier(40, 2);
	varsi = new ParticleBezier(80, 2);
    varsi->addPoint(maapos, Vector(0, 1, 0));
    varsi->addPoint(Vector(0, 0, 0), Vector(0, -1, 0)*rotation);


}
Flower::~Flower()
{
}


void Flower::draw(float alpha, float t)
{
    int i;

    glPushMatrix();
    glTranslatef(this->pos.x, this->pos.y, this->pos.z);
 
    //TODO: siirrä nämä pois sitten kun kukka on debugattu
    glEnable(GL_TEXTURE_2D);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);//(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glDisable(GL_DEPTH_TEST);
    glBindTexture(GL_TEXTURE_2D, this->textureID);

    float alphahere = sinf(t*3.141592f);
    for (i = 0; i < petalcount; i++)
    {
        petals[i]->draw(t, alpha * alphahere);
    }
    glBindTexture(GL_TEXTURE_2D, dmsGetTexture("greenflare.png")->getID());
    varsi->draw(t, alpha*alphahere, Vector(0.4f, 1.0f, 0.4f));
    glPopMatrix();
}


BezierKukka::BezierKukka()
{
    int i;
    flowercount = 20;
    flowers = new Flower*[flowercount];

    //srand(17019);
	//srand(17022);
	srand(17030);
    for (i = 0; i < flowercount; i++)
    {
        flowers[i] = new Flower(7);
    }


    spiraalicount = 40;
    spiraalit = new Kukkaspiraali*[spiraalicount];
    
    for (i = 0; i < spiraalicount; i++)
    {
        spiraalit[i] = new Kukkaspiraali();
        spiraalit[i]->count = 100;
        spiraalit[i]->vertices = new Vector[spiraalit[i]->count];

        float splinetime = spiraalit[i]->st + 0.05f;
        if (splinetime > 1.0f)
            splinetime = 1.0f;

        float ga = Mathematics::randFloat()*2*3.141592f;
        float gr = 2 + powf(Mathematics::randFloat(), 0.4f)*5.0f;

        Vector p = Vector(cosf(ga), 0, sinf(ga))*gr;

        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();
        spiraalit[i]->color = (c1 * (1-colort) + c2*colort)*coloralpha;

        float movea = Mathematics::randFloat()*2*3.141592f;
        spiraalit[i]->movedelta = Vector(cosf(movea), 0, sinf(movea))*(0.3f+Mathematics::randFloat());
/*

        switch(rand()%2)
        {
            case 0: 
                spiraalit[i]->color = Vector(1 - Mathematics::randFloat()*0.2f, 0.2f, 0.2f);
                break;

            case 1: 
                spiraalit[i]->color = Vector(0.5f, 0.5f, 1.0f - Mathematics::randFloat()*0.15f);
                break;
        }
*/
        float koko = 1.03f + powf(Mathematics::randFloat(), 5.5f)*2.26f;//Mathematics::randBetween(0.08f, 0.15f);
        float kiertyma = Mathematics::randBetween(3, 5)*2*3.141592f;

        for (int j = 0; j < spiraalit[i]->count; j++)
        {
            float t = j / (float)spiraalit[i]->count;

            float radius = koko * powf(t, 2.5f);
            float a = kiertyma * t;

            spiraalit[i]->vertices[j] = p + (Vector(cosf(a), 0, sinf(a))*radius);
        }
    }






}

BezierKukka::~BezierKukka()
{
}


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

