//
// Created by jovian on 18/07/17.
//

// Basics
#include <iostream>
#include "GameCore.h"
#include "Graphics/MetaField.h"

GameCore::GameCore()
        : m_input(nullptr), m_rend(nullptr) {}

GameCore::~GameCore() {
    // Input
    if (m_input != nullptr) {
        delete m_input;
        m_input = nullptr;
    }

    // Destroy SDL renderer
    if (m_rend != nullptr) {
        delete m_rend;
        m_rend = nullptr;
    }
}

bool GameCore::initialize() {
    // Already initialized
    if (m_input != nullptr)
        return false;

    // Error check
    bool okay(true);

    // Create display
    m_rend = new Renderer;
    okay = okay && m_rend->initialize();

    // Create hardware interface
    m_input = new Input;
    m_input->setWindow(m_rend->getWindow());

    // End
    return okay;
}

void GameCore::start() {
    // Time
    Uint32 frameRate(60); // Frame per second
    Uint32 prevTime(0); // Previous chrono
    Uint32 waitTime(1000 / frameRate); // Time to wait between each frame
    Uint32 osBuffer(4); // To prevent SDL_Delay mistake : high > less mistake, more CPU usage

    // Matrix field
    bool field[WIN_H][WIN_W];
    MetaField meta;
    std::vector<MetaBall> balls;

    // Main loop
    while (!m_input->isFinished() && !m_input->getKey(SDL_SCANCODE_ESCAPE)) {
        // Update events
        m_input->updateEvents();

        // Rendering
        m_rend->clearWindow();

        meta.clean();

        if (m_input->getInstantKey(SDL_SCANCODE_E))
            balls.push_back({m_input->getX(), m_input->getY(), 1000.0});

        for (auto b : balls)
            meta.disturb(b.y, b.x, b.power);

        meta.disturb(m_input->getY(), m_input->getX(), 1000.0);

        meta.binary(field, 1.0);

        m_rend->renderBoolMatrix(field);

        m_rend->presentWindow();

        // todo Remove debug
        /*Uint32 debug_conso(SDL_GetTicks() - prevTime);
        std::cout << "Time use : " << debug_conso << std::endl;*/

        // Pause
        if (SDL_GetTicks() + osBuffer < prevTime + waitTime)
            SDL_Delay(waitTime + prevTime - SDL_GetTicks() - osBuffer);

        while (SDL_GetTicks() < prevTime + waitTime) {}

        prevTime = SDL_GetTicks();
    }
}