#define GLEW_STATIC
#define GLM_FORCE_RADIANS

#include <iostream>
#include <fstream>
#include <sstream>

#include <GL/glew.h>
#include <GL/glu.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>
#include <SOIL/SOIL.h>

#include <time.h>
#include <stdio.h>

#include <websock/websock.h>

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include "camera.hpp"
#include "texture.hpp"
#include "shader.hpp"
#include "thing.hpp"

SDL_Window *window;
SDL_GLContext context;
float mL = 0;
float mR = 0;
int screenWidth = 1920;
int screenHeight = 1080;
float lastX = 400;
float lastY = 300;
bool firstMouse = true;
bool keys[1024];
bool anim = 1;
int tick = 0;

glm::vec4 bg = {0.0f, 0.0f, 0.0f, 1.0f};

enum anim_statess {
    ANIM_1 = 1,
    ANIM_2 = 2,
    ANIM_3 = 3,
    ANIM_4 = 4,
    ANIM_5 = 5,
    ANIM_6 = 6,
    ANIM_7 = 7,
    ANIM_71 = 71,
    ANIM_8 = 8,
    ANIM_9 = 9,
    ANIM_10,
    ANIM_11,
    ANIM_12,
    ANIM_13,
    ANIM_14,
    ANIM_15
};

int ANIM_STATE = ANIM_1;

Camera camera(glm::vec3(5.0f, 5.0f, 5.0f));

/* GLfloat vertices[] = { */
/*     0.5f,  0.5f, 0.0f,  0.0f, 0.0f,    // Top Right */
/*     0.5f, -0.5f, 0.0f,  1.0f, 0.0f,    // Bottom Right */
/*     -0.5f, -0.5f, 0.0f,  1.0f, 1.0f,    // Bottom Left */
/*     -0.5f,  0.5f, 0.0f,  0.0f, 1.0f     // Top Left */ 
/* }; */

