#include "Errlog.h"
#include "GResource.h"
#include "Program.h"

std::deque<GResource *> ToLoad;


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


void OpacityBlend(float op) {
  al_set_blender(ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, al_map_rgba_f(1.0, 1.0, 1.0, op));
}

void OpacityBlendMix(float op) {
  GCOLOR b;
  al_get_blender(NULL, NULL, &b);
  float tr, tg, tb, ta;
  al_unmap_rgba_f(b, &tr, &tg, &tb, &ta);
  al_set_blender(ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, al_map_rgba_f(tr, tg, tb, op));
}

void ColorBlend(GCOLOR c) {
  al_set_blender(ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, c);
}

void NormalBlend() {
  al_set_blender(ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, al_map_rgba_f(1, 1, 1, 1));
}


GBitmap *GetBitmap(std::string name) {
  std::deque<GBitmap *>::iterator it;
  for (it=GBitmaps.begin(); it!=GBitmaps.end(); it++) {
    if ((*it)->GetName() == name) {
      return (*it);
    }
  }

  GBitmap *g;
  g = new GBitmap(name);
  GBitmaps.push_back(g);
  return g;
}


GFont *GetFont(std::string name) {
  std::deque<GFont *>::iterator it;
  for (it=GFonts.begin(); it!=GFonts.end(); it++) {
    if ((*it)->GetName() == name) {
      return (*it);
    }
  }

  GFont *g;
  g = new GFont(name);
  GFonts.push_back(g);
  return g;
}

GSound *GetSound(std::string name) {
  std::deque<GSound *>::iterator it;
  for (it=GSounds.begin(); it!=GSounds.end(); it++) {
    if ((*it)->GetName() == name) {
      return (*it);
    }
  }

  GSound *g;
  g = new GSound(name);
  GSounds.push_back(g);
  return g;
}


/*  BITMAP ROUTINES  */

GBitmap::GBitmap(std::string nm) {
  name = nm;
  mods.clear();
  bit = NULL;
  Load();
}


void GBitmap::Load() {
  if ((bit == NULL) && (ProgramStarted)) {
    if (name != "NONE") {
      if (!FileExists(name)) {
        bit = GLOAD_BITMAP("Data/Missing.png");
        if (GlobalLog!=NULL) GlobalLog->LogMessage(name + " couldn't be loaded because it doesn't exist.");
      }
      else {
        if (ProgramStarted) bit = GLOAD_BITMAP(name.c_str());
        if (ProgramStarted) {
          if (!bit) {
            if (GlobalLog!=NULL) GlobalLog->LogMessage("Loading " + name + " failed.");
          }
          else {
            if (GlobalLog!=NULL) GlobalLog->LogMessage("Loaded " + name + " correctly.");
          }
        }
      }
    }
  }
}


GBitmap *GBitmap::AddModifiedVersion(std::string nm, GBITMAP *b) {
  std::deque<GBitmap *>::iterator it;
  for (it=mods.begin(); it!=mods.end(); it++) {
    if ((*it)->GetName() == nm) {
      return (*it);
    }
  }

  GBitmap *new_mod;
  new_mod = new GBitmap(nm, b);
  mods.push_back(new_mod);
  return new_mod;
}


GBitmap *GBitmap::GetModifiedVersion(std::string nm) {
  std::deque<GBitmap *>::iterator it;
  for (it=mods.begin(); it!=mods.end(); it++) {
    if ((*it)->GetName() == nm) {
      return (*it);
    }
  }
  return NULL;
}




/*  FONTS ROUTINES  */

float GFont::Width(std::string text) {
  if (font != NULL) return al_get_text_width(font, text.c_str());
  else return 0;
}


GFont::GFont(std::string nm, int sz) {
  size = sz;
  name = nm;
  if ((size > 0) && (ProgramStarted)) font = GLOAD_FONT(name.c_str(), size, 0);
  else ToLoad.push_back(this);
  sizes.clear();
}

