#ifndef _HPP_GAIA_TEXTURELIBRARY
#define _HPP_GAIA_TEXTURELIBRARY

#include <vector>
#include <SDL_image.h>

namespace gaia {

  struct Texture {
    Texture() {
      referenceCount = 0;
    }
    SDL_Texture* sdlTexture;
    std::string filename;
    bool reusable;
    int referenceCount;
    int w, h;
  };

  // singleton
  class TextureLibrary {

    public:

      static TextureLibrary &GetInstance() {
        static TextureLibrary instance; // guaranteed to be destroyed on progam end
        return instance;
      }

      TextureLibrary() {}
      virtual ~TextureLibrary() {
        for (unsigned int i = 0; i < textures.size(); i++) {
          printf("~TextureLibrary(): texture '%s' left undeleted :( lrn2cleanup!\n", textures.at(i).filename.c_str());
        }
      }

      TextureLibrary(TextureLibrary const&) = delete;
      void operator=(TextureLibrary const&) = delete;

      SDL_Texture *FetchTexture(const std::string &filename, e_FilterMode filterMode = e_FilterMode_Nearest, int *w = 0, int *h = 0, bool reusable = true) {
        Texture texture;
        if (reusable) {
          int index = -1;
          bool found = FindTexture(filename, index);
          if (found) {
            textures.at(index).referenceCount++;
            *w = textures.at(index).w;
            *h = textures.at(index).h;
            return textures.at(index).sdlTexture;
          }
        }
        // not found (or not reusable)
        texture.sdlTexture = LoadSDLTexture(filename, filterMode, w, h);
        texture.filename = filename;
        texture.w = *w;
        texture.h = *h;
        texture.reusable = reusable;
        texture.referenceCount = 1;
        textures.push_back(texture);
        return texture.sdlTexture;
      }

      void ReleaseTexture(SDL_Texture *sdlTexture) {
        int index = -1;
        bool found = FindTexture(sdlTexture, index);
        if (found) {
          textures.at(index).referenceCount--;
          if (textures.at(index).referenceCount <= 0) {
            //printf("erasing texture: %s\n", textures.at(index).filename.c_str());
            SDL_DestroyTexture(textures.at(index).sdlTexture);
            textures.erase(textures.begin() + index);
          }
        }
      }

      bool FindTexture(const std::string &filename, int &index_ret) {
        for (unsigned int i = 0; i < textures.size(); i++) {
          if (textures.at(i).filename.compare(filename) == 0 && textures.at(i).reusable == true) {
            index_ret = i;
            return true;
          }
        }
        return false;
      }

      bool FindTexture(const SDL_Texture *sdlTexture, int &index_ret) {
        for (unsigned int i = 0; i < textures.size(); i++) {
          if (textures.at(i).sdlTexture == sdlTexture && textures.at(i).reusable == true) {
            index_ret = i;
            return true;
          }
        }
        return false;
      }

    private:

      std::vector<Texture> textures;

  };

}

#endif
