#include <iostream>

#include <QKeyEvent>
#include <QImage>
#include <QMessageBox>
#include <eigen3/Eigen/Geometry>
#include <fstream>
#include <vector>
#include "OpenGL.h"
#include "glview.h"
#include "fbo.h"

#define VERTEX_SHADER   "../IOGS_RV/simple.vert"
#define FRAGMENT_SHADER "../IOGS_RV/simple.frag"

using namespace Eigen;

GLView::GLView(QWidget *parent)
    : QGLWidget(parent),
      _initGL(false)
{
}

GLView::~GLView()
{
}

void GLView::setScene(int scene)
{
    switch (scene) {
    case 1:
        _scene = Scene1();
        break;
    case 2:
        _scene = Scene2();
        break;
    case 3:
        _scene = Scene3();
        break;
    case 4:
        _scene = Scene4();
        break;
    case 5:
        _scene = Scene5();
        break;
    case 6:
        _scene = Scene6();
        break;
    case 7:
        _scene = Scene7();
        break;
    case 8:
        _scene = Scene8();
        break;
    case 9:
        _scene = Scene9();
        break;
    }
    updateGL();
}

void GLView::colorPicking(Vector2i mouse_coord)
{
    makeCurrent();
    int renderType;

    // init fbo
    FBO* image = new FBO();
    image->init(_scene.camera()->vpWidth(),
                _scene.camera()->vpHeight(),
                GL_RGBA32F, GL_RGBA, GL_FLOAT);
    GL_TEST_ERR;

    // use fbo
    image->beginCapture();

    // init render
    glDisable(GL_BLEND);
    glClearColor(0.,0.,0.,1);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glViewport(0, 0,
               _scene.camera()->vpWidth(),
               _scene.camera()->vpHeight());
    activeShaderObject();
    GL_TEST_ERR;

    // draw the scene
    _scene.draw(&_program, true);

    // texture reading
    glUseProgram(0); GL_TEST_ERR;
    image->endCapture(); GL_TEST_ERR;
    image->bindTexture();

    // TODO : retrieve color under mouse coords
    QImage img = Texture2D::currentFrame();



    // TODO : compute id associated to the color



    // TODO : retrive the associated object


    // save render
    Texture2D::save("colorById.png");


    //Free memory
    delete image;
}

void GLView::initializeGL()
{
    if(!_initGL)
    {
        makeCurrent();
        std::cout << "Using OpenGL version: \"" << glGetString(GL_VERSION) << "\"" << std::endl;

        glEnable(GL_DEPTH_TEST);
        glClearColor(0.,0.,0.,0);

        // load shader
        loadShaders();

        // load texture
        QImage img;
        img.load(TEXTURE_WOOD);
        _texture.load(img);

        _initGL = true;
    }
}

void GLView::resizeGL(int width, int height)
{
    _scene.camera()->setViewport(width, height);
}

void GLView::paintGL()
{
    if(!_program.valid())
        return;

    makeCurrent();

    /********** DRAW THE SCENE ***********/
    glClearColor(0.,0.,0.,0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glViewport(0, 0, _scene.camera()->vpWidth(), _scene.camera()->vpHeight());

    activeShaderObject();

    // draw scene
    _scene.draw(&_program);

    GL_TEST_ERR;
}

void GLView::activeShaderObject()
{
    _program.activate();

    // camera information
    glUniformMatrix4fv(glGetUniformLocation(_program.id(),"mat_view"), 1, GL_FALSE, _scene.camera()->viewMatrix().data());
    glUniformMatrix4fv(glGetUniformLocation(_program.id(),"mat_proj"), 1, GL_FALSE, _scene.camera()->projectionMatrix().data());
    GL_TEST_ERR;

    // texture
    glActiveTexture(GL_TEXTURE0);
    _texture.bind();
    glUniform1i(glGetUniformLocation(_program.id(), "texture"), 0);
    GL_TEST_ERR;
}

void GLView::loadShaders()
{
    _program.load_from_files(VERTEX_SHADER, FRAGMENT_SHADER);
}
