#include "Niveau.h"

Niveau::Niveau():m_font(0),m_items(0),m_nom("Sans Nom"),m_nomFichier(""),m_lvlNumber(0),m_effectifItems(0)
{
    m_font = SDL_CreateRGBSurface(SDL_HWSURFACE, 600, 600, 32, 0, 0, 0, 0);
    m_items = SDL_CreateRGBSurface(SDL_HWSURFACE, 600, 600, 32, 0, 0, 0, 0);
    reset();
}

Niveau::Niveau(std::string nomFichier, Uint16 fraction):m_font(0),m_items(0),m_nom("Sans Nom"),m_nomFichier(""),m_lvlNumber(0),m_effectifItems(0)
{
    m_font = SDL_CreateRGBSurface(SDL_HWSURFACE, 600, 600, 32, 0, 0, 0, 0);
    m_items = SDL_CreateRGBSurface(SDL_HWSURFACE, 600, 600, 32, 0, 0, 0, 0);

    if (!creer(nomFichier,fraction))//Si impossible de créer le niveau ...
        reset();//On le formate. Utile pour l'éditeur, mais impossible à jouer. ;-)
}

Niveau::~Niveau()
{
    SDL_FreeSurface(m_font);
    SDL_FreeSurface(m_items);
}

int Niveau::peindreFont(Uint16 fraction)
{
    /// [1] Mettre au point les surfaces
    // [A] Couleur de m_font en rouge + blanc
    Uint32 fontColor(8388608);//rouge foncé 32 bits
    SDL_FillRect(m_font,NULL,fontColor);
    Uint32 blanc(SDL_MapRGB(m_font->format,255,255,255));

    // [B] Surface de colle en rouge et mur_gomme en blanc
    SDL_Surface* fontCopie = SDL_CreateRGBSurface(SDL_HWSURFACE, m_font->w, m_font->h, 32, 0, 0, 0, 0);
    SDL_Surface* mur = SDL_CreateRGBSurface(SDL_HWSURFACE, LG_BLOC, LG_BLOC, 32, 0, 0, 0, 0);
    SDL_FillRect(fontCopie,NULL,fontColor);
    SDL_FillRect(mur,NULL,blanc);
    SDL_Rect pos={0,0,0,0};

    // [C] Préparation au gommage
    if (fraction==0 || LG_BLOC%fraction!=0)
    {
        std::cout << "Objet Niveau: argument non renseigné ou non-multiple de " << LG_BLOC << std::endl;
        fraction=5;
    }
    Uint16 coteGum(LG_BLOC/fraction);
    SDL_Surface* gomme = SDL_CreateRGBSurface(SDL_HWSURFACE,coteGum, coteGum, 32, 0, 0, 0, 0);
    SDL_FillRect(gomme,NULL,fontColor);

    // [D] Chargement des textures
    SDL_Surface* solTexture = SDL_LoadBMP("Textures/planks.bmp");
    SDL_Surface* murTexture = SDL_LoadBMP("Textures/cobblestone.bmp");
    SDL_Surface* plaqueSprite = SDL_LoadBMP("Textures/plaque.bmp");
    SDL_Surface* spawnAllieImg = SDL_LoadBMP("Textures/spawnAllie.bmp");
    SDL_Surface* spawnFantomImg = SDL_LoadBMP("Textures/spawnFantom.bmp");
    if (solTexture==0 || murTexture==0 || plaqueSprite==0 || spawnAllieImg==0 || spawnFantomImg==0)
    {
        std::cout << "Problème de chargement de texture dans l'objet Niveau, dans textures." << std::endl;
        return 1;
    }
    SDL_SetColorKey(plaqueSprite,SDL_SRCCOLORKEY,blanc);
    SDL_SetColorKey(spawnAllieImg,SDL_SRCCOLORKEY,blanc);
    SDL_SetColorKey(spawnFantomImg,SDL_SRCCOLORKEY,blanc);

    // [E] Application des textures
    SDL_Surface* fullMur = SDL_CreateRGBSurface(SDL_HWSURFACE,600,600, 32, 0, 0, 0, 0);
    for (int i(0); i<600; i++)
    {
        for (int j(0); j<600; j++)
        {
            //Collage du sol sur m_font
            pos.x=i*solTexture->w;
            pos.y=j*solTexture->h;
            SDL_BlitSurface(solTexture, 0, m_font, &pos);

            //Collage du mur sur fullMur
            pos.x=i*murTexture->w;
            pos.y=j*murTexture->h;
            SDL_BlitSurface(murTexture, 0, fullMur, &pos);
        }
    }

    /// [2] Dessiner la surface de niveau sur la copie du fond
    const int largeurTabl(LG_BLOC/coteGum);
    //Balayage du terrain
    for (int y(0); y<LG_TABL; y++)
    {
        for (int x(0); x<LG_TABL; x++)
        {
            //Collage si besoin sur m_font
            if (m_tabl[y][x]==PLAQUE)
            {
                pos.x=x*LG_BLOC+(LG_BLOC-plaqueSprite->w)/2;
                pos.y=y*LG_BLOC+(LG_BLOC-plaqueSprite->h);
                SDL_BlitSurface(plaqueSprite,0,m_font,&pos);
            }
            if (m_tabl[y][x]==SPAWN_ALLIE)
            {
                pos.x=x*LG_BLOC+(LG_BLOC-spawnAllieImg->w)/2;
                pos.y=y*LG_BLOC+(LG_BLOC-spawnAllieImg->h)/2;
                SDL_BlitSurface(spawnAllieImg,0,m_font,&pos);
            }
            if (m_tabl[y][x]==SPAWN_PHANTOM)
            {
                pos.x=x*LG_BLOC+(LG_BLOC-spawnFantomImg->w)/2;
                pos.y=y*LG_BLOC+(LG_BLOC-spawnFantomImg->h)/2;
                SDL_BlitSurface(spawnFantomImg,0,m_font,&pos);
            }
            //Collage du mur en entier sur fontCopie
            if (m_tabl[y][x]==MUR)
            {
                pos.x=x*LG_BLOC;
                pos.y=y*LG_BLOC;
                SDL_BlitSurface(mur, 0, fontCopie, &pos);

                //Ajustement mur
                for (int i(0); i<largeurTabl; i++)//x
                {
                    for (int j(0); j<largeurTabl; j++)//y
                    {
                        //Inventaire des parties à conserver
                        short dirx,diry;//permet de savoir où regarder autour
                        if (i==0)
                            dirx=-1;
                        else if (i==largeurTabl-1)
                            dirx=1;
                        else
                            dirx=0;
                        if (j==0)
                            diry=-1;
                        else if (j==largeurTabl-1)
                            diry=1;
                        else
                            diry=0;
                        //Gommage des parties inutiles

                        if (typeBloc(x+dirx,y+diry)!=MUR || typeBloc(x+dirx,y)!=MUR || typeBloc(x,y+diry)!=MUR)
                        {
                            pos.x=x*LG_BLOC+i*coteGum;
                            pos.y=y*LG_BLOC+j*coteGum;
                            SDL_BlitSurface(gomme, 0, fontCopie, &pos);
                        }
                    }
                }//[END for] Ajustement mur
            }//[END if] Collage du mur en entier
        }
    }//[END for] Balayage du terrain

    /// [3] Finalisation des textures
    //Mise en place texture des murs
    SDL_SetColorKey(fontCopie, SDL_SRCCOLORKEY, blanc);//mur en transparence
    SDL_BlitSurface(fontCopie, 0, fullMur, 0);//colle le tracé du sol sur fullMur
    SDL_SetColorKey(fullMur,SDL_SRCCOLORKEY,fontColor);//met le sol transparent

    //Coller les murs sur m_font
    SDL_BlitSurface(fullMur, 0, m_font, 0);

    /// [4] Nettoyer
    SDL_FreeSurface(murTexture);
    SDL_FreeSurface(solTexture);
    SDL_FreeSurface(plaqueSprite);
    SDL_FreeSurface(mur);
    SDL_FreeSurface(fontCopie);
    SDL_FreeSurface(gomme);
    SDL_FreeSurface(fullMur);
    SDL_FreeSurface(spawnAllieImg);
    SDL_FreeSurface(spawnFantomImg);

    return 0;
}

