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

#include <math.h>

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

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

	const float fadeinstart = 0.0f;
	const float fadeinstop = 0.01f;
	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);
	
	filter.initDOF();
	 renderScene(pos, alpha);
	 render3ds(pos, alpha);
	filter.dof(0.97065f, 0.985f, 1.0199f, 4, 0.006f, 0.006f, 1.0f);

//    filter.glow(8, 0.005f, 0.005f, 0.92f, -1.0f, 1.0f);
}

SynkkaStrip::SynkkaStrip(int yres, float radius, float width)
{
    this->yres = yres;

    this->st = Mathematics::randBetween(0.085f, 0.7f);//Mathematics::randFloat();
    this->et = this->st + Mathematics::randBetween(0.04f,0.1f);

    this->vertices = new Vector[yres*2];
    this->normals = new Vector[yres*2];

    this->rot1 = Mathematics::randVectSphere()*2*3.151592f;
    this->rot2 = Mathematics::randVectSphere()*2*3.151592f;

    Vector rotate;
    rotate = Mathematics::randVectSphere()*2*3.151592f;

    Matrix rotmat;
    rotmat.makeRotation(rotate.x,rotate.y,rotate.z);

    const float arc = 2*3.141592f;
    
    float a = 0.0f;
    for (int y = 0; y < this->yres; y++)
    {
        int offset = y << 1;

        //ympyrä xy-tasossa
        Vector arcpoint = Vector(cosf(a), sinf(a), 0) * radius;
        Vector v1 = arcpoint + Vector(0, 0, -width);
        Vector v2 = arcpoint + Vector(0, 0,  width);

        this->normals[offset] = (v1 * rotmat).normalize();
        this->normals[offset+1] = (v2 * rotmat).normalize();
        
        this->vertices[offset] = v1 * rotmat;
        this->vertices[offset+1] = v2 * rotmat;

        a += arc / (this->yres-1);
    }
}

void SynkkaStrip::render(float pos, float alpha, float sync, float musta, float kerroin)
{
    int y;
/*
    glDisable(GL_TEXTURE_2D);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_DEPTH_TEST);
*/
    float poshere = Mathematics::calcPosFloat(pos, this->st,this->et);

    glPushMatrix();

	

    const float rotspeed = 0.06f;
    Vector rot = this->rot1*(1-pos) + this->rot2*pos;
    glRotatef(360*rotspeed*rot.x, 1, 0, 0);
    glRotatef(360*rotspeed*rot.y, 0, 1, 0);
    glRotatef(360*rotspeed*rot.z, 0, 0, 1);

    //Vector light = Vector(1, 0, 0);
	Matrix valorotate;
	valorotate.makeRotation(2.75f + 3.140f*pos, 0, 0);
	Vector light = Vector(1,1,1).normalize()*valorotate;

	glEnable(GL_DEPTH_TEST);
	glDisable(GL_BLEND);

    int drawcount = (int)(poshere*this->yres);
    glBegin(GL_TRIANGLE_STRIP);
    int offset = 0;
    for (y = 0; y < drawcount; y++)
    {
        //float l = 0.0f + 0.15f*this->normals[offset].dotProduct(light);
		float l = 0.15f*this->normals[offset].dotProduct(light);
		//glColor3f(0,0,0);
        glColor4f(l,l,l,musta*(1-kerroin));

        glVertex3fv((float *)&this->vertices[offset++]);
        glVertex3fv((float *)&this->vertices[offset++]);
    }
    glEnd();

	glEnable(GL_BLEND);
	glDisable(GL_DEPTH_TEST);
    if (sync > 0.0001f)
    {
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE);
		//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glLineWidth(2.5f);
		glEnable(GL_LINE_SMOOTH);
        //Vector synccolor = Vector(0.4f, 0.65f, 0.7f);//Vector(0.85f, 0.5f, 0.2f);
		Vector synccolor = Vector(0.8f, 0.4f, 0.1f);
		glColor4f(synccolor.x,synccolor.y,synccolor.z, sync/*alpha*0.8f*powf(sync, 1.7f)*/);
        glPushMatrix();
        float s = 1.3f - sync*0.3f;
        glScalef(s,s,s);
        glBegin(GL_LINE_STRIP);
        for (y = 0; y < drawcount; y++)
        {
            glVertex3fv((float *)&this->vertices[y << 1]);
        }
        glEnd();
        glBegin(GL_LINE_STRIP);
        for (y = 0; y < drawcount; y++)
        {
            glVertex3fv((float *)&this->vertices[(y << 1) + 1]);
        }
        glEnd();
        glPopMatrix();
        glDisable(GL_LINE_SMOOTH);
    }

    glPopMatrix();

	glEnable(GL_TEXTURE_2D);


}

SynkkaStrip::~SynkkaStrip()
{
    delete this->vertices;
    delete this->normals;

}
/*
public:

    SynkkaStrip(float radius);
    void render(float pos, float alpha);

    float st;
    float et;

    int yres;
    Vector *vertices;
    Vector *normals;
};
*/