GLfloat vertices[] = {
    -0.5f, -0.5f, -0.5f,  0.0f, 0.0f, 0.0f,  0.0f, -1.0f,
    0.5f, -0.5f, -0.5f,  1.0f, 0.0f,  0.0f,  0.0f, -1.0f,
    0.5f,  0.5f, -0.5f,  1.0f, 1.0f,  0.0f,  0.0f, -1.0f,
    0.5f,  0.5f, -0.5f,  1.0f, 1.0f,  0.0f,  0.0f, -1.0f,
    -0.5f,  0.5f, -0.5f,  0.0f, 1.0f, 0.0f,  0.0f, -1.0f,
    -0.5f, -0.5f, -0.5f,  0.0f, 0.0f, 0.0f,  0.0f, -1.0f,
                                                          
    -0.5f, -0.5f,  0.5f,  0.0f, 0.0f, 0.0f,  0.0f,  1.0f,
    0.5f, -0.5f,  0.5f,  1.0f, 0.0f,  0.0f,  0.0f,  1.0f,
    0.5f,  0.5f,  0.5f,  1.0f, 1.0f,  0.0f,  0.0f,  1.0f,
    0.5f,  0.5f,  0.5f,  1.0f, 1.0f,  0.0f,  0.0f,  1.0f,
    -0.5f,  0.5f,  0.5f,  0.0f, 1.0f, 0.0f,  0.0f,  1.0f,
    -0.5f, -0.5f,  0.5f,  0.0f, 0.0f, 0.0f,  0.0f,  1.0f,
                                                          
    -0.5f,  0.5f,  0.5f,  1.0f, 0.0f, 1.0f,  0.0f,  0.0f,
    -0.5f,  0.5f, -0.5f,  1.0f, 1.0f, 1.0f,  0.0f,  0.0f,
    -0.5f, -0.5f, -0.5f,  0.0f, 1.0f, 1.0f,  0.0f,  0.0f,
    -0.5f, -0.5f, -0.5f,  0.0f, 1.0f, 1.0f,  0.0f,  0.0f,
    -0.5f, -0.5f,  0.5f,  0.0f, 0.0f, 1.0f,  0.0f,  0.0f,
    -0.5f,  0.5f,  0.5f,  1.0f, 0.0f, 1.0f,  0.0f,  0.0f,
                                                          
    0.5f,  0.5f,  0.5f,  1.0f, 0.0f,  1.0f,  0.0f,  0.0f,
    0.5f,  0.5f, -0.5f,  1.0f, 1.0f,  1.0f,  0.0f,  0.0f,
    0.5f, -0.5f, -0.5f,  0.0f, 1.0f,  1.0f,  0.0f,  0.0f,
    0.5f, -0.5f, -0.5f,  0.0f, 1.0f,  1.0f,  0.0f,  0.0f,
    0.5f, -0.5f,  0.5f,  0.0f, 0.0f,  1.0f,  0.0f,  0.0f,
    0.5f,  0.5f,  0.5f,  1.0f, 0.0f,  1.0f,  0.0f,  0.0f,
                                                          
    -0.5f, -0.5f, -0.5f,  0.0f, 1.0f, 0.0f, -1.0f,  0.0f,
    0.5f, -0.5f, -0.5f,  1.0f, 1.0f,  0.0f, -1.0f,  0.0f,
    0.5f, -0.5f,  0.5f,  1.0f, 0.0f,  0.0f, -1.0f,  0.0f,
    0.5f, -0.5f,  0.5f,  1.0f, 0.0f,  0.0f, -1.0f,  0.0f,
    -0.5f, -0.5f,  0.5f,  0.0f, 0.0f, 0.0f, -1.0f,  0.0f,
    -0.5f, -0.5f, -0.5f,  0.0f, 1.0f, 0.0f, -1.0f,  0.0f,
                                                          
    -0.5f,  0.5f, -0.5f,  0.0f, 1.0f, 0.0f,  1.0f,  0.0f,
    0.5f,  0.5f, -0.5f,  1.0f, 1.0f,  0.0f,  1.0f,  0.0f,
    0.5f,  0.5f,  0.5f,  1.0f, 0.0f,  0.0f,  1.0f,  0.0f,
    0.5f,  0.5f,  0.5f,  1.0f, 0.0f,  0.0f,  1.0f,  0.0f,
    -0.5f,  0.5f,  0.5f,  0.0f, 0.0f, 0.0f,  1.0f,  0.0f,
    -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,  0.0f,  1.0f,  0.0f
};

glm::vec3 cubePositions[] = {
    glm::vec3( 0.0f,  0.0f,  0.0f),
    glm::vec3( 2.0f,  5.0f, -15.0f),
    glm::vec3(-1.5f, -2.2f, -2.5f),
    glm::vec3(-3.8f, -2.0f, -12.3f),
    glm::vec3( 2.4f, -0.4f, -3.5f),
    glm::vec3(-1.7f,  3.0f, -7.5f),
    glm::vec3( 1.3f, -2.0f, -2.5f),
    glm::vec3( 1.5f,  2.0f, -2.5f),
    glm::vec3( 1.5f,  0.2f, -1.5f),
    glm::vec3(-1.3f,  1.0f, -1.5f)
};

GLuint indices[] = {  // Note that we start from 0!
    0, 1, 3,   // First Triangle
    1, 2, 3    // Second Triangle
}; 

GLfloat texCoords[] = {
    0.0f, 0.0f,
    1.0f, 0.0f,
    1.0f, 1.0f,
    0.0f, 1.0f
};



int gl_init() {
    SDL_Init(SDL_INIT_VIDEO);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);

    window = SDL_CreateWindow("OpenGL", 100, 100, screenWidth, screenHeight, SDL_WINDOW_OPENGL);
    context = SDL_GL_CreateContext(window); 
    if (context == NULL) fprintf(stderr, "ERROR in context (Don't use Intel with GL > 3.3): %s\n", SDL_GetError()); 

    return 0;
}

int glew_init() {
    // Set up glew 
    glewExperimental = GL_TRUE;
    GLenum glewError = glewInit();
    if (glewError != GLEW_OK) fprintf(stderr, "ERROR in glewInit: %s\n", glewGetErrorString(glewError));

    SDL_SetRelativeMouseMode(SDL_TRUE);
    return 0;
}

