#include <iostream>
#include <SDL/SDL.h>
#undef main
#include <cstdlib>
#include <ctime>
#include "Niveau.h"
#include "Thread.h"
#include "Flux/Client.h"
#include "Flux/LecteurSSD.h"
#include "Flux/SpriteLoader.h"

class Patienter : public Thread
{
public:
    Patienter(Client* lan, int* manage, char* IDMoi, char* IDLui): m_lan(lan), m_manage(manage), m_IDMoi(IDMoi), m_IDLui(IDLui)
    {

    }

    void run()
    {
        if (m_lan != 0) {
            if (!m_lan->rendreUtilisable()) {
                std::cout << "Problème d'initialisation des connexions." << std::endl;
                *m_manage = -1;
                return;
            }
        }
        else {
            std::cout << "Problème de lecture de la configuration réseau." << std::endl;
                *m_manage = -1;
                return;
        }

        m_lan->recevoir(m_IDMoi, 1);
        std::cout << "Votre identifiant est : " << *m_IDMoi << std::endl;
        if (*m_IDMoi == '0') *m_IDLui = '1';
        else *m_IDLui = '0';
        *m_manage = 1;
    }

private:
    Client* m_lan;
    int *m_manage;
    char *m_IDMoi, *m_IDLui;
};

int main ( int argc, char** argv )
{
    srand(time(0));
    /// [1] Démarrage
    // [1.1] Démarrages SDL
    if ( SDL_Init( SDL_INIT_VIDEO ) < 0)
    {
        std::cout << "Impossible d'initialiser la SDL: " << SDL_GetError() << std::endl;
        return 1;
    }
    putenv("SDL_VIDEO_CENTERED=1");

    // [1.2] Préparation de fermeture
    atexit(SDL_Quit);

    // [1.3] Para-fenêtre
    SDL_WM_SetCaption("Twokoban", 0);

    /// [2] Préparation des composants
    // [2.0] Variables
    const char crash(197);//'┼'
    const char loadLvl(9);//'○'
    const char pasBouger(254);//'■'
    const char fini(36);//'$'
    const char reset(47);//'/'

    char cmd(pasBouger), cmdLui(pasBouger);

    // [2.1] Préparation du réseau
    // [2.1.1] Fenetre d'attente
    SDL_Surface* attente = SDL_SetVideoMode(400, 400, 32, SDL_HWSURFACE|SDL_DOUBLEBUF);
    if ( !attente )
    {
        std::cout << "Inpossible de créer une fenêtre : " << SDL_GetError() << std::endl;
        return 1;
    }
    SDL_Surface* imgattente = SDL_LoadBMP("Textures/patientez.bmp");
    SDL_BlitSurface(imgattente, 0, attente, 0);
    SDL_Flip(attente);
    SDL_FreeSurface(imgattente);

    // [2.1.2] initialisation du réseau
    char octet;
    int manage = 0;
    Client* lan(0);
    lan = readConfig();
    char IDMoi, IDLui;

    Patienter *p = new Patienter(lan, &manage, &IDMoi, &IDLui);
    p->setAutoDelete(true);
    p->start();

    SDL_Event event;
    while(!manage)
    {
        // [3.1] Gestion évènements
        while (SDL_PollEvent(&event) && !manage)
        {
            switch (event.type)
            {
            case SDL_QUIT:
                manage = -1;
                break;
            case SDL_KEYDOWN:
                switch (event.key.keysym.sym)
                {
                case SDLK_ESCAPE:
                    manage = -1;
                default:
                    break;
                }
                break;
            } // end switch event type
        } // end of message processing
    }

    // [2.1.3] disparition fenetre attente
    SDL_FreeSurface(attente);

    if(manage == -1)
        return -1;

    // [2.2] Préparation de la fenêtre
    SDL_Surface* screen = SDL_SetVideoMode(40*24, 40*18, 32,
                                           SDL_HWSURFACE|SDL_DOUBLEBUF);
    if ( !screen )
    {
        std::cout << "Inpossible de créer une fenêtre : " << SDL_GetError() << std::endl;
        return 1;
    }

    // [2.3] Préparation du gestionnaire de textures
    SpriteLoader* spriteGet(0);
    spriteGet = new SpriteLoader("Textures/");

    // [2.4] Préparation du niveau
    Niveau level(spriteGet);

    /// [3] Boucle principale
    bool done = false;
    while (!done)
    {
        // [3.1] Gestion évènements
        while (SDL_PollEvent(&event) && !done)
        {
            switch (event.type)
            {
            case SDL_QUIT:
                done = true;
                cmd = crash;
                break;
            case SDL_KEYDOWN:
                switch (event.key.keysym.sym)
                {
                case SDLK_ESCAPE:
                    done = true;
                    cmd = crash;
                    break;
                case SDLK_UP:
                    cmd = 24;
                    break;
                case SDLK_DOWN:
                    cmd = 25;
                    break;
                case SDLK_RIGHT:
                    cmd = 26;
                    break;
                case SDLK_LEFT:
                    cmd = 27;
                    break;
                case SDLK_KP_DIVIDE:
                    cmd = reset;
                    break;
                default:
                    break;
                }
                break;
            } // end switch event type
        } // end of message processing

        // [3.2] Réseau
        lan->recevoir(&octet, 1);
        switch (octet) // Exécution de la commande requise par le serveur
        {
        case loadLvl: // Recevoir le niveau
            char lvlTmp[18][24];
            for (Uint16 y(0); y < 18; y++)
                for (Uint16 x(0); x < 24; x++) {
                    lan->recevoir(&octet, 1);
                    lvlTmp[y][x] = octet;
                }
            level.majLevel(lvlTmp);
            std::cout << "Niveau reçu." << std::endl;
            break;
        case crash:
            std::cout << "Le serveur a annoncé une erreur critique. Extinction préventive du programme." << std::endl;
            done = true;
            break;
        default:
            cmdLui = octet;
            break;
        }

        if ( level.suisJeArrive(IDMoi) )
        {
            char fin = fini;
            lan->envoyer(&fin, 1);
        }
        else
        {
            ///*****si crash, latence pour permetre un transfert fonctionnel***********
            if(cmd==crash)
                SDL_Delay(500);
            ///************************************************************************
            lan->envoyer(&cmd, 1);
        }

        // [3.3] Calculs
        if(!level.deplacer(IDMoi, cmd))
        {
            lan->recevoir(&octet, 1);
            cmd = reset;
            lan->envoyer(&cmd, 1);
        }
        cmd = pasBouger;
        level.deplacer(IDLui, cmdLui);
        cmdLui = pasBouger;

        level.updateBoutons();

        // [3.4] Dessin des composants
        level.afficher(screen);

        SDL_Flip(screen);
    } //fin bcl principale

    ///[4] Destruction des composants
    SDL_FreeSurface(screen);
    delete lan;
    delete spriteGet;

    std::cout << "Aucune erreur détectée." << std::endl;
    return 0;
}