#include "Niveau.h"

Niveau::Niveau(SpriteLoader* spriteGet) : m_terrain(0), m_spriteGet(spriteGet)
{
    // Surface du terrain
    m_terrain = SDL_CreateRGBSurface(SDL_HWSURFACE, 24*40, 18*40, 32, 0, 0, 0, 0);

    // Remplissage tableau
    for (Uint16 y(0); y < 18; y++)
        for (Uint16 x(0); x < 24; x++)
            m_tabl[y][x] = '#';

    // Association noms aux chars
    m_pass['#'] = "mur";
    m_pass[' '] = "sol";
    m_pass[36] = "end";//'$'

    //Association couleurs lettres
    Uint32 tab[26] = {0xffff0000, 0xff00ff00, 0x00ffff00, 0xff000000, 0x00ff0000, 0x0000ff00, 0xff770000, 0x00ff7700, 0x7700ff00, 0xff777700, 0x77ff7700, 0x7777ff00, 0x8c551500, 0xff00e000, 0x88880000, 0x88008800, 0x00888800, 0x2cb15800, 0x2cb15800, 0x008ebc00, 0x00bc5400, 0x6fbc0000, 0x6fbc0000, 0xff875200, 0xe56dff00, 0x00000000};
    for(int i = 0;i<26;i++)
        tabColor[i] = tab[i];

    // Création des persos
    m_perso[0].skin = m_spriteGet->takeSprite("bleu");
    m_perso[1].skin = m_spriteGet->takeSprite("rouge");
    m_perso[0].y = m_perso[1].y = 8;
    m_perso[0].x = m_perso[1].x = 12;
    SDL_SetColorKey(m_perso[0].skin, SDL_SRCCOLORKEY, 0xffffffff);
    SDL_SetColorKey(m_perso[1].skin, SDL_SRCCOLORKEY, 0xffffffff);

    //Création des
    SDL_SetColorKey(m_spriteGet->takeSprite("boutonA"), SDL_SRCCOLORKEY, 0xff000000);
    SDL_SetColorKey(m_spriteGet->takeSprite("boutonR"), SDL_SRCCOLORKEY, 0xff000000);
    SDL_SetColorKey(m_spriteGet->takeSprite("porteO"), SDL_SRCCOLORKEY, 0xff000000);
    SDL_SetColorKey(m_spriteGet->takeSprite("porteF"), SDL_SRCCOLORKEY, 0xff000000);
}

Niveau::~Niveau()
{
    SDL_FreeSurface(m_terrain);
}

void Niveau::majLevel(char newTerrain[18][24])
{
    // Nettoyage de la map
    m_gates.clear();
    for(unsigned int y = 0; y<18; y++) for(unsigned int x = 0; x<24; x++) m_caisses[y][x] = false;

    // Balayage
    for (Uint16 y(0); y < 18; y++)
        for (Uint16 x(0); x < 24; x++)
        {
            // Valeur
            m_tabl[y][x] = newTerrain[y][x];

            // Pêche aux infos
            if (m_tabl[y][x] == '0') {
                m_perso[0].y = y;
                m_perso[0].x = x;
                m_tabl[y][x] = ' ';
            }
            if (m_tabl[y][x] == '1') {
                m_perso[1].y = y;
                m_perso[1].x = x;
                m_tabl[y][x] = ' ';
            }
            if(m_tabl[y][x] == '*')
            {
                m_caisses[y][x] = true;
                m_tabl[y][x] = ' ';
            }

            m_blitPos.x = x*40;
            m_blitPos.y = y*40;
            if(m_tabl[y][x] >= 97 && m_tabl[y][x] <= 122)//Minuscules
            {
                m_gates[m_tabl[y][x]].first = false;
                m_gates[m_tabl[y][x]].second[0].push_back(x);
                m_gates[m_tabl[y][x]].second[0].push_back(y);
                SDL_BlitSurface(m_spriteGet->takeSprite(m_pass[' ']), 0, m_terrain, &m_blitPos);
            }
            else if(m_tabl[y][x] >= 65 && m_tabl[y][x] <= 90)//majuscules
            {
                m_gates[tolower(m_tabl[y][x])].second[1].push_back(x);
                m_gates[tolower(m_tabl[y][x])].second[1].push_back(y);
                SDL_BlitSurface(m_spriteGet->takeSprite(m_pass[' ']), 0, m_terrain, &m_blitPos);
            }
            else //blit si ce n'est ni porte ni bouton
            {
                SDL_BlitSurface(m_spriteGet->takeSprite(m_pass[m_tabl[y][x]]), 0, m_terrain, &m_blitPos);
            }
        }
}

