#include "game/mapa.hpp"

#include <stdlib.h>

#include "core/jail/jgame.hpp"
#include "core/jail/jinput.hpp"

Mapa::Mapa(JD8_Surface gfx, Prota* sam) {
    this->gfx = gfx;
    this->sam = sam;

    this->preparaFondoEstatic();
    this->preparaTombes();

    this->ultim_vertex.columna = 255;
    this->frame_torxes = 0;

    this->farao = false;
    this->clau = false;
    this->porta_oberta = false;
    this->nova_momia = false;
}

Mapa::~Mapa(void) {
    JD8_FreeSurface(this->fondo);
}

void Mapa::draw() {
    if (info::num_piramide != 4) {
        switch (sam->o) {
            case 0:  // Down
                JD8_BlitCKToSurface(sam->x, sam->y, this->gfx, 15, 125 + sam->frame_pejades, 15, 1, this->fondo, 255);
                break;
            case 1:  // Up
                JD8_BlitCKToSurface(sam->x, sam->y + 15, this->gfx, 0, 125 + (14 - sam->frame_pejades), 15, 1, this->fondo, 255);
                break;
            case 2:  // Right
                JD8_BlitCKToSurface(sam->x + 7, sam->y, this->gfx, 30 + sam->frame_pejades, 125, 1, 15, this->fondo, 255);
                break;
            case 3:  // Left
                JD8_BlitCKToSurface(sam->x + 8, sam->y, this->gfx, 45 + (14 - sam->frame_pejades), 125, 1, 15, this->fondo, 255);
                break;
        }
    }

    JD8_Blit(this->fondo);

    // Pinta tombes
    for (int y = 0; y < 4; y++) {
        for (int x = 0; x < 4; x++) {
            JD8_BlitCK(35 + (x * 65), 45 + (y * 35), this->gfx, this->tombes[x + y * 4].x, this->tombes[x + y * 4].y, 50, 20, 255);
        }
    }

    JD8_BlitCK(45, 15, this->gfx, 30 + (this->frame_torxes * 25), 80, 25, 15, 255);
    JD8_BlitCK(95, 15, this->gfx, 30 + (this->frame_torxes * 25), 80, 25, 15, 255);
    JD8_BlitCK(195, 15, this->gfx, 30 + (this->frame_torxes * 25), 80, 25, 15, 255);
    JD8_BlitCK(245, 15, this->gfx, 30 + (this->frame_torxes * 25), 80, 25, 15, 255);
};

void Mapa::update() {
    if (((sam->x - 20) % 65 == 0) && ((sam->y - 30) % 35 == 0) && ((this->ultim_vertex.columna != (sam->x - 20) / 65) || (this->ultim_vertex.fila != (sam->y - 30) / 35))) {
        this->vertex.columna = (sam->x - 20) / 65;
        this->vertex.fila = (sam->y - 30) / 35;
        if (this->ultim_vertex.columna != 255) this->comprovaUltimCami();
        this->ultim_vertex = this->vertex;
    }

    if (this->porta_oberta && sam->x == 150 && sam->y == 30) {
        if (JI_KeyPressed(SDL_SCANCODE_UP)) {
            this->sam->o = 4;
            this->sam->y -= 15;
        }
    }

    if (JG_GetCycleCounter() % 8 == 0) {
        this->frame_torxes++;
        this->frame_torxes = this->frame_torxes % 4;
    }
}

bool Mapa::novaMomia() {
    bool resultat = nova_momia;
    nova_momia = false;
    return resultat;
}

