#include <Windows.h>
#else
#include <unistd.h>
#endif

#include "../testje/RingBuffer.h"
#include "../testje/BufferedSerial.h"
#include "SerialCommand.h"
#include "rs232.h"

const int TTYACM0=24;
const int SEND_BUFFER_SIZE=101;
const int RUNTIME_MS=10000;

BufferedSerial serial = BufferedSerial(256, 256);
RingBuffer send_buffer= RingBuffer(SEND_BUFFER_SIZE);
SerialCommand sCmd;
struct timeval start, startLoop;
unsigned int uiRxPacketCtr, uiTxPacketCtr;

void handlePacket(byte* packet, byte length){
    sCmd.readSerial(packet, length);
}

void respondData(byte* packet, byte length){
    uiRxPacketCtr++;
}

int openComport(byte serial_port, unsigned long baud_rate){
    if(RS232_OpenComport(serial_port, baud_rate))
    {
/**
 * @brief Renderer::Renderer -- construct a new renderer
 * The renderer initializes a window and rendering context
 * using SDL2 and OpenGL 2.1, and allocates a sufficient
 * amount of memory on the GPU to upload particle data.
 * @param ds the Dataset to render from each frame.
 */
Renderer::Renderer(Dataset ds){
    dataset = ds;
    if(SDL_Init(SDL_INIT_EVERYTHING) == 1){
        printf("SDL failed to initialize: %s\n", SDL_GetError());
        exit(EXIT_FAILURE);
    }
    win = SDL_CreateWindow("The toppest of keks", 0, 0, width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
    if(win == NULL){
        printf("SDL failed to create window: %s\n", SDL_GetError());
        exit(EXIT_FAILURE);
    }

    testrb = RingBuffer(20000, glm::vec3(0.0));
    detect_gamepads();

    SDL_SetWindowGrab(win, SDL_TRUE);
    SDL_SetRelativeMouseMode(SDL_TRUE);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

    if(SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1) != 0){
        std::cout << "failed to set MULTISAMPLEBUFFERS to 1" << std::endl;
    }
    if(SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 16) != 0){
        std::cout << "failed to set MULTISAMPLEBUFFERS to 16" << std::endl;
    }

    glcontext = SDL_GL_CreateContext(win);
    if(glcontext == NULL){
        printf("SDL failed to create context: %s\n", SDL_GetError());
        exit(EXIT_FAILURE);
    }

    glEnable(GL_MULTISAMPLE);

    GLenum err = glewInit();
    if (GLEW_OK != err){
      fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
      exit(EXIT_FAILURE);
    }

    if (!GLEW_VERSION_2_1){
      std::cout << "Your OpenGL version is too old to run this program!" << std::endl;
      exit(EXIT_FAILURE);
    }

    if (GLEW_VERSION_3_1){
        std::cout << "Using fancier shaders." << std::endl;
        use_fancy_shaders = true;
    }

    printf("OpenGL vendor: '%s'\n", glGetString(GL_VENDOR));
    printf("OpenGL renderer: '%s'\n", glGetString(GL_RENDERER));
    printf("OpenGL version: '%s'\n", glGetString(GL_VERSION));
    printf("GLSL version: '%s'\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
    int val;
    SDL_GL_GetAttribute(SDL_GL_MULTISAMPLEBUFFERS, &val);
    std::cout << "Multisample buffers: " << val << std::endl;
    SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &val);
    std::cout << "Multisamples: " << val << std::endl;

    initialize_axes();
    initialize_trails();
    initialize_pointsprites();
}