#include "gamestates.h"
#include "jgame.h"
#include <SDL2/SDL.h>
#include <string>
#include "aux_font.h"
#include "proc_mapa.h"
#include "proc_arounders.h"

namespace gamestate
{
    namespace play
    {
        namespace eixir
        {
            const int no = 0;
            const int postfase = 1;
            const int mort = 2;
        }

        draw::surface *faded = nullptr;
        draw::surface *fondo = nullptr;
        draw::surface *cursor = nullptr;
        draw::surface *aigua = nullptr;

        uint32_t *original_palette = nullptr;

        uint32_t arounderCount;
        uint32_t startTicks;
        uint32_t currentTicks;

        int aigua_frame1 = 0;
        int aigua_frame2 = 5;

        int exit = 0;

        bool loop();

        bool loop_pause();
        bool loop_menu();

        void backToLoop();

        void draw();
        void draw_aigua();

        void finalize();

        void init()
        {
            // Ara comença tot, per tant no volem eixir
            play::exit = play::eixir::no;

            // Carregar el fondo que toque i la seua paleta (que nomes usa els colors del 128 al 255)
            char arxiuFondo[10] = "BKG00.GIF";
	        arxiuFondo[4] = (game::getConfig("fase") % 10) + 48;
	        play::fondo = draw::loadSurface(arxiuFondo, true);

            // Carregar la paleta estandar (colors del 0 al 128)
            uint32_t *pal = draw::loadPalette("tiles.gif");
            draw::setPalette(pal, 128);
            free(pal);

            // Carregar els gifs auxiliars i crear la superficie per al fondo de la pausa i el menu
            play::cursor = draw::loadSurface("cursor.gif");
            play::aigua = draw::loadSurface("aigua.gif");
            play::faded = draw::createSurface(320, 200);

            arounders::init();
            // [TODO] Crear el primer Arounder
            // REALMENT NO. PREFEREIXC QUE PASEN UNS SEGONS ABANS QUE ARRIBE EL PRIMER
            // mapa::arounders::eixits++;
            // arounder_seleccionat = primerArounders

            // Enxufa el arradio
            audio::loadMusic((game::getConfig("fase")+1) % 5 == 0 ? "mus6.ogg" : "mus4.ogg");
            audio::playMusic();

            // Fiquem a contar el cronómetre de arounders
            play::arounderCount = play::startTicks = game::getTicks();

            // Fade in i anem al bucle principal
            draw::fadein();
            game::setState(gamestate::play::loop);
        }