GFont *GFont::GetSize(int sz) {
  if (sz == size) {
    return this;
  }

  std::deque<GFont *>::iterator it;
  for (it = sizes.begin(); it!=sizes.end(); it++) {
    if ((*it)->GetDefaultSize() == sz) {
      return (*it);
    }
  }

  GFont *f;
  f = new GFont(name, sz);
  sizes.push_back(f);
  return f;
}



void GFont::PrintOutline(std::string text, float x, float y, int sz, int flag, GCOLOR c) {
  Print(text, x-1, y, sz, flag, al_map_rgb(0,0,0));
  Print(text, x+1, y, sz, flag, al_map_rgb(0,0,0));
  Print(text, x, y-1, sz, flag, al_map_rgb(0,0,0));
  Print(text, x, y+1, sz, flag, al_map_rgb(0,0,0));
  Print(text, x, y, sz, flag, c);
}


void GFont::Print(std::string text, float x, float y, int sz, int flag, GCOLOR c) {
  if ((sz == -1) || (sz==size)) {
    ColorBlend(c);
    al_draw_text(font, x, y, flag, text.c_str());
    NormalBlend();
  }
  else {
    GFont *f;
    f = GetSize(sz);
    f->Print(text, x, y, sz, flag, c);
  }
}





/*  SOUND ROUTINES  */

GSound::GSound(std::string nm) {
  name = nm;
  sample = NULL;
  if (name != "NONE") {
    if (!FileExists(name)) {
      sample = GLOAD_SAMPLE("Data/Missing.ogg");
      if (GlobalLog!=NULL) GlobalLog->LogMessage(nm + " couldn't be loaded because it doesn't exist.");
    }
    else {
      if (ProgramStarted) sample = GLOAD_SAMPLE(name.c_str());
      else {
        ToLoad.push_back(this);
      }
      if (!sample) {
        if (GlobalLog!=NULL) GlobalLog->LogMessage("Loading " + name + " failed.");
      }
      else {
        if (GlobalLog!=NULL) GlobalLog->LogMessage("Loaded " + name + " correctly.");
      }
    }
  }
}


void GSound::Play(float gain, float pan, float freq, int flag) {
  al_play_sample(sample, gain, pan, freq, flag, NULL);
}



void Play3DSample(ALLEGRO_SAMPLE *s, float vol, float freq, float loop, float x, float y) {
/*  float cvol;
  cvol = distance_between_points(x, y, RSW(Camera_X)+SCREEN_W/2, RSH(Camera_Y)+SCREEN_H/2);
  cvol = cvol / SCREEN_W;
  cvol = 1.0 - cvol;

  if (cvol < 0) cvol = 0;

  vol = (float)vol * cvol;

  float d;
  d = x - (RSW(Camera_X) + SCREEN_W/2);
  d = d / (SCREEN_W/2);

  int pan;

  pan = 0.5 + (0.5 * d);

  if (pan < 0) pan = 0;
  if (pan > 1) pan = 1;

  al_play_sample(s, vol, pan, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL);*/
}

GCOLOR MixColor(ALLEGRO_COLOR c1, ALLEGRO_COLOR c2, float p) {
  float dr, br, dg, bg, db, bb, da, ba;
  al_unmap_rgba_f(c1, &dr, &dg, &db, &da);
  al_unmap_rgba_f(c2, &br, &bg, &bb, &ba);
  return al_map_rgba_f(dr+(dr-br)*p, dg+(dg-bg)*p, db+(db-bb)*p, da+(da-ba)*p);
}


void ClearGResources() {
  for (std::deque<GBitmap *>::iterator it=GBitmaps.begin(); it!=GBitmaps.end(); it++) {
    delete (*it);
  }
  for (std::deque<GSound *>::iterator it=GSounds.begin(); it!=GSounds.end(); it++) {
    delete (*it);
  }
  for (std::deque<GFont *>::iterator it=GFonts.begin(); it!=GFonts.end(); it++) {
    delete (*it);
  }
  GBitmaps.clear();
  GSounds.clear();
  GFonts.clear();
}
