
#include "eruta.h"
#include "dynar.h"
#include "sprite.h"
#include "spritelist.h"


/* Sprite list functions. */
/* The list of all loaded sprites. Some may be drawn and some not. */
struct SpriteList_ {
  Dynar * sprites;
  int     sprites_used;
};


/* Allocate a sprite list. */
SpriteList * spritelist_alloc() {
  return STRUCT_ALLOC(SpriteList);
}

SpriteList * spritelist_initall(SpriteList * self, int maxsprites) {
  if (!self) return NULL;
  self->sprites         = dynar_newptr(maxsprites);
  self->sprites_used    = 0;
  dynar_putnullall(self->sprites);
  return self;
}

SpriteList * spritelist_init(SpriteList * self) {
  return spritelist_initall(self, SPRITELIST_NSPRITES_DEFAULT);
}

SpriteList * spritelist_done(SpriteList * self) {
  if (!self) return NULL;
  /* Clean up using a walker callback. */
  dynar_walkptr(self->sprites, sprite_cleanup_walker, NULL);
  self->sprites      = dynar_free(self->sprites);
  self->sprites_used = 0;
  return self;
}

SpriteList * spritelist_new() {
  return spritelist_init(spritelist_alloc());
}


/* Frees the memory associated to the sprite list and all sprites in it. */
SpriteList * spritelist_free(SpriteList * self) {
  return mem_free(spritelist_done(self));
}

/* Gets a sprite from a sprite list. Returns NULL if not found;*/
Sprite * spritelist_sprite(SpriteList * self, int index)  {
  if (!self) return NULL;
  return dynar_getptr(self->sprites, index);
}


/** Deletes a sprite with the given id from the sprite list and frees it. 
 * Returns negative on failure (sprite didn't exist), or 0
 * on success.  */
int spritelist_delete_sprite(SpriteList * self, int index) {
  Sprite * sprite;
  if (!self) return -1;  
  sprite = spritelist_sprite(self, index);
  if (!sprite) return -2;
  sprite_free(sprite);
  dynar_putptr(self->sprites, index, NULL); 
  return 0;
}


/* Puts a sprite into a sprite list. If there was a sprite there already it will 
 * be freed */
Sprite * spritelist_sprite_(SpriteList * self, int index, Sprite * sprite) {
  Sprite * old;
  if (!self) return NULL;
  old = spritelist_sprite(self, index);
  sprite_free(old);
  dynar_putptr(self->sprites, index, sprite);  
  return sprite;
}

/** Makes a new sprite and returns it */
Sprite * spritelist_new_sprite(SpriteList * self) {
  Sprite * sprite;
  int index;
  if (!self) return NULL;
  index = spritelist_get_unused_sprite_id(self);  
  if (index < 0) return NULL;  
  sprite = sprite_new(index);  
  if(!sprite) return NULL;
  return spritelist_sprite_(self, index, sprite);
}

/** Makes a new sprite and returns it's ID or negative on error
 * (ie, cannot make more sprites).
*/
int spritelist_new_sprite_id(SpriteList * self) {
  Sprite * sprite = spritelist_new_sprite(self);
  return sprite_id(sprite);
}


/* Makes a new sprite if it doesn't exist yet or otherwise returns the old one 
 at the given index. 
Sprite * spritelist_getornew(SpriteList * self, int index) {
  Sprite * sprite = spritelist_sprite(self, index);
  if (sprite) return sprite;
  return spritelist_newsprite(self, index);
} 
*/

/* Loads a sprite cell in ulpcss format into the sprite with 
 the given index in the sprite list. If no sprite exists yet,
 it will be created. The sprite s returned on sucess of NULL on failure. 
*/

Sprite * spritelist_loadlayer_ulpcss_vpath(
  SpriteList * self, int index,  int layerindex, char * vpath) { 
  Sprite * sprite;
  int oversize = FALSE;
  if (!self) return NULL;
  if (strstr(vpath, "oversize")) { oversize = TRUE; } 
  sprite = spritelist_sprite(self, index);
  if (!sprite) return NULL;
  if (!sprite_loadlayer_ulpcss_vpath(sprite, layerindex, vpath, oversize)) 
    return NULL;
  return sprite;
}


/* Returns the first unused sprite ID larger than minimum. */
int spritelist_get_unused_sprite_id(SpriteList * self) {
  int index, stop;
  if (!self) return -1;  
  stop = dynar_size(self->sprites);
  for (index = 0; index < stop; index++) {
    Sprite * sprite = spritelist_sprite(self, index);
    if (!sprite) {
      return index;
    }
  }
  return -3;
}


/* Loads a layer of a sprite from a vpath using one of the built in layout
 * loaders, normally ULPCSS format. */
int spritelist_load_sprite_layer_with_builtin_layout
  (SpriteList * me, int sprite_index,
  int layer_index, char * vpath, int layout) {

  Sprite * sprite = spritelist_sprite(me, sprite_index);
  if (!sprite) return -1;
  if(sprite_loadlayer_ulpcss_vpath(sprite, layer_index, vpath, layout)) { 
    return sprite_index;
  } else {
    return -2;
  }
}


/* Loads a layer of a sprite from a vpath using a custom layout. */
int spritelist_load_sprite_layer_with_layout
  (SpriteList * me, int sprite_index,
  int layer_index, char * vpath, SpriteLayout * layout) {

  Sprite * sprite = spritelist_sprite(me, sprite_index);
  if (!sprite) return -1;
  if(sprite_loadlayer_vpath(sprite, layout, layer_index, vpath)) { 
    return sprite_index;
  } else {
    return -2;
  }
}