int event_controller(SDL_Event *windowEvent, int *alive, int time_delta) {
    while (SDL_PollEvent(windowEvent) != 0) {
        if (windowEvent->type == SDL_QUIT) {
            *alive = 0;     
            break;

        }
        else if (windowEvent->type == SDL_KEYDOWN) {
            switch (windowEvent->key.keysym.sym) {
                case SDLK_LEFT:
                    camera.ProcessKeyboard(LEFT, time_delta);
                    mL += 0.1f;
                    break;
                case SDLK_RIGHT:
                    camera.ProcessKeyboard(RIGHT, time_delta);
                    mL -= 0.1f;
                    break;
                case SDLK_UP:
                    camera.ProcessKeyboard(FORWARD, time_delta);
                    mR += 0.1f;
                    break;
                case SDLK_DOWN:
                    camera.ProcessKeyboard(BACKWARD, time_delta);
                    mR -= 0.1f;
                    break;

                case SDLK_1:
                    anim = !anim;
                    break;
            }
        }
    }

    // Get mouse movement
    int xpos, ypos;
    SDL_GetMouseState(&xpos, &ypos);

    if(firstMouse)
    {
        lastX = xpos;
        lastY = ypos;
        firstMouse = false;
    }

    GLfloat xoffset = xpos - lastX;
    GLfloat yoffset = lastY - ypos;

    lastX = xpos;
    lastY = ypos;

    camera.ProcessMouseMovement(xoffset, yoffset);
    /* printf("x: %d, y: %d\n", xpos, ypos); */
    return 0;
}

glm::vec3 cubes_pos[50*50*2] = {glm::vec3(0.0f, -10.0f, 0.0f)};
glm::vec3 cubes_light_color[50*50*2] = {glm::vec3(0.0f, 0.0f, 0.0f)};
glm::vec3 camera_pos[2] =  {glm::vec3(0.0f, 0.0f, 0.0f)};

void cubes_anim(Thing **things, GLfloat dt) {
            camera_pos[0] = camera_pos[1] + (camera_pos[1] - camera_pos[0]) * (dt/10000) * 0.03f;
            camera.Position.x = camera_pos[0].x;
            camera.Position.y = camera_pos[0].y;
            camera.Position.z = camera_pos[0].z;


            for (int i = 0; i < 50; i++) {
                for (int j = 0; j < 50; j++) {
                    cubes_pos[i*50+j] = cubes_pos[i*50+j] + (cubes_pos[50*50 + i*50+j] - cubes_pos[i*50+j]) * (dt/10000) * 0.1f;
                    things[i*50+j]->set_position(cubes_pos[i*50+j]);

                    cubes_light_color[i*50+j] = cubes_light_color[i*50+j] + (cubes_light_color[50*50 + i*50+j] - cubes_light_color[i*50+j]) * (dt/10000) * 0.1f;
                    things[i*50+j]->set_light_color(cubes_light_color[i*50+j]);


                }
            }
            printf("CUBE_ANIM_POS %4f\tDT %4f\n", cubes_pos[0*50].y, dt/10000);
    
}

