#ifndef DATA_MANAGER_HPP
#define DATA_MANAGER_HPP

// Détection du système cible...
#include "usgeDetectSystem.h"

// C++
#include <string>
#include <map>


/**
 * @file DataManager.hpp
 * Déclaration de la classe de "DataManager" : USpeedGameEngine::DataManager
 */

namespace USpeedGameEngine
{

/**
 * Gestionniaire de données pour éviter les doublons.
 * @author U.Speed
 * @class USpeedGameEngine::DataManager
 */
template <class DataType> class DataManager
{
    // Liste des variables
    public:
    protected:
    private:
        std::map<std::string, void*> dataMap;   //!< Liste des données déclarées

    // Liste des fonctions
    public:
        /**
         * Constructeur par défaut.
         * @author U.Speed
         */
        DataManager() { this->clear(); }

        /**
         * Destructeur par défaut.
         * @author U.Speed
         */
        ~DataManager() { this->clear(); }

        /**
         * Suppression de toutes les données.
         * Attention ! Il ne s'agit que de la suppression des références dans le gestionnaire des données.<br />
         * Aucune désallocation de mémoire n'est effectuée.
         * @author U.Speed
         */
        void clear()
        {
            // Vider la liste
            this->clear(false);
        }

        /**
         * Suppression de toutes les données <b>AVEC POSSIBILITÉ de désallocation de mémoire</b>.
         * @author U.Speed
         * @param delData bool : <code>true</code> pour effectuer un "<code>delete</code>" sur chaque donnée référencée.
         */
        void clear(bool delData)
        {
            if (delData == true)
            {
                // Parcours de la liste des données pour les supprimer
                std::map<std::string, void*>::iterator elt;
                for (elt = this->dataMap.begin(); elt != this->dataMap.end(); elt++)
                {
                    delete (DataType*)elt->second;
                }
            }
            // Vider la liste
            this->dataMap.clear();
        }

        /**
         * Suppression d'une donnée.
         * Attention ! Il ne s'agit que de la suppression des références dans le gestionnaire des données.<br />
         * Aucune désallocation de mémoire n'est effectuée.
         * @author U.Speed
         * @param key std::string const& : la clé de la donnée à supprimer
         */
        void erase(std::string const &key)
        {
            this->erase(key, false);
        }

        /**
         * Suppression d'une donnée <b>AVEC POSSIBILITÉ de désallocation de mémoire</b>.
         * @author U.Speed
         * @param key std::string const& : la clé de la donnée à supprimer
         * @param delData bool : <code>true</code> pour effectuer un "<code>delete</code>" sur la donnée référencée.
         */
        void erase(std::string const &key, bool delData)
        {
            // Une clé valide ?
            if (key.size() > 0)
            {
                // Recherche de l'élément
                std::map<std::string, void*>::iterator elt = this->dataMap.find(key);
                if (elt != this->dataMap.end())
                {
                    // Suppression effective
                    if (delData == true)
                    {
                        delete (DataType*)elt->second;
                    }
                    // Retrait de la liste
                    this->dataMap.erase(elt);
                }
            }
        }

        /**
         * Ajout d'une texture.
         * @author U.Speed
         * @param key std::string const& : la clé de référence
         * @param data DataType* : le pointeur de la donnée à ajouter
         * @return bool : <code>true</code> si l'ajout a été effectué. <code>false</code> si la clé est invalide ou déjà saisie ou que la donnée est nulle.
         */
        bool add(std::string const &key, DataType *data)
        {
            bool result = false;
            // La clé et la texture doit être valide !
            if ((key.size() > 0) && (data != 0))
            {
                // Si la clé n'est pas déjà utilisée...
                if (this->find(key) == 0)
                {
                    // ...on peut ajouter la texture fournie !
                    this->dataMap.insert(std::make_pair(key, data));
                }
            }
            return result;
        }

        /**
         * Accès à une texture.
         * @author U.Speed
         * @param key std::string const& : la clé de référence
         * @return DataType* : le pointeur de la texture concernée ou pointeur nul si non trouvée
         */
        DataType *find(std::string const &key)
        {
            DataType *data = 0;
            // Une clé valide ?
            if (key.size() > 0)
            {
                // Recherche de l'élément
                std::map<std::string, void*>::iterator elt = this->dataMap.find(key);
                if (elt != this->dataMap.end())
                {
                    // Élément trouvé
                    data = (DataType *)elt->second;
                }
            }
            return data;
        }

    protected:
    private:
};

}

#endif