        bool loop()
        {
            // Si ja s'ha demanat l'eixida...
            if (play::exit) {
                // I si ja s'ha acabat el fadeout...
                if (!draw::isfading()) {
                    // Alliberem memòria
                    play::finalize();

                    // I anem on toque
                    if (play::exit==play::eixir::postfase) gamestate::postfase::init();
                    else if (play::exit==play::eixir::mort) gamestate::mort::init();
                }
                // En qualsevol cas, renderitzem i eixim ja del bucle (fins que acabe el fadeout)
                draw::render();
                return true;
            }

            // Pintar tot menys el cursor
            play::draw();

            // Si se pulsa 'P', o el botó del mig del ratolí, o si la finestra perd el foco...
            if (input::keyPressed(SDL_SCANCODE_P) || input::mouseClk(input::mouse::button::middle) || !game::windowHasFocus)
            {
                // Parem el cronòmetre d'arounders
                play::arounderCount = game::getTicks() - play::arounderCount;

                // Pintem el que hi ha a la pantalla en la surface "faded", li afegim el text "PAUSA" i aixó es tot el que pintarem fins eixir de la pausa
                draw::setSource(nullptr);
                draw::setDestination(play::faded);
                draw::draw();
                font::selectFont(font::type::fade);
                font::print(136, 80, "PAUSA");
                draw::setDestination(nullptr);

                // Reduïm tots els colors de la paleta (menys els epecials) a la meitat del seu color
                play::original_palette = draw::getPalette();
                for (int i=0; i<256; ++i) if ( i!=61 && i!= 62 && (i<68 || i >75) )
                {
                    uint32_t p = play::original_palette[i];
                    uint8_t r = (p >> 16) & 0xff;
                    uint8_t g = (p >> 8) & 0xff;
                    uint8_t b = p & 0xff;
                    draw::setPaletteEntry(i, r >> 1, g >> 1, b >> 1);
                }

                // Canviem el bucle principal a "loop_pausa()"
                game::setState(gamestate::play::loop_pause);
                return true;
            }

            // Si se pulsa ESC...
            if (input::keyPressed(SDL_SCANCODE_ESCAPE))
            {
                // Parem el cronòmetre d'arounders
                play::arounderCount = game::getTicks() - play::arounderCount;

                // Pintem el que hi ha a la pantalla en la surface "faded", li afegim el menú i aixó es tot el que pintarem fins eixir del menú
                draw::setSource(nullptr);
                draw::setDestination(play::faded);
                draw::draw();
                draw::surface *menu = draw::loadSurface("menu.gif");
                draw::setSource(menu);
                draw::draw(97, 52);
                draw::freeSurface(menu);
                font::selectFont(font::type::fade);
                font::print(129, 60, "CONTINUAR");
                font::print(129, 71, "REINICIAR");
                font::print(112, 82, "MENU PRINCIPAL");
                font::print(143, 93, "EIXIR");
                draw::setDestination(nullptr);

                // Reduïm tots els colors de la paleta (menys els epecials) a la meitat del seu color
                play::original_palette = draw::getPalette();
                for (int i=0; i<256; ++i) if ( i!=61 && i!= 62 && (i<68 || i >75) )
                {
                    uint32_t p = play::original_palette[i];
                    uint8_t r = (p >> 16) & 0xff;
                    uint8_t g = (p >> 8) & 0xff;
                    uint8_t b = p & 0xff;
                    draw::setPaletteEntry(i, r >> 1, g >> 1, b >> 1);
                }

                // Canviem el bucle principal a "loop_menu()"
                game::setState(gamestate::play::loop_menu);
                return true;
            }

            // Ara ja, pintem el cursor i enviem tot a pantalla
            // No ho havem fet abans perque en el fondo de la pausa o el menú no volem que aparega el cursor
            draw::setSource(cursor);
            draw::draw(input::mouseX(), input::mouseY());
            draw::render();

            // Si pulsem el botó de la dreta, el arounder seleccionat deixa de fer l'acció que està fent
            if (input::mouseClk(input::mouse::button::right))
            {
                arounders::abortarAccio();
            }

            if (input::mouseClk(input::mouse::button::left))
            {
                if (!arounders::seleccionar())
                {
                    if (input::mouseY()<165 && arounders::seleccionat != nullptr && arounders::seleccionat->accio == arounders::accions::caminar)
                    {
                        arounders::seleccionat->orientacio = input::mouseX() > arounders::seleccionat->x ? arounders::orientacions::dreta : arounders::orientacions::esquerra;
                    }
                }

                const int botoPulsat = mapa::procesar();
                if (botoPulsat != -1 && arounders::seleccionat != nullptr)
                {
                    if (botoPulsat == arounders::seleccionat->prevista) {
                        arounders::seleccionat->prevista = arounders::seleccionat->accio;
                    } else {
                        arounders::seleccionat->prevista = botoPulsat;
                    }
                }
            }

            currentTicks = game::getTicks() - startTicks;
            if( currentTicks >= mapa::velocitat ) {
                startTicks = game::getTicks();
                aigua_frame1 = (aigua_frame1+1)%10;
                aigua_frame2 = (aigua_frame2+1)%10;

                arounders::procesar();
            }

            if ( (game::getTicks() - arounderCount) >= mapa::velocitat*58) {
                if (mapa::arounders::eixits < mapa::arounders::totals) {
                    arounders::afegir();
                    mapa::arounders::eixits++;
                    arounderCount = game::getTicks();
                }
            }

      		if (mapa::arounders::arrivats + mapa::arounders::morts == mapa::arounders::totals) {
                if (mapa::arounders::arrivats >= mapa::arounders::necessaris) {
                    game::setConfig("fase", game::getConfig("fase")+1);
                    draw::fadeout();
                    audio::fadeoutMusic();
                    play::exit = 1;
                } else {
                    draw::fadeout();
                    audio::fadeoutMusic();
                    play::exit = 2;
                }
            }

            return true;
        }