void a_rainbow(Thing **things, GLfloat time) {
    GLfloat norm_ticks = glm::sin(time / 1000.0f);
    bg.x = 1.0f;
    bg.y = 1.0f;
    bg.z = 1.0f;
            for (int i = 0; i < 50; i++) {
                for (int j = 0; j < 50; j++) {
                    things[i*50+j]->set_cube_color(glm::vec3(1.0f, 1.0f, 1.0f));
                    things[i*50+j]->set_light_color(glm::vec3(1.0f, 1.0f, 1.0f));
                    things[i*50+j]->set_position(glm::vec3(i, -5.0f, j));
                    things[i*50+j]->set_light_position(glm::vec3(10.0f, 10.0f, 10.0f));
                }
            }

}
void a_bgflash(Thing **things, GLfloat time) {
    GLfloat norm_ticks = glm::sin(time / 1000.0f);
    bg.x = 0.9f * glm::cos(norm_ticks/1014);
    bg.y = 0.3f * glm::cos(norm_ticks/1014);
    bg.z = 0.1f * glm::sin(norm_ticks/2000);

            for (int i = 0; i < 50; i++) {
                for (int j = 0; j < 50; j++) {
                    things[i*50+j]->set_cube_color(glm::vec3(0.0f, 0.0f, 0.0f));
                    things[i*50+j]->set_light_color(glm::vec3(0.0f, 0.0f, 0.0f));
                    things[i*50+j]->modify_position(glm::vec3(0.0f, norm_ticks * 30, 0.0f));
                    things[i*50+j]->set_light_position(glm::vec3((float) 10, 10.0f, (float) 10));
                }
            }

}
void a_2(Thing **things, GLfloat time) {
    GLfloat norm_ticks = glm::sin(time / 1000.0f);
    GLfloat norm_ticksc = glm::cos(time / 1000.0f);

    GLfloat norm_ticks_fast = glm::sin(time / 500.0f);
    GLfloat norm_ticksc_fast = glm::cos(time / 500.0f);
        for (int i = 0; i < 50; i++) {
            for (int j = 0; j < 50; j++) {
                things[i*50+j]->set_rotation(glm::vec3(1.0f, 1.0f, 1.0f), norm_ticks*4 );
                things[i*50+j]->set_scale(glm::vec3(1.0f, 1.0f, 1.0f));
                things[i*50+j]->set_light_color(glm::vec3((float) glm::sin(i/10)+1.0f, -5.0f + norm_ticks*10 , (float) glm::sin(j/10)+1.0f));
                things[i*50+j]->set_light_position(glm::vec3((float) i/10, -5.0f + glm::sin(i*j)*20, (float) j/10));

                things[i*50+j]->set_position(glm::vec3((float) i, -5.0f + glm::sin(i)*glm::sin(j)*20 , (float) -j));
                if (i%8 && j%8) {
                things[i*50+j]->set_position(glm::vec3((float) i, -5.0f + norm_ticks*12 , (float) -j));
                    if (i%4 && j%4) {
                        things[i*50+j]->set_position(glm::vec3((float) i, -5.0f - norm_ticks_fast*12 , (float) -j));
                    }
                }
            }
        }
}

void a_blink(Thing **things, GLfloat time) {
float r = (float)rand()/(float)(RAND_MAX/1.0f);
float g = (float)rand()/(float)(RAND_MAX/1.0f);
float b = (float)rand()/(float)(RAND_MAX/1.0f);

    for (int i = 0; i < 50; i++) {
        for (int j = 0; j < 50; j++) {
            if (i%2 || j%2 && tick < 25) {
                cubes_light_color[50*50 + i*50+j] = glm::vec3(r, 0.0f, 0.0f);
            } else if (i%2 || j%2 && tick > 25) {
                cubes_light_color[50*50 + i*50+j] = glm::vec3(0.0f, 0.0f, g);
            }
            if (i == tick) {
                cubes_pos[50*50 + i*50] = glm::vec3(-49 + i*2, 8*glm::sin(i/3.14)*2, -150 + j*2);
            }

        }
    }
}
void a_downbow(Thing **things, GLfloat time) {
float r = (float)rand()/(float)(RAND_MAX/1.0f);
float g = (float)rand()/(float)(RAND_MAX/1.0f);
float b = (float)rand()/(float)(RAND_MAX/1.0f);

    for (int i = 0; i < 50; i++) {
        for (int j = 0; j < 50; j++) {
            if (j == tick) {
                cubes_pos[50*50 + i*50+j] = glm::vec3(-49 + i*2, 8*glm::sin(i/3.14)*2, -150 + j*2);
            }

        }
    }
}