bool Niveau::creer(std::string nomFichier, Uint16 fraction)
{
    /// [0] Mise au point du nom du fichier
    nomFichier="Niveaux/"+nomFichier;
    m_nomFichier=nomFichier;

    /// [1] Ouverture du flux
    std::ifstream fluxIn(nomFichier.c_str());
    if (!fluxIn)
    {
        std::cout << "Echec de l'ouverture du fichier : "<<nomFichier<<"."<<std::endl;
        return false;
    }
    else
    {
        std::cout << "Ouverture du fichier "<<nomFichier<<" réussie."<<std::endl;

        /// [2] Remplissage du niveau
        getline(fluxIn,m_nom);
        fluxIn >> m_lvlNumber;
        for (int y(0); y<LG_TABL; y++)
        {
            for (int x(0); x<LG_TABL; x++)
            {
                fluxIn >> m_tabl[y][x];
                if (m_tabl[y][x] == SPAWN_ALLIE)
                {
                    m_spawnAllie[Y] = y;
                    m_spawnAllie[X] = x;
                }
                else if (m_tabl[y][x] < 0)
                {
                    m_spawnPhantom[Y] = y;
                    m_spawnPhantom[X] = x;
                    m_effectifMobs = -m_tabl[y][x];
                    m_tabl[y][x] = SPAWN_PHANTOM;
                }
            }
        }
    }

    /// [3] Peindre la surface du niveau
    if (peindreFont(fraction)==1)
        std::cout << "Problème dans la fonction peindreFont() dans niveau." << std::endl;

    /// [4] Mettre les items
    remplirItems();

    /// [5] Tout va bien !
    return true;
}