        bool loop_pause()
        {
            draw::draw(faded);
            draw::setSource(cursor);
            draw::draw(input::mouseX(), input::mouseY());

            draw::render();

            if (input::keyPressed(SDL_SCANCODE_P) || input::keyPressed(SDL_SCANCODE_ESCAPE))
            {
                play::backToLoop();
            }
            return true;
        }

        bool loop_menu()
        {
            if (play::exit) {
                if (!draw::isfading()) {
                    play::finalize();
                    if (exit==1) {
                        mapa::carregar();
                        gamestate::play::init();
                    }
                    if (exit==2) gamestate::menu::init();
                }
                draw::render();
                return true;
            }

            draw::draw(faded);
            draw::setSource(cursor);
            draw::draw(input::mouseX(), input::mouseY());

            draw::render();

            if (input::keyPressed(SDL_SCANCODE_ESCAPE))
            {
                play::backToLoop();
            }

            if (input::mouseClk(input::mouse::button::left))
            {
                if (input::mouseX() >= 97 && input::mouseX() <= 223) {
                    if (input::mouseY() >= 60 && input::mouseY() <= 65) {
                        play::backToLoop();
                    }
                    if (input::mouseY() >= 71 && input::mouseY() <= 76) {
                        free(play::original_palette);
                        draw::fadeout();
                        audio::fadeoutMusic();
                        play::exit = 1;
                    }
                    if (input::mouseY() >= 82 && input::mouseY() <= 87) {
                        free(play::original_palette);
                        draw::fadeout();
                        audio::fadeoutMusic();
                        play::exit = 2;
                    }
                    if (input::mouseY() >= 93 && input::mouseY() <= 98) {
                        return false;
                    }
                }

            }
            return true;
        }

        void backToLoop()
        {
            draw::setPalette(play::original_palette, 256);
            free(play::original_palette);
            game::setState(gamestate::play::loop);
            arounderCount = game::getTicks() - arounderCount;
        }

        void draw()
        {
            draw::draw(play::fondo);
            
            int accio = 0;
            int prevista = 0;
            if (arounders::seleccionat) { accio = arounders::seleccionat->accio; prevista = arounders::seleccionat->prevista; }
            mapa::pintar(accio, prevista);

            draw_aigua();
            arounders::pintar();

            // [TODO] de fet, pintar la marca en el modul "arounders"
            /*
            if (arounders::seleccionat) {
                draw::setSource(marca);
                draw::draw(arounderSeleccionat->X-3, arounderSeleccionat->Y-3);
            }
            */

        }

        void draw_aigua()
        {
            static int frames1[10] = {0,1,2,1,0,3,4,5,4,3};
            static int frames2[10] = {6,7,8,7,6,9,10,11,10,9};
            int *frames;
            frames = (game::getConfig("fase")+1) % 5 == 0 ? frames2 : frames1;

            draw::setSource(aigua);
            for (int i=0;i<10;i++) {
                draw::draw(i*32, 150, 16, 15, frames[aigua_frame1]*16, 0);
                draw::draw(16+i*32, 150, 16, 15, frames[aigua_frame2]*16, 0);
            }
        }

        void finalize()
        {
            draw::freeSurface(faded);
            draw::freeSurface(fondo);
            draw::freeSurface(cursor);
            draw::freeSurface(aigua);
        }
    }
}