int animation_controller(Thing **things, GLfloat time, GLfloat dt) {
    bool once = 0;
    GLfloat norm_ticks = glm::sin(time / 1000.0f);
    GLfloat norm_ticksc = glm::cos(time / 1000.0f);

    GLfloat norm_ticks_fast = glm::sin(time / 500.0f);
    GLfloat norm_ticksc_fast = glm::cos(time / 500.0f);

    if ((int)(time/1000)%8) {
        tick++;
    }
    if (tick >= 50) {
        tick = 0;
    }
    
    switch (ANIM_STATE) {
        case ANIM_1: 
                camera.Position.x = 0;
                camera.Position.y = 0;
                camera.Position.z = 0;

            for (int i = 0; i < 50; i++) {
                for (int j = 0; j < 50; j++) {
                    cubes_pos[50*50 + i*50+j] = glm::vec3(-50 + i*2, -10.0f, -150 + j*2);
                }
            }

            cubes_anim(things, dt);
        /* for (int i = 0; i < 50; i++) { */
        /*     for (int j = 0; j < 50; j++) { */
        /*             things[i*50+j]->set_cube_color(glm::vec3(1.0f, 0.0f, 0.0f)); */
        /*         if (i%4) { */
        /*             things[i*50+j]->set_position(glm::vec3((float) i, -5.0f + norm_ticks*8 , (float) -j)); */
        /*         } else if (i%3) { */
        /*             things[i*50+j]->set_position(glm::vec3((float) i, -5.0f + norm_ticks*10 , (float) -j)); */
        /*         } else if (i%2) { */
        /*             things[i*50+j]->set_position(glm::vec3((float) i, -5.0f + norm_ticks*12 , (float) -j)); */
        /*         } else { */
        /*             things[i*50+j]->set_position(glm::vec3((float) i, -5.0f + norm_ticks*14 , (float) -j)); */
        /*         } */
        /*     } */
        /* } */
            break;

        case ANIM_2: 
            /* a_bgflash(things, time); */
            a_blink(things, time);
            if (camera_pos[0].z < 40)
                camera_pos[1].z = 40;
            cubes_anim(things, dt);
            break;

        case ANIM_3:
            /* a_2(things, time); */
            /* a_bgflash(things, time); */
            for (int i = 0; i < 50; i++) {
                for (int j = 0; j < 50; j++) {
                    cubes_pos[50*50 + i*50+j] = glm::vec3(-100 + glm::pow(i,2), 8.0f, -200 + glm::pow(j,2));
                }
            }
            cubes_anim(things, dt);
            break;

        case ANIM_4: 
            /* a_2(things, time); */
            /* a_rainbow(things, time); */
            cubes_anim(things, dt);
            break;

        case ANIM_5: 
            cubes_anim(things, dt);
            break;
        case ANIM_6:
           if (!once) {
            for (int i = 0; i < 50; i++) {
                for (int j = 0; j < 50; j++) {
                    cubes_pos[50*50 + i*50+j] += glm::vec3(glm::sin(i/3.14), 0.0f, 0.0f);
                }
            }
            once = !once;
           }
            cubes_anim(things, dt);
            break;
        case ANIM_7:
            if (once) {
                for (int i = 0; i < 50; i++) {
                    for (int j = 0; j < 50; j++) {
                        cubes_pos[50*50 + i*50+j] += glm::vec3(0.0f, glm::sin(i/3.14)*glm::sin(time/583), 0.0f);
                        cubes_light_color[50*50 + i*50+j] += glm::vec3(0.0f, 0.0f, glm::sin(time/291));
                    }
                }
            }
            once = !once;
                for (int i = 0; i < 50; i++) {
                    for (int j = 0; j < 50; j++) {
                        if ((i*j)%2) {
                            /* cubes_pos[50*50 + i*50+j] += glm::vec3(0.0f, glm::sin(time / 200)*4, 0.0f); */
                        }
                    }
                }

            a_blink(things, time);
            /* a_bgflash(things, time); */
            cubes_anim(things, dt);
            break;
        case ANIM_71:
            if (!once) {
                for (int i = 0; i < 50; i++) {
                    for (int j = 0; j < 50; j++) {
                        cubes_pos[50*50 + i*50+j] += glm::vec3(0.0f, glm::sin(i/3.14), 0.0f);
                    }
                }
            }
            once = !once;
                for (int i = 0; i < 50; i++) {
                    for (int j = 0; j < 50; j++) {
                        cubes_pos[50*50 + i*50+j] += glm::vec3(0.0f, glm::sin(time / 100)*2, 0.0f);
                        if ((i*j)%2) {
                            cubes_pos[50*50 + i*50+j] += glm::vec3(0.0f, glm::sin(time / 200)*4, 0.0f);
                        }
                    }
                }
            for (int i = 0; i < 50; i++) {
                for (int j = 0; j < 50; j++) {
                    if (i%3 || j%2) {
                        cubes_light_color[50*50 + i*50+j] = glm::vec3(1.0f, 0.0f, 0.0f);
                    } else if (i%2 || j%2) {
                        cubes_light_color[50*50 + i*50+j] = glm::vec3(0.0f, 0.0f, 0.5f);
                    }
                    if (i == tick) {
                        cubes_pos[50*50 + i*50] = glm::vec3(-49 + i*2, 16*glm::sin(time/119), -150 + j*2);
                    }

                }
            }
            a_blink(things, time);
            cubes_anim(things, dt);
            break;
        case ANIM_8:
            if (!once) {
                for (int i = 0; i < 50; i++) {
                    for (int j = 0; j < 50; j++) {
                        cubes_pos[50*50 + i*50+j] = glm::vec3(0.0f, -10 + j, -30.0f);
                    }
                }
            }
            once = !once;
            cubes_anim(things, dt);
            break;
        case ANIM_9:
            /* if (once) { */
                for (int i = 0; i < 50; i++) {
                    for (int j = 0; j < 50; j++) {
                        cubes_pos[50*50 + i*50+j] += glm::vec3(glm::sin(time/583)*glm::cos(i/3.14), 0.0f, 0.0f);
                    }
                }
            /* } */
            once = !once;
            a_downbow(things, time);
            cubes_anim(things, dt);
            break;
        case ANIM_10:
            /* if (once) { */
                for (int i = 0; i < 50; i++) {
                    for (int j = 0; j < 50; j++) {
                        cubes_pos[50*50 + i*50+j] = glm::vec3( 0.0f, 0.0f, -30.0f );
                    }
                }
            /* } */
            /* once = !once; */
            cubes_anim(things, dt);
            break;
        case ANIM_11:
            if (!once) {
                for (int i = 0; i < 50; i++) {
                    for (int j = 0; j < 50; j++) {
                        cubes_pos[50*50 + i*50+j] = glm::vec3( -5.0f + j, i, -30.0f );
                    }
                }
            }
            once = !once;
            cubes_anim(things, dt);
            break;
        case ANIM_12:
                for (int i = 0; i < 50; i++) {
                    for (int j = 0; j < 50; j++) {
                        cubes_pos[50*50 + i*50+j] = glm::vec3( 20.0f, 0.0f, -30.0f );
                        things[i*50+j]->set_cube_color(glm::vec3(tick/50, tick/50, tick/50));
                    }
                }
            cubes_anim(things, dt);
            break;
        case ANIM_13:
                for (int i = 0; i < 50; i++) {
                    for (int j = 0; j < 50; j++) {
                        cubes_pos[50*50 + i*50+j] = glm::vec3( -5.0f + j, i, -30.0f );
                        things[i*50+j]->set_light_position(glm::vec3(20.0f + glm::cos(time/600)*10, 10 + glm::sin(time/600)*10, -20.0f));
                            

                    }
                }
                for (int i = 0; i < 50; i++) {
                    cubes_pos[50*50 + i*50+tick] = glm::vec3( -5.0f + glm::sin(time/300)*4, i, -30.0f );
                    /* cubes_pos[50*50 + tick*50+i] = glm::vec3( -5.0f + glm::sin(time/300)*4, i, -30.0f ); */
                }
            once = !once;
            cubes_anim(things, dt);
            break;
        case ANIM_14:
                for (int i = 0; i < 50; i++) {
                    for (int j = 0; j < 50; j++) {
                        cubes_pos[50*50 + i*50+j] = glm::vec3( -25.0f + j, 30-i, -30.0f );
                        things[i*50+j]->set_light_position(glm::vec3(20.0f + glm::cos(time/583.333)*10, 10 + glm::sin(time/600)*10, -20.0f));
                    }
                }
                for (int i = 0; i < 50; i++) {
                    cubes_pos[50*50 + i*50+tick] = glm::vec3( -5.0f + glm::sin(time/291.666)*4, i, -30.0f );
                    /* cubes_pos[50*50 + tick*50+i] = glm::vec3( -5.0f + glm::sin(time/300)*4, i, -30.0f ); */
                }
            cubes_anim(things, dt);
            break;
        case ANIM_15:
            cubes_pos[50*50 + 0*50+25] = glm::vec3( -5.0f + 25, 10, 2.0f );
                    for (int j = 0; j < 50; j++) {
                        things[j*50+tick]->set_light_color(glm::vec3(glm::sin(tick/3.14), glm::sin(tick/3.14), glm::sin(tick/3.14)));
                    }
            cubes_anim(things, dt);
            break;

    }

        if (time > 3000 && time < 6000) {
            ANIM_STATE = ANIM_3; 
        } else if (time > 6000 && time < 13500) {
            ANIM_STATE = ANIM_2;
        } else if (time > 14000 && time < 18000) {
            ANIM_STATE = ANIM_9;
        } else if (time > 18500 && time < 20000) {
            ANIM_STATE = ANIM_7;
        } else if (time > 20000 && time < 22500) {
/*
bg.x = 0.1f;
bg.y = 0.1f;
bg.z = 0.8f;
*/
            ANIM_STATE = ANIM_71;
        } else if (time > 22500 && time < 23000) {
            ANIM_STATE = ANIM_7;
        } else if (time > 23000 && time < 28000) {
            ANIM_STATE = ANIM_9;
        } else if (time > 28000 && time < 28500) {
            ANIM_STATE = ANIM_10;
        } else if (time > 28500 && time < 35000) {
            ANIM_STATE = ANIM_14;
        } else if (time > 35000 && time < 38000) {
            ANIM_STATE = ANIM_6;
        } else if (time > 38000 && time < 39000) {
            ANIM_STATE = ANIM_7;
        } else if (time > 39000 && time < 40000) {
            ANIM_STATE = ANIM_14;
        } else if (time > 40000 && time < 42000) {
            ANIM_STATE = ANIM_7;
        } else if (time > 42000 && time < 48000) {
            ANIM_STATE = ANIM_9;
        } else if (time > 48000 && time < 49000) {
            ANIM_STATE = ANIM_3;
        } else if (time > 49000 && time < 51000) {
bg.x = 0.8f;
bg.y = 0.1f;
bg.z = 0.8f;
            ANIM_STATE = ANIM_2;
        } else if (time > 51000 && time < 54000) {
            ANIM_STATE = ANIM_7;
        } else if (time > 54000 && time < 54500) {
            ANIM_STATE = ANIM_9;
        } else if (time > 54500 && time < 58000) {
            ANIM_STATE = ANIM_7;
        } else if (time > 58000 && time < 60000) {
            ANIM_STATE = ANIM_2;
bg.x = 0.1f;
bg.y = 0.1f;
bg.z = 0.1f;
            ANIM_STATE = ANIM_14;
        } else if (time > 60000 && time < 62000) {
            ANIM_STATE = ANIM_7;
        } else if (time > 62000 && time < 65000) {
            ANIM_STATE = ANIM_9;
        } else if (time > 65000 && time < 67000) {
            ANIM_STATE = ANIM_9; // 3
        } else if (time > 68000 && time < 69000) {
            ANIM_STATE = ANIM_10;
bg.x = 0.0f;
bg.y = 0.0f;
bg.z = 0.0f;
        }

        /* } else if (time > 10000 && time < 14000) { */
        /*     ANIM_STATE = ANIM_6; */
        /* } else if (time > 14000 && time < 18000) { */
        /*     ANIM_STATE = ANIM_7; */
        /* } else if (time > 18000 && time < 22000) { */
        /*     ANIM_STATE = ANIM_8; */
        /* } else if (time > 22000 && time < 26000) { */
        /*     ANIM_STATE = ANIM_9; */
        /* } else if (time > 26000 && time < 28000) { */
        /*     ANIM_STATE = ANIM_10; */
        /* } else if (time > 28000 && time < 28030) { */
        /*     ANIM_STATE = ANIM_14; */
        /* } else if (time > 28030 && time < 30000) { */
        /*     ANIM_STATE = ANIM_15; */
        /* } else if (time > 30000 && time < 34000) { */
        /*     ANIM_STATE = ANIM_14; */
        /* } else if (time > 34000 && time < 38000) { */
        /*     ANIM_STATE = ANIM_15; */
        /* } */
        printf(" ANIM_STATE %d TICK %d", ANIM_STATE, tick);
    return 0;
}

