#include "Client.h"
#include "../engine/Mouse.h"
#include "../math/Matrix3D.h"
#include "../math/Matrix3DStack.h"
#include "../engine/Key.h"

Mesh Client::mesh;
TextureMesh Client::tmesh;
Vector3D Client::position;
Texture Client::texture;
Texture Client::texture2;
float Client::lengthAngle = 0;
float Client::widthAngle = 0;

Client::Client()
{
}

void Client::init()
{
    if(texture.load("resources/textures.png"))
    {
        cout << "texture success" << endl;
    }
    else
    {
        cout << "texture fail" << endl;
    }
    if(texture2.load("resources/font8x8.png"))
    {
        cout << "texture2 success" << endl;
    }
    else
    {
        cout << "texture2 fail" << endl;
    }
    
    cout << "init" << endl;
    mesh.init();
    
    // bottom
    mesh.addPoint(0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f);
    mesh.addPoint(1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f);
    mesh.addPoint(0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f);
    mesh.addPoint(1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f);
    mesh.addPoint(1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f);
    mesh.addPoint(0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f);
    
    // top
    mesh.addPoint(0.0f, 1.0f, 0.0f, 0.5f, 0.0f, 0.0f, 1.0f);
    mesh.addPoint(0.0f, 1.0f, 1.0f, 0.5f, 0.0f, 0.0f, 1.0f);
    mesh.addPoint(1.0f, 1.0f, 0.0f, 0.5f, 0.0f, 0.0f, 1.0f);
    mesh.addPoint(1.0f, 1.0f, 0.0f, 0.5f, 0.0f, 0.0f, 1.0f);
    mesh.addPoint(0.0f, 1.0f, 1.0f, 0.5f, 0.0f, 0.0f, 1.0f);
    mesh.addPoint(1.0f, 1.0f, 1.0f, 0.5f, 0.0f, 0.0f, 1.0f);
    
    // right
    mesh.addPoint(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f);
    mesh.addPoint(1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
    mesh.addPoint(1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
    mesh.addPoint(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f);
    mesh.addPoint(1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f);
    mesh.addPoint(1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
    
    // left
    mesh.addPoint(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 1.0f);
    mesh.addPoint(0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 1.0f);
    mesh.addPoint(0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.5f, 1.0f);
    mesh.addPoint(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 1.0f);
    mesh.addPoint(0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.5f, 1.0f);
    mesh.addPoint(0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.5f, 1.0f);
    
    // back
    mesh.addPoint(0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
    mesh.addPoint(1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
    mesh.addPoint(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
    mesh.addPoint(0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
    mesh.addPoint(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
    mesh.addPoint(0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
    
    // front
    mesh.addPoint(0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 1.0f);
    mesh.addPoint(1.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.0f, 1.0f);
    mesh.addPoint(1.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 1.0f);
    mesh.addPoint(0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 1.0f);
    mesh.addPoint(0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.0f, 1.0f);
    mesh.addPoint(1.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.0f, 1.0f);
    
    mesh.build();
    
    tmesh.init();
    
    // bottom
    tmesh.addPoint(0.0f, 0.0f, 0.0f, 0.125f, 0.0f);
    tmesh.addPoint(1.0f, 0.0f, 0.0f, 0.1875f, 0.0f);
    tmesh.addPoint(0.0f, 0.0f, 1.0f, 0.125f, 0.0625f);
    tmesh.addPoint(1.0f, 0.0f, 0.0f, 0.1875f, 0.0f);
    tmesh.addPoint(1.0f, 0.0f, 1.0f, 0.1875f, 0.0625f);
    tmesh.addPoint(0.0f, 0.0f, 1.0f, 0.125f, 0.0625f);
    
    // top
    tmesh.addPoint(0.0f, 1.0f, 0.0f, 0.25f, 0.0f);
    tmesh.addPoint(0.0f, 1.0f, 1.0f, 0.25f, 0.0625f);
    tmesh.addPoint(1.0f, 1.0f, 0.0f, 0.3125f, 0.0f);
    tmesh.addPoint(1.0f, 1.0f, 0.0f, 0.3125f, 0.0f);
    tmesh.addPoint(0.0f, 1.0f, 1.0f, 0.25f, 0.0625f);
    tmesh.addPoint(1.0f, 1.0f, 1.0f, 0.3125f, 0.0625f);
    
    // right
    tmesh.addPoint(1.0f, 0.0f, 0.0f, 0.1875f, 0.0625f);
    tmesh.addPoint(1.0f, 1.0f, 1.0f, 0.25f, 0.0f);
    tmesh.addPoint(1.0f, 0.0f, 1.0f, 0.25f, 0.0625f);
    tmesh.addPoint(1.0f, 0.0f, 0.0f, 0.1875f, 0.0625f);
    tmesh.addPoint(1.0f, 1.0f, 0.0f, 0.1875f, 0.0f);
    tmesh.addPoint(1.0f, 1.0f, 1.0f, 0.25f, 0.0f);
    
    // left
    tmesh.addPoint(0.0f, 0.0f, 0.0f, 0.1875f, 0.0625f);
    tmesh.addPoint(0.0f, 0.0f, 1.0f, 0.25f, 0.0625f);
    tmesh.addPoint(0.0f, 1.0f, 1.0f, 0.25f, 0.0f);
    tmesh.addPoint(0.0f, 0.0f, 0.0f, 0.1875f, 0.0625f);
    tmesh.addPoint(0.0f, 1.0f, 1.0f, 0.25f, 0.0f);
    tmesh.addPoint(0.0f, 1.0f, 0.0f, 0.1875f, 0.0f);
    
    // back
    tmesh.addPoint(0.0f, 0.0f, 1.0f, 0.1875f, 0.0625f);
    tmesh.addPoint(1.0f, 0.0f, 1.0f, 0.25f, 0.0625f);
    tmesh.addPoint(1.0f, 1.0f, 1.0f, 0.25f, 0.0f);
    tmesh.addPoint(0.0f, 0.0f, 1.0f, 0.1875f, 0.0625f);
    tmesh.addPoint(1.0f, 1.0f, 1.0f, 0.25f, 0.0f);
    tmesh.addPoint(0.0f, 1.0f, 1.0f, 0.1875f, 0.0f);
    
    // front
    tmesh.addPoint(0.0f, 0.0f, 0.0f, 0.1875f, 0.0625f);
    tmesh.addPoint(1.0f, 1.0f, 0.0f, 0.25f, 0.0f);
    tmesh.addPoint(1.0f, 0.0f, 0.0f, 0.25f, 0.0625f);
    tmesh.addPoint(0.0f, 0.0f, 0.0f, 0.1875f, 0.0625f);
    tmesh.addPoint(0.0f, 1.0f, 0.0f, 0.1875f, 0.0f);
    tmesh.addPoint(1.0f, 1.0f, 0.0f, 0.25f, 0.0f);
    
    tmesh.build();
    
    position.set(0, 0, -2);
    GameEngine::getCamera().setPosition(position.getX(), position.getY(), position.getZ());
    GameEngine::getCamera().storePosition();
    
    Key::map(KEY_LEFT, GLFW_KEY_A);
    Key::map(KEY_RIGHT, GLFW_KEY_D);
    Key::map(KEY_UP, GLFW_KEY_W);
    Key::map(KEY_DOWN, GLFW_KEY_S);
    Key::map(KEY_JUMP, GLFW_KEY_SPACE);
    Key::map(KEY_SNEAK, GLFW_KEY_LEFT_SHIFT);
    
    Key::map(KEY_CAM_LEFT, GLFW_KEY_H);
    Key::map(KEY_CAM_RIGHT, GLFW_KEY_K);
    Key::map(KEY_CAM_UP, GLFW_KEY_U);
    Key::map(KEY_CAM_DOWN, GLFW_KEY_J);
}

uint64_t oldTime = -1;

uint64_t count = 0;
uint64_t sum = 0;

void Client::tick()
{
    Camera& c = GameEngine::getCamera();
    
    c.storePosition();
    c.storeAngles();
    
    float factor = 0.125f;
    if(Key::isDown(KEY_LEFT))
    {
        position.addMul(c.getLeft(), factor);
    }
    if(Key::isDown(KEY_RIGHT))
    {
        position.addMul(c.getRight(), factor);
    }
    if(Key::isDown(KEY_UP))
    {
        position.addMul(c.getFront(), factor);
    }
    if(Key::isDown(KEY_DOWN))
    {
        position.addMul(c.getBack(), factor);
    }
    if(Key::isDown(KEY_JUMP))
    {
        position.addMul(c.getUp(), factor);
    }
    if(Key::isDown(KEY_SNEAK))
    {
        position.addMul(c.getDown(), factor);
    }
    
    if(Key::isDown(KEY_CAM_LEFT))
    {
        lengthAngle += 2;
    }
    if(Key::isDown(KEY_CAM_RIGHT))
    {
        lengthAngle -= 2;
    }
    if(Key::isDown(KEY_CAM_UP))
    {
        widthAngle += 2;
    }
    if(Key::isDown(KEY_CAM_DOWN))
    {
        widthAngle -= 2;
    }
    
    c.setPosition(position.getX(), position.getY(), position.getZ());
    c.setAngles(lengthAngle, widthAngle);
    //cout << "tick" << endl;
    
    cout << (1000000000.0 * count ) / sum << endl;
}

void Client::renderTick(float lag)
{
    uint64_t t = glfwGetTimerValue();
    if(oldTime == -1)
    {
        oldTime = t;
    }
    else
    {
        sum += t - oldTime;
        count++;
        oldTime = t;
    }
    
    GameEngine::getCamera().updateView(lag);
    texture.bind();
    GameEngine::setTextureEnabled(true);
    //GameEngine::setColorEnabled(true);
    GameEngine::getDirectRenderer().prepare();
    GameEngine::getDirectRenderer().drawRectangle(0, 0, 300, 300, 0, 0, 1, 1, 1, 0, 0, 1);
    //tmesh.draw();
    //cout << "renderTick" << endl;
}

void Client::start()
{
    GameEngine::start(640, 480, "Test Game", init, tick, renderTick);
}