void Mapa::preparaFondoEstatic() {
    // Prepara el fondo est�tic de l'habitaci�
    this->fondo = JD8_NewSurface();
    if (info::num_piramide == 6) {
        JD8_BlitToSurface(9, 2, this->gfx, 227, 185, 92, 7, this->fondo);  // Text "SECRETA"
    } else {
        JD8_BlitToSurface(9, 2, this->gfx, 60, 185, 39, 7, this->fondo);   // Text "NIVELL"
        JD8_BlitToSurface(72, 6, this->gfx, 153, 189, 3, 1, this->fondo);  // Ralleta entre num piramide i num habitacio
    }
    JD8_BlitToSurface(130, 2, this->gfx, 225, 192, 19, 8, this->fondo);  // Montonet de monedes + signe '='
    JD8_BlitToSurface(220, 2, this->gfx, 160, 185, 48, 7, this->fondo);  // Text "ENERGIA"
    if (info::diners >= 200) JD8_BlitToSurface(175, 3, this->gfx, 60, 193, 7, 6, this->fondo);

    // Pinta taulells
    for (int y = 0; y < 11; y++) {
        for (int x = 0; x < 19; x++) {
            switch (info::num_piramide) {
                case 1:
                    JD8_BlitToSurface(20 + (x * 15), 30 + (y * 15), this->gfx, 0, 80, 15, 15, this->fondo);
                    break;
                case 2:
                    JD8_BlitToSurface(20 + (x * 15), 30 + (y * 15), this->gfx, 25, 95, 15, 15, this->fondo);
                    break;
                case 3:
                    JD8_BlitToSurface(20 + (x * 15), 30 + (y * 15), this->gfx, 40, 95, 15, 15, this->fondo);
                    break;
                case 4:
                    JD8_BlitToSurface(20 + (x * 15), 30 + (y * 15), this->gfx, 175 + ((rand() % 3) * 15), 80, 15, 15, this->fondo);
                    break;
                case 5:
                    JD8_BlitToSurface(20 + (x * 15), 30 + (y * 15), this->gfx, 130, 80, 15, 15, this->fondo);
                    break;
                case 6:
                    JD8_BlitToSurface(20 + (x * 15), 30 + (y * 15), this->gfx, 145, 80, 15, 15, this->fondo);
                    break;
            }
        }
    }

    // Pinta vores de les parets
    JD8_BlitCKToSurface(5, 15, this->gfx, 30, 110, 15, 15, this->fondo, 255);
    JD8_BlitCKToSurface(295, 15, this->gfx, 45, 110, 15, 15, this->fondo, 255);
    JD8_BlitCKToSurface(5, 180, this->gfx, 0, 155, 15, 20, this->fondo, 255);
    JD8_BlitCKToSurface(295, 180, this->gfx, 15, 155, 15, 20, this->fondo, 255);

    // Pinta parets verticals
    for (int i = 0; i < 10; i++) {
        JD8_BlitToSurface(5, 30 + (i * 15), this->gfx, 0, 110, 15, 15, this->fondo);
        JD8_BlitToSurface(295, 30 + (i * 15), this->gfx, 15, 110, 15, 15, this->fondo);
    }

    // Pinta parets hortzintals
    for (int i = 0; i < 11; i++) {
        JD8_BlitToSurface(20 + (i * 25), 185, this->gfx, 0, 95, 25, 15, this->fondo);
        JD8_BlitToSurface(20 + (i * 25), 15, this->gfx, 0, 95, 25, 15, this->fondo);
    }

    // Pinta la porta
    JD8_BlitCKToSurface(150, 18, this->gfx, 0, 143, 15, 12, this->fondo, 255);

    if (info::num_piramide == 2) {
        JD8_BlitToSurface(5, 100, this->gfx, 30, 140, 15, 15, this->fondo);
    }
}

void swap(Uint8& a, Uint8& b) {
    Uint8 temp = a;
    a = b;
    b = temp;
}