int render_init(GLuint *VBO, GLuint *VAO, GLuint *EBO) {
    glGenBuffers(1, VBO); 
    glGenVertexArrays(1, VAO); 
    /* glGenBuffers(1, EBO); */

    glBindBuffer(GL_ARRAY_BUFFER, *VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glBindVertexArray(*VAO);
    /* glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *EBO); */
    /* glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); */ 

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);

    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);

    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(2);

    glBindVertexArray(0);

    glEnable(GL_DEPTH_TEST);

    return 0;
}


int main(int argc, char *argv[]) {
    int alive = 1;
    SDL_Event windowEvent;
    GLuint VBO, VAO, EBO;
    Shader *s, *lampShader;
    Texture *t0, *t1;
    

    /* libwebsock_context *ctx = NULL; */
    /* ctx = libwebsock_init(); */
    /* if(ctx == NULL) { */
    /*     fprintf(stderr, "Error during libwebsock_init.\n"); */
    /*     exit(1); */
    /* } */
    /* libwebsock_bind(ctx, "0.0.0.0", "8080"); */
    /* libwebsock_wait(ctx); */

    gl_init();
    glew_init();
    srand(time(NULL));

    s = new Shader("vertex.glsl", "fragment.glsl");
    lampShader = new Shader("lamp.vert", "lamp.frag");
    t0 = new Texture("wall.png");
    t1 = new Texture("awesomeface.png");

    render_init(&VBO, &VAO, &EBO);

    int xdir = 50;
    int ydir = 50;
    Thing *things[xdir*ydir];
    for (int i = 0; i < xdir; i++) {
        for (int j = 0; j < ydir; j++) {
            things[i*xdir + j] = new Thing(&camera, VBO, s, t0, glm::vec3((float) i, -5.0f,(float) -j)); 
            things[i*xdir + j]->set_rotation(glm::vec3(1.0f, 1.0f, 1.0f), i*2);
        }
    }

    // So, audio is hard. Let's SUPERHACK!!
    system("aplay demo_audio.wav&");

    while (alive) {
        GLfloat time_delta = (GLfloat) SDL_GetTicks();
        event_controller(&windowEvent, &alive, time_delta);
        if ( anim ) {
            animation_controller(things, (GLfloat) SDL_GetTicks(), time_delta );
        }
        glClearColor(bg.x, bg.y, bg.z, bg.w);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


        for (int i = 0; i < xdir; i++) {
            for (int j = 0; j < ydir; j++) {
                things[i*xdir+j]->render();
            }
        }


        SDL_GL_SwapWindow(window);
        fprintf(stderr, "\r Frame time: %.1f ms", ((GLfloat) SDL_GetTicks() - time_delta));
    }

    for (int i = 0; i < xdir; i++) {
        for (int j = 0; j < ydir; j++) {
            delete things[i*xdir + j];
        }
    }
    delete s;
    delete lampShader;
    delete t0;
    delete t1;

    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);

    SDL_GL_DeleteContext(context);
    SDL_DestroyWindow(window);
    SDL_Quit();

    system("killall aplay");

    return 0;
}
