#include "RenderThread.h"

#include <iostream>

#include "Bildschirm.h"
#include "Logging.h"
#include "Zeit.h"

using namespace Framework;

// Inhalt der RenderTh Klasse aus RenderThread.h
// Konstruktor
RenderTh::RenderTh()
    : Thread(),
      stoppen(0),
      bildschirm(0),
      zeit(new ZeitMesser()),
      renderTickZeit(1 / 60),
      renderParameter(0),
      tickParameter(0),
      renderFunktion(0),
      tickFunktion(0),
      pause(0),
      maxFps(30),
      quiet(0)
{}

// Destruktor
RenderTh::~RenderTh()
{
    beenden();
    if (bildschirm) bildschirm->release();
    zeit->release();
}

// nicht constant
void RenderTh::lock()
{
    cs.lock();
}

void RenderTh::unlock()
{
    cs.unlock();
}

void RenderTh::setBildschirm(Bildschirm* bildschirm) // setzt den Bildschirm
{
    lock();
    if (this->bildschirm) this->bildschirm->release();
    this->bildschirm = bildschirm;
    unlock();
}

void RenderTh::thread() // Render Schleife
{
    int val = 0;
    double time = 0;
    zeit->messungStart();
    double ausgleich = 0;
    while (!stoppen)
    {
        lock();
        if (bildschirm && !pause)
        {
            if (renderFunktion)
                renderFunktion(
                    renderParameter, this, bildschirm->zRenderBild());
            bildschirm->render();
            val++;
            if (tickFunktion) tickFunktion(tickParameter, this, renderTickZeit);
            bildschirm->tick(renderTickZeit);
            time += renderTickZeit;
            unlock();
            if (time > 1)
            {
                time -= 1;
                if (!quiet)
                {
                    Logging::info() << "FPS: " << val << "\n";
                }
                val = 0;
            }
        }
        else
        {
            unlock();
            Sleep(100);
        }
        ausgleich += 1.0 / maxFps - renderTickZeit;
        if (ausgleich > 0) Sleep((int)(ausgleich * 1000));
        zeit->messungEnde();
        zeit->messungStart();
        renderTickZeit = zeit->getSekunden();
    }
    zeit->messungEnde();
}

void RenderTh::beginn() // beginnt rendering
{
    stoppen = 0;
    start();
}

void RenderTh::beenden() // beendet den Thread
{
    stoppen = 1;
    warteAufThread(2000);
    if (run) ende();
}

void RenderTh::setQuiet(
    bool quiet) // if true, then nothing will be printent to std::cout
{
    this->quiet = quiet;
}

void RenderTh::setMaxFps(int fps) // setzt die Anzahl der Bilder pro Sekunde
{
    maxFps = fps;
}

void RenderTh::setPause(bool p) // Renderpause
{
    pause = p;
}

void RenderTh::setRenderFunktion(std::function<void(void*, void*, Bild*)>
        rF) // setzt die R�ckruf Funktion beim Rendern
{
    renderFunktion = rF;
}

void RenderTh::setTickFunktion(std::function<void(void*, void*, double)>
        tF) // setzt die R�ckruf Funktion beim Tick
{
    tickFunktion = tF;
}

void RenderTh::setRenderFunktionParameter(
    void* p) // setzt den Parameter der R�ckruf Funktion beim Rendern
{
    renderParameter = p;
}

void RenderTh::setTickFunktionParameter(
    void* p) // setzt den Parameter der R�ckruf Funktion beim Tick
{
    tickParameter = p;
}

// constant
Bildschirm* RenderTh::getBildschirm() const // gibt den Bildschirm zur�ck
{
    return bildschirm ? dynamic_cast<Bildschirm*>(bildschirm->getThis()) : 0;
}

Bildschirm* RenderTh::zBildschirm() const
{
    return bildschirm;
}

double RenderTh::getRenderTickZeit()
    const // gibt die Zeit zur�ck, die zum Rendern und zum Tick ben�tigt wird
{
    return renderTickZeit;
}