#include "allegroall.h"
#include <string>
#include <deque>
#include "errlog.h"
#include "MathLib.h"

#ifndef GRESOURCE_H_INCLUDED
#define GRESOURCE_H_INCLUDED


// Some global defines will make my life easier in case I need to switch the library.


#define GBITMAP  ALLEGRO_BITMAP
#define GSAMPLE  ALLEGRO_SAMPLE
#define GFONT    ALLEGRO_FONT
#define GCOLOR   ALLEGRO_COLOR


#define GLOAD_BITMAP    al_load_bitmap
#define GLOAD_SAMPLE    al_load_sample
#define GDESTROY_BITMAP al_destroy_bitmap
#define GLOAD_FONT      al_load_font
#define GCLONE_BITMAP   al_clone_bitmap
#define GWIDTH          al_get_bitmap_width
#define GHEIGHT         al_get_bitmap_height

#define GCOLOR_WHITE al_map_rgb_f(1.0, 1.0, 1.0)


void OpacityBlend(float op);
void OpacityBlendMix(float op);
void ColorBlend(GCOLOR c);
void NormalBlend();



class GResource {
  protected:
    std::string name;
  public:
    GResource(std::string nm="NONE") {name=nm;}

    void SetName(std::string nm) {name=nm;}
    std::string GetName() {return name;}

    // Wrapper for GetName and == between two Resources
    bool Compare(GResource *r) {
      if (r == NULL) return false;
      if (r->GetName() == name) {
        return true;
      }
      return false;
    }

    virtual void Load(){}
};



class GBitmap : public GResource {
  protected:
    GBITMAP *bit;
    std::deque<GBitmap *> mods;
  public:

    // Constructs a Resource bitmap with nothing inside, or loads the bitmap from HD if name != "NONE"
    GBitmap(std::string nm="NONE");

    // Constructs a Resource bitmap with a given name and a bitmap
    GBitmap(std::string nm, GBITMAP *b) {name=nm; bit=b; mods.clear();}

    // Adds a new Resource Bitmap to the modified versions list.
    GBitmap *AddModifiedVersion(std::string nm, GBITMAP *b);

    // Gets a mod from the mods list.
    GBitmap *GetModifiedVersion(std::string nm);

    // Returns the bitmap

    GBITMAP *GetBit() {
      Load();
      return bit;
    }

    // Returns a clone of the bitmap. Useful for modified versions.

    GBITMAP *CreateClone() {
      if (bit != NULL) return GCLONE_BITMAP(bit);
      else return NULL;
    }

    // Loads the bitmap with the name given previously.

    void Load();

    // Destructor
    ~GBitmap() {
      if (bit != NULL) GDESTROY_BITMAP(bit);
      std::deque<GBitmap *>::iterator it;
      for (it=mods.begin();it!=mods.end();it++) {
        delete (*it);
      }
      mods.clear();
    }

    int Width() {if (bit != NULL) return GWIDTH(bit);}
    int Height() {if (bit != NULL) return GHEIGHT(bit);}

    void Draw(float x, float y, int flag);
    void DrawScaled(float x, float y, float w, float h, int flag);

    void DrawTransformed(float x, float y, float w, float h, float angle, int flag=0);
    void DrawTransformedMotionBlur(int x, int y, int w, int h, float angle, int flag, Vec2D blur_dir, float angle_dir=0);
    void GBitmap::DrawCenteredMotionBlur(int x, int y, int w, int h,float cx, float cy, float angle, int flag, Vec2D blur_dir, float angle_dir=0);
    void DrawCentered(float x, float y, float w, float h, float cx, float cy, float angle, int flag=0);
};


class GFont : public GResource {
  protected:
    GFONT *font;
    std::deque<GFont *> sizes;
    int size;
  public:
    // Constructs a Font. If size <= 0, it won't preload any size.
    GFont(std::string nm, int sz=0);

    // Request Font with given size
    GFont *GetSize(int sz);

    int GetDefaultSize() {
      return size;
    }

    // Loads the font with the name given previously.

    void Load() {
      font = GLOAD_FONT(name.c_str(), size, 0);
    }

    // High Level print function, which will automatically handle any loading of a font with different size
    void Print(std::string text, float x, float y, int sz=-1, int flag=ALLEGRO_ALIGN_LEFT, GCOLOR c=GCOLOR_WHITE);

    void PrintOutline(std::string text, float x, float y, int sz=-1, int flag=ALLEGRO_ALIGN_LEFT, GCOLOR c=GCOLOR_WHITE);

    float Width(std::string text);
    int Height() {
      return size;
    }

    ~GFont() {
      if ((font != NULL) && (size != 0)) al_destroy_font(font);
      std::deque<GFont *>::iterator it;
      for (it=sizes.begin(); it!=sizes.end(); it++) {
        delete (*it);
      }
      sizes.clear();
    }
};



class GSound : public GResource {
  protected:
    GSAMPLE *sample;
  public:
    // Constructs a Sample with nothing inside, or loads the bitmap from HD if name != "NONE"
    GSound(std::string nm="NONE");

    GSAMPLE *GetSample() {return sample;}

    void Play(float gain=1.0, float pan=0.5, float freq=1.0, int flag=ALLEGRO_PLAYMODE_ONCE);

    ~GSound() {
      if (sample != NULL) al_destroy_sample(sample);
    }
};


GCOLOR MixColor(ALLEGRO_COLOR c1, ALLEGRO_COLOR c2, float p);


extern std::deque<GBitmap *> GBitmaps;
extern std::deque<GFont *>   GFonts;
extern std::deque<GSound *>  GSounds;

extern std::deque<GResource *> ToLoad;

GBitmap *GetBitmap(std::string);
GFont *GetFont(std::string);
GSound *GetSound(std::string);

void ClearGResources();


#endif