void Niveau::afficher(SDL_Surface* support, bool hideItem)
{
    SDL_BlitSurface(m_font, 0, support, 0);
    if (!hideItem)
        SDL_BlitSurface(m_items, 0, support, 0);
}

void Niveau::remplirItems()
{
    //Création de la position SDL
    SDL_Rect pos = {0,0,0,0};

    //Charger les textures
    SDL_FillRect(m_items,0,0);
    SDL_Surface* steackImg = SDL_LoadBMP("Textures/steak.bmp");
    SDL_Surface* tonneauImg = SDL_LoadBMP("Textures/tonneau.bmp");
    if (steackImg==0 || tonneauImg==0)
        std::cout << "Problème de chargement de texture dans l'objet Niveau, dans items." << std::endl;

    //Parcours du tableau
    m_effectifItems=0;
    for (int x(0); x<LG_TABL; x++)
        for (int y(0); y<LG_TABL; y++)
        {
            //Teste le terrain
            if (m_tabl[y][x]==RIEN)
            {
                //Renseigne la présence du steack
                m_itemTabl[y][x]=STEACK;
                m_effectifItems++;

                //Modifie la surface
                pos.x=x*LG_BLOC+(LG_BLOC-steackImg->w)/2;
                pos.y=y*LG_BLOC+(LG_BLOC-steackImg->h)/2;
                SDL_BlitSurface(steackImg, 0, m_items, &pos);
            }
            else if (m_tabl[y][x]==PLAQUE)
            {
                //Renseignela présence du tonneau
                m_itemTabl[y][x]=TONNEAU;
                m_effectifItems++;

                //Modifie la surface
                pos.x=x*LG_BLOC+(LG_BLOC-tonneauImg->w)/2;
                pos.y=y*LG_BLOC+(LG_BLOC-tonneauImg->h)/2;
                SDL_BlitSurface(tonneauImg, 0, m_items, &pos);
            }
            else//Renseigne l'absence d'item
                m_itemTabl[y][x]=VIDE;
        }

    //Met au point la surface des items
    SDL_SetColorKey(m_items,SDL_SRCCOLORKEY,0);

    //Nettoyer la texture
    SDL_FreeSurface(steackImg);
    SDL_FreeSurface(tonneauImg);
}

short Niveau::typeBloc(int x, int y, bool coordonee)
{
	///Adapter les coordonnées si besoin
    if(coordonee)
    {
        x /= LG_BLOC;
        y /= LG_BLOC;
    }
	///Accès sécurisé au tableau
    if (x<0 || x>=LG_TABL || y>=LG_TABL || y<0)
       return MUR;
    else
        return m_tabl[y][x];
}

