#ifndef ARC_GRAPHICS_SPRITE_H_
#define ARC_GRAPHICS_SPRITE_H_

#ifdef __cplusplus
extern "C" {
#endif

#include "arc/graphics/renderer.h"
#include "arc/graphics/spritesheet.h"
#include "arc/math/point.h"
#include "arc/math/rectangle.h"
#include "arc/std/array.h"

/**
 * @brief a sprite type
 * 
 * @note the actual type should be define by overriding for a graphics api
 */
typedef struct ARC_Sprite ARC_Sprite;

/**
 * @brief creates ARC_Sprite type
 * 
 * @param sprite      ARC_Sprite that is being created
 * @param spritesheet ARC_Spritesheet that ARC_Sprite will be pulled from
 * @param frames      ARC_Array of bounds of sprite on spritesheet
 */
void ARC_Sprite_Create(ARC_Sprite **sprite, ARC_Spritesheet *spritesheet, ARC_Array *frames);

/**
 * @brief destroys ARC_Sprite type
 * 
 * @param sprite ARC_Sprite to destroy
 */
void ARC_Sprite_Destroy(ARC_Sprite *sprite);

/**
 * @brief copies ARC_Sprite to a new ARC_Sprite
 * 
 * @param newSprite ARC_Sprite that is being copied to and created
 * @param oldSprite ARC_Sprite contents that are being copied
 */
void ARC_Sprite_Copy(ARC_Sprite **newSprite, ARC_Sprite *oldSprite);

//TODO: temp
/**
 * @brief sets ARC_Sprite's opacity
 *
 * @param sprite  ARC_Sprite that is changing opacity
 * @param opacity new opacity for ARC_Sprite
 *
 * @note this is temp because opacity probably should be a value
 *       bigger than 255
*/
void ARC_Sprite_SetOpacity(ARC_Sprite *sprite, uint8_t opacity);

/**
 * @brief renders ARC_Sprite type
 * 
 * @param sprite       ARC_Sprite that will be rendered
 * @param renderer     ARC_Renderer that is handling rendering
 * @param renderBounds area of renderer that ARC_Sprite will be rendered to
 */
void ARC_Sprite_Render(ARC_Sprite *sprite, ARC_Renderer *renderer, ARC_Rect *renderBounds);

//TODO: move this to a better location
typedef enum ARC_Sprite_Axis {
    ARC_SPRITE_AXIS_NONE = 0x00,
    ARC_SPRITE_AXIS_Y    = 0x01,
    ARC_SPRITE_AXIS_X    = 0x02,
} ARC_Sprite_Axix;

/**
 * @brief renders ARC_Sprite type with flip
 * 
 * @param sprite       ARC_Sprite that will be rendered
 * @param renderer     ARC_Renderer that is handling rendering
 * @param renderBounds area of renderer that ARC_Sprite will be rendered to
 * @param axis         axis to flip sprite
 */
void ARC_Sprite_RenderFlip(ARC_Sprite *sprite, ARC_Renderer *renderer, ARC_Rect *renderBounds, enum ARC_Sprite_Axis axis);

/**
 * @brief renders ARC_Sprite type with rotation
 * 
 * @param sprite       ARC_Sprite that will be rendered
 * @param renderer     ARC_Renderer that is handling rendering
 * @param renderBounds area of renderer that ARC_Sprite will be rendered to
 * @param angle        angle to rotate ARC_Sprite
 * @param center       point to rotate ARC_Sprite around
 */
void ARC_Sprite_RenderRotated(ARC_Sprite *sprite, ARC_Renderer *renderer, ARC_Rect *renderBounds, ARC_Point *center, double angle);

/**
 * @brief switches ARC_Sprite's frame to specified index
 * 
 * @param sprite ARC_Sprite that is having its frame set
 * @param index  uint32_t to set ARC_Sprite's frame index to
 */
void ARC_Sprite_SetFrameIndex(ARC_Sprite *sprite, uint32_t index);

/**
 * @brief switches ARC_Sprite's frames to next for animation
 * 
 * @param sprite ARC_Sprite that is having its frame updated
 */
void ARC_Sprite_IterateFrame(ARC_Sprite *sprite);

/**
 * @brief gets ARC_Sprite's current frame
 * 
 * @param sprite ARC_Sprite to get frame from
 *
 * @return index ARC_Sprite's current frame index
 */
uint32_t ARC_Sprite_GetFrameIndex(ARC_Sprite *sprite);

/**
 * @brief returns the current bounds based on the ARC_Sprite's frames
 * 
 * @param sprite ARC_Sprite to get bounds from
 */
ARC_Rect *ARC_Sprite_GetBounds(ARC_Sprite *sprite);

/**
 * @brief returns the array of bounds that a sprite has
 *
 * @param sprite ARC_Sprite to get all the bounds from
*/
ARC_Array *ARC_Sprite_GetAllBounds(ARC_Sprite *sprite);

#ifdef __cplusplus
}
#endif

#endif // !ARC_GRAPHICS_SPRITE_H_