void Niveau::afficher(SDL_Surface* screen)
{
    // Sol
    SDL_BlitSurface(m_terrain, 0, screen, 0);

    //affichage des potres/boutons ouvertes/fermées
    SDL_Surface *tmpSurface;
    for(std::map<char, std::pair<bool, std::vector<int>[2] > >::iterator tmp_gates = m_gates.begin(); tmp_gates!=m_gates.end(); tmp_gates++)
    {
        int index = (int)tmp_gates->first-97;
        //boutons
        tmpSurface = SDL_CreateRGBSurface(SDL_HWSURFACE, 40, 40, 32, m_spriteGet->takeSprite("boutonA")->format->Rmask, m_spriteGet->takeSprite("boutonA")->format->Gmask, m_spriteGet->takeSprite("boutonA")->format->Bmask, m_spriteGet->takeSprite("boutonA")->format->Amask);
        SDL_FillRect(tmpSurface, 0, tabColor[index]);
        if(tmp_gates->second.first)
            SDL_BlitSurface(m_spriteGet->takeSprite("boutonA"), 0, tmpSurface, 0);
        else
            SDL_BlitSurface(m_spriteGet->takeSprite("boutonR"), 0, tmpSurface, 0);
        for(unsigned int i = 0;i<tmp_gates->second.second[0].size();i+=2)
        {
            m_blitPos.x = tmp_gates->second.second[0][i]*40;
            m_blitPos.y = tmp_gates->second.second[0][i+1]*40;
            SDL_SetColorKey(tmpSurface, SDL_SRCCOLORKEY, 0xffffff00);
            SDL_BlitSurface(tmpSurface, 0, screen, &m_blitPos);
        }
        SDL_FreeSurface(tmpSurface);

        //portes
        tmpSurface = SDL_CreateRGBSurface(SDL_HWSURFACE, 40, 40, 32, m_spriteGet->takeSprite("porteO")->format->Rmask, m_spriteGet->takeSprite("boutonA")->format->Gmask, m_spriteGet->takeSprite("boutonA")->format->Bmask, m_spriteGet->takeSprite("boutonA")->format->Amask);
        SDL_FillRect(tmpSurface, 0, tabColor[index]);
        if(tmp_gates->second.first)
            SDL_BlitSurface(m_spriteGet->takeSprite("porteO"), 0, tmpSurface, 0);
        else
            SDL_BlitSurface(m_spriteGet->takeSprite("porteF"), 0, tmpSurface, 0);
        for(unsigned int i = 0;i<tmp_gates->second.second[1].size();i+=2)
        {
            m_blitPos.x = tmp_gates->second.second[1][i]*40;
            m_blitPos.y = tmp_gates->second.second[1][i+1]*40;
            SDL_SetColorKey(tmpSurface, SDL_SRCCOLORKEY, 0xffffff00);
            SDL_BlitSurface(tmpSurface, 0, screen, &m_blitPos);
        }
        SDL_FreeSurface(tmpSurface);
    }

    // Caisses
    for (Uint16 y(0); y < 18; y++)
        for (Uint16 x(0); x < 24; x++)
            if (m_caisses[y][x])
            {
                m_blitPos.x = x*40;
                m_blitPos.y = y*40;
                SDL_BlitSurface(m_spriteGet->takeSprite("caisse"), 0, screen, &m_blitPos);
            }

    // Bonhommes
    for (Uint16 i(0); i<=1; i++) {
        m_blitPos.x = m_perso[i].x*40;
        m_blitPos.y = m_perso[i].y*40;
        SDL_BlitSurface(m_perso[i].skin, 0, screen, &m_blitPos);
    }
}