void Mapa::preparaTombes() {
    const Uint8 contingut = info::num_piramide == 6 ? CONTE_DIAMANT : CONTE_RES;
    int cx = info::num_piramide == 6 ? 270 : 0;
    int cy = info::num_piramide == 6 ? 50 : 0;

    for (int i = 0; i < 16; i++) {
        this->tombes[i].contingut = contingut;
        this->tombes[i].oberta = false;
        this->tombes[i].costat[0] = false;
        this->tombes[i].costat[1] = false;
        this->tombes[i].costat[2] = false;
        this->tombes[i].costat[3] = false;
        this->tombes[i].x = cx;
        this->tombes[i].y = cy;
    }
    if (info::num_piramide == 6) return;
    this->tombes[0].contingut = CONTE_FARAO;
    this->tombes[1].contingut = CONTE_CLAU;
    this->tombes[2].contingut = CONTE_PERGAMI;
    this->tombes[3].contingut = CONTE_MOMIA;
    for (int i = 4; i < 8; i++) this->tombes[i].contingut = CONTE_RES;
    for (int i = 8; i < 16; i++) this->tombes[i].contingut = CONTE_TRESOR;

    for (int i = 0; i < 50; i++) swap(this->tombes[rand() % 16].contingut, this->tombes[rand() % 16].contingut);
}

Uint8 minim(Uint8 a, Uint8 b) {
    return (a < b) ? a : b;
}

void Mapa::comprovaUltimCami() {
    Uint8 col_aux = abs(this->vertex.columna - this->ultim_vertex.columna);
    Uint8 fil_aux = abs(this->vertex.fila - this->ultim_vertex.fila);

    if (col_aux > fil_aux) {  // Cam� horitzontal
        Uint8 cami_fila = this->vertex.fila;
        Uint8 cami_columna = minim(this->vertex.columna, this->ultim_vertex.columna);

        Sint8 caixa_avall = (cami_fila << 2) + cami_columna;
        Sint8 caixa_amunt = caixa_avall - 4;

        if (caixa_avall < 16) {
            this->tombes[caixa_avall].costat[0] = true;
            this->comprovaCaixa(caixa_avall);
        }
        if (caixa_amunt >= 0) {
            this->tombes[caixa_amunt].costat[2] = true;
            this->comprovaCaixa(caixa_amunt);
        }
    } else {  // Cam� vertical
        Uint8 cami_columna = this->vertex.columna;
        Uint8 cami_fila = minim(this->vertex.fila, this->ultim_vertex.fila);

        Sint8 caixa_dreta = (cami_fila << 2) + cami_columna;
        Sint8 caixa_esquerra = caixa_dreta - 1;

        if (caixa_dreta <= (cami_fila << 2) + 3) {
            this->tombes[caixa_dreta].costat[3] = true;
            this->comprovaCaixa(caixa_dreta);
        }
        if (caixa_esquerra >= (cami_fila << 2)) {
            this->tombes[caixa_esquerra].costat[1] = true;
            this->comprovaCaixa(caixa_esquerra);
        }
    }
}

void Mapa::comprovaCaixa(Uint8 num) {
    // Si la tomba ja està oberta, no hi ha res que mirar
    if (this->tombes[num].oberta) return;

    // Si algun costat encara no està passat, no hi ha res que fer
    for (int i = 0; i < 4; i++)
        if (!this->tombes[num].costat[i]) return;

    // Sinó, pos la acabem d'obrir
    this->tombes[num].oberta = true;

    // Comprobem el premi del kinder sorpresa
    switch (this->tombes[num].contingut) {
        case CONTE_RES:
            this->tombes[num].x = 50;
            break;
        case CONTE_TRESOR:
            this->tombes[num].x = 100;
            info::diners++;
            break;
        case CONTE_FARAO:
            this->tombes[num].x = 150;
            this->farao = true;
            break;
        case CONTE_CLAU:
            this->tombes[num].x = 200;
            this->clau = true;
            break;
        case CONTE_MOMIA:
            this->tombes[num].y = 175;
            this->nova_momia = true;
            break;
        case CONTE_PERGAMI:
            this->tombes[num].x = 250;
            this->sam->pergami = true;
            break;
        case CONTE_DIAMANT:
            this->tombes[num].y = 70;
            info::diamants++;
            info::diners += VALOR_DIAMANT;
            if (info::diamants == 16) this->farao = this->clau = true;
            break;
    }

    this->comprovaPorta();
}

void Mapa::comprovaPorta() {
    if (this->clau && this->farao) {
        JD8_BlitCKToSurface(150, 18, this->gfx, 15, 143, 15, 12, this->fondo, 255);
        porta_oberta = true;
    }
}