void Synkkakappale::renderScene(float pos, float alpha)
{
    int i = 0;
    
	glDisable(GL_TEXTURE_2D);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    //glEnable(GL_TEXTURE_2D);
    glEnable(GL_BLEND);
	glEnable(GL_DEPTH_TEST);

    int realtime = dmsGetModulePosition();
    float pysyvyys = 0;//powf(sinf(Mathematics::calcPosFloat(realtime*1.0f, 94200+8000, 95800+8000)*3.141592f*0.5f), 1.7f);
    float sync = triggers->get(realtime) + pysyvyys;
    cam->useCamera(0);

    glPushMatrix();
	const float kerroin = (powf(sinf(Mathematics::calcPosFloat(realtime*1.0f, 104000, 104500)*3.141592f*0.5f), 3));
    float s = 0.8f+20.0f*kerroin;
    glScalef(s,s,s);
	if(kerroin<0.999f)
    for (i = 0; i < count; i++)
    {
        strips[i]->render(pos, alpha, sync, 1-pysyvyys, kerroin);

    }
    glPopMatrix();
}




Synkkakappale::Synkkakappale()
{	
    int i;
    count = 50;
    strips = new SynkkaStrip*[count];

    srand(1701011);
    for (i = 0; i < count; i++)
    {
        strips[i] = new SynkkaStrip(100, 
                                    Mathematics::randBetween(1, 3), 
                                    Mathematics::randBetween(0.035f, 0.047f));

    }

    triggers = new TriggerSystem();
    triggers->add(88000+7500, 88500+7500);
    triggers->add(89000+8000, 90000+8000);
    triggers->add(90800+8000, 91800+8000);
    triggers->add(92500+8000, 93500+8000);
    triggers->add(94200+8000, 95200+8000);
}

Synkkakappale::~Synkkakappale()
{
    int i;
    for (i = 0; i < count; i++)
    {
        delete strips[i];
    }
    delete [] strips;
	
	model->freeVBO();
	delete model;
}


bool Synkkakappale::init(unsigned long s, unsigned long e)
{

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

	startTime = s;
	endTime = e;
	return true;
}



void Synkkakappale::render3ds(float pos, float alpha)
{
	cam->useCamera(0);

	// Kämynen fadeout .. 
	//if(pos>0.5f)
	{
		float a = (1-Mathematics::calcPosCos(pos, 0.9f, 0.95f))* (pos>0.95f ? 0 : 1);
		glColor4f(a,a,a,a);
		glTranslatef(5*a*a - 5, -7*a*a + 7, -5*a + 5);
		glRotatef(a*110.0f, 0.2f, 1.0f, -0.3f);
	}

	const float in_ = (1-Mathematics::calcPosFloat(pos, 0.0f, 0.5f));
	glTranslatef(3*in_*in_*in_ , 2*in_*in_, 0);
	
	glDisable(GL_BLEND);
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_TEXTURE_2D);

    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	
	shaders.synkka->bind();

	glActiveTextureARB(GL_TEXTURE0_ARB);
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, dmsGetTexture("organic01.jpg")->getID());
	shaders.synkka->setUniform1i("tex0", 0);

	glActiveTextureARB(GL_TEXTURE1_ARB);
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, dmsGetTexture("cau_009.jpg")->getID());
	shaders.synkka->setUniform1i("tex1", 1);

	glActiveTextureARB(GL_TEXTURE2_ARB);
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, dmsGetTexture("dirt2.jpg")->getID());
	shaders.synkka->setUniform1i("tex2", 2);

	int realtime = dmsGetModulePosition();
    float pysyvyys = powf(sinf(Mathematics::calcPosFloat(realtime*1.0f, 94200+8000, 95800+8000)*3.141592f*0.5f), 1.7f);
    float sync = triggers->get(realtime) + pysyvyys;

	shaders.synkka->setUniform1f("scale", sync);

	//Vector light = Vector(1, 25, 0);
	//light = light.normalize();
	glTranslatef(0,0,-3*(1-Mathematics::calcPosSmooth(pos, 0.0, 0.13f)));

	Matrix valorotate;
	//valorotate.makeRotation(20.0f*pos, 0, 0);
	valorotate.makeRotation(6.0f*pos, 0, 0);
	Vector light = Vector(1,1,1).normalize()*valorotate;
	shaders.lightfade->setUniform3f("lightDir", light.x, light.y, light.z);

	glColor4f(alpha,alpha,alpha, alpha);

			glPushMatrix();
				
				glScalef(0.009f,0.009f,0.009f);

				glRotatef(pos*19.0f+175, -0.64f, -0.34f, 0.7f);

					// piirtää
					// * normaalit
					// * uv:t
					// * facet
					model->renderVBO();

			glPopMatrix();


	shaders.unbind();

	glActiveTextureARB(GL_TEXTURE2_ARB);
	glDisable(GL_TEXTURE_2D);

	glActiveTextureARB(GL_TEXTURE1_ARB);
	glDisable(GL_TEXTURE_2D);
	
	glActiveTextureARB(GL_TEXTURE0_ARB);

}