bool Niveau::test(Uint16 y, Uint16 x, short dirX, short dirY)
{

    // Mur ?
    if (m_tabl[y][x] == '#')
        return false;

    // Porte fermée ?
    if(m_tabl[y][x] >= 65 && m_tabl[y][x] <= 90)
        if (!m_gates[tolower(m_tabl[y][x])].first)
            return false;

    // Collisions caisse
    if (m_caisses[y][x]) {
        if(m_tabl[y+dirY][x+dirX] == '#')
            return false;
        if(m_tabl[y+dirY][x+dirX] >= 65 && m_tabl[y+dirY][x+dirX] <= 90)
        {
            if(m_gates[tolower(m_tabl[y+dirY][x+dirX])].first)
            {
                m_caisses[y][x] = false;
                m_caisses[y + dirY][x + dirX] = true;
                return true;
            }
            else
                return false;
        }
        else
        {
            m_caisses[y][x] = false;
            m_caisses[y + dirY][x + dirX] = true;
            return true;
        }
    }

    // Si rien n'empêche ...
    return true;
}

char Niveau::getCase(Uint16 y, Uint16 x)
{
    if (y < 18 && x < 24)
        return m_tabl[y][x];

    return '#';
}

void Niveau::setCase(Uint16 y, Uint16 x, char bloc)
{
    if (y < 18 && x < 24)
        m_tabl[y][x] = bloc;
}

bool Niveau::deplacer(char ID, char ordre)
{
    // Détermination du joueur qui bouge
    Uint16 ind;
    if (ID == '0') ind = 0;
    else ind = 1;

    // Détermination de la direction
    short dirX(0), dirY(0);
    switch (ordre)
    {
    case 24://'↑'
        dirY--;
        break;
    case 25://'↓'
        dirY++;
        break;
    case 26://'→'
        dirX++;
        break;
    case 27://'←'
        dirX--;
        break;
    default:
        break;
    }

    // Collisions bonhomme
    for(std::map<char, std::pair<bool, std::vector<int>[2] > >::iterator tmp_gates = m_gates.begin(); tmp_gates!=m_gates.end(); tmp_gates++)
        for(unsigned int i = 0;i<tmp_gates->second.second[1].size();i+=2)
            if(tmp_gates->second.second[1][i] == m_perso[ind].x && tmp_gates->second.second[1][i+1] == m_perso[ind].y)
            {
                if(tmp_gates->second.first)
                    break;
                else
                    return false;
            }
    if (test(m_perso[ind].y+dirY, m_perso[ind].x+dirX, dirX, dirY)) {
        m_perso[ind].y += dirY;
        m_perso[ind].x += dirX;
    }
    return true;
}

void Niveau::updateBoutons()
{
    // Vérifie si un bouton est activé par une caisse A BOUGER
    for(std::map<char, std::pair<bool, std::vector<int>[2] > >::iterator tmp_gates = m_gates.begin(); tmp_gates!=m_gates.end(); tmp_gates++)
    {
        tmp_gates->second.first = false;
        for(unsigned int i = 0;i<tmp_gates->second.second[0].size();i+=2)
            tmp_gates->second.first |= m_caisses[tmp_gates->second.second[0][i+1]][tmp_gates->second.second[0][i]];
    }

    // Vérifie perso on bouton
    int x, y;
    for (Uint16 i(0); i<=1; i++) {
        x = m_perso[i].x;
        y = m_perso[i].y;
        if(m_tabl[y][x] >= 97 && m_tabl[y][x] <= 122)
            m_gates[m_tabl[y][x]].first = true;
    }

    //destruction si caisse sur porte fermée
    for(std::map<char, std::pair<bool, std::vector<int>[2] > >::iterator tmp_gates = m_gates.begin(); tmp_gates!=m_gates.end(); tmp_gates++)
        for(unsigned int i = 0;i<tmp_gates->second.second[1].size();i+=2)
            if(!tmp_gates->second.first && m_caisses[tmp_gates->second.second[1][i+1]][tmp_gates->second.second[1][i]])
                m_caisses[tmp_gates->second.second[1][i+1]][tmp_gates->second.second[1][i]] = false;
}

bool Niveau::suisJeArrive(char ID)
{
     // Détermination du joueur qui bouge
    Uint16 ind;
    if (ID == '0') ind = 0;
    else ind = 1;

    // Retour
    return (m_tabl[m_perso[ind].y][m_perso[ind].x] == 36);//'$'
}