short Niveau::takeItem(int x, int y, bool coordonee)
{
    ///Adapter les coordonnées si besoin
    if(coordonee)
    {
        x /= LG_BLOC;
        y /= LG_BLOC;
    }
	///Accès sécurisé au tableau
    if (x<0 || x>=LG_TABL || y>=LG_TABL || y<0)
    {
        std::cout << "Attention: demande d'une case de tableau inexistante avec typeItem()" << std::endl;
        return VIDE;
    }
    else
    {
        //Recupere l'item
        short butin(m_itemTabl[y][x]);
        m_itemTabl[y][x]=VIDE;

        if (butin!=VIDE)
        {
            //Gommage de l'item
            SDL_Surface* gomme = SDL_CreateRGBSurface(SDL_HWSURFACE, LG_BLOC, LG_BLOC, 32, 0, 0, 0, 0);
            SDL_Rect pos = {0,0,0,0};
            pos.x=x*LG_BLOC;
            pos.y=y*LG_BLOC;
            SDL_BlitSurface(gomme,0,m_items,&pos);
            SDL_SetColorKey(m_items,SDL_SRCCOLORKEY,0);
            SDL_FreeSurface(gomme);

            //Retire un objet
            m_effectifItems--;
        }

        //Retour
        return butin;
    }
}


int Niveau::itemsRestants()
{
    return m_effectifItems;
}


int Niveau::popFantom(axe choisi)
{
    if (choisi == X)
        return m_spawnPhantom[X];
    else if (choisi == Y)
        return m_spawnPhantom[Y];
    else
        return EXIT_FAILURE;
}

int Niveau::popAllie(axe choisi)
{
    if (choisi == X)
        return m_spawnAllie[X];
    else if (choisi == Y)
        return m_spawnAllie[Y];
    else
        return EXIT_FAILURE;
}

int Niveau::getEffectifMobs()
{
    return m_effectifMobs;
}


std::string Niveau::getNom()
{
    return m_nom;
}

void Niveau::save(int effectifPhantom)
{
    std::cout << "Demande de sauvegarde du niveau: " << m_nomFichier << std::endl;
    std::ofstream ecriture(m_nomFichier.c_str());
    if (ecriture)
    {
        ecriture << m_nom << std::endl;
        ecriture << m_lvlNumber;
        for (int y(0); y<LG_TABL; y++)
        {
            ecriture << std::endl;
            for (int x(0); x<LG_TABL; x++)
            {
                if (m_tabl[y][x]==SPAWN_PHANTOM)
                    ecriture << -effectifPhantom;
                else
                    ecriture << m_tabl[y][x];
                ecriture << " ";
            }
        }
    }
    else
        std::cout << "La sauvegarde a échoué." << std::endl;
}

void Niveau::placeBloc(short blocChoisi, int x, int y, Uint32 couleur, bool coordonee)
{
    ///Adapter les coordonnées si besoin
    if(coordonee)
    {
        x /= LG_BLOC;
        y /= LG_BLOC;
    }

    ///Modifier le tableau numérique
    if (x>=0 && x<LG_TABL && y>=0 && y<LG_TABL)
        m_tabl[y][x]=blocChoisi;

    ///Modifier l'image
    SDL_Surface* carreColore = SDL_CreateRGBSurface(SDL_HWSURFACE, LG_BLOC, LG_BLOC, 32, 0, 0, 0, 0);
    SDL_FillRect(carreColore,NULL,couleur);
    SDL_Rect position;
    position.x = x*LG_BLOC;
    position.y = y*LG_BLOC;
    SDL_BlitSurface(carreColore, 0, m_font, &position);
    SDL_FreeSurface(carreColore);
}

void Niveau::reset()
{
    //Remplir de murs
    for (int y(0); y<LG_TABL; y++)
        for (int x(0); x<LG_TABL; x++)
            m_tabl[y][x]=MUR;

    //Peindre les murs
    if (peindreFont(5)==1)
        std::cout << "Problème dans la fonction peindreFont() dans niveau." << std::endl;
}