/***************************************************************************
 *                                                                         *
 * Module  : baresour.h                                                    *
 *                                                                         *
 * Purpose : Resource handling                                             *
 *                                                                         *
 **************************************************************************/

#ifndef RWRESOUR_H
#define RWRESOUR_H

/****************************************************************************
 Includes
 */

#include "batypes.h"

/****************************************************************************
 Defines
 */

/* RWPUBLIC */
/****************************************************************************
 Global Types
 */

/**
 * \ingroup datatypes
 * \typedef RwResEntry 
 * RwResEntry object. Instanced data block in resources arena.  
 * This should be considered an opaque
 * type. Use the RwResEntry API functions to access.
 */
typedef struct RwResEntry RwResEntry;

/**
 * \ingroup datatypes
 * \typedef RwResEntryDestroyNotify
 * This type represents the function
 * called from \ref RwResourcesFreeResEntry (and indirectly from 
 * \ref RwResourcesEmptyArena) immediately before the memory used by the
 * specified resources entry is released.
 *
 * \param  entry   Pointer to the instanced data. 
 */
typedef void        (*RwResEntryDestroyNotify) (RwResEntry * resEntry);

#if (!defined(DOXYGEN))
struct RwResEntry
{
    RwLLLink            link;   /**< Node in the list of resource elements */
    RwInt32             size;   /**< Size of this node */
    void               *owner;  /**< Owner of this node */
    RwResEntry        **ownerRef; /**< Pointer to pointer to this (enables de-alloc) */
    RwResEntryDestroyNotify destroyNotify; /**< This is called right before destruction */
};
#endif /* (!defined(DOXYGEN)) */

enum rwResEntryMemoryPool
{
    rwMEMORYPOOLDEFAULT = 0,
    rwMEMORYPOOLARENA,
    rwMEMORYFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum rwResEntryMemoryPool rwResEntryMemoryPool;

/* RWPUBLICEND */

typedef struct rwResources rwResources;
struct rwResources
{
    RwInt32             maxSize;
    RwInt32             currentSize;
    RwInt32             reusageSize;

    void               *memHeap;

    RwLinkList          entriesA;
    RwLinkList          entriesB;

    RwLinkList         *freeEntries;
    RwLinkList         *usedEntries;
};

typedef struct rwResourcesGlobals rwResourcesGlobals;
struct rwResourcesGlobals
{
    rwResources         res;
};

/* RWPUBLIC */
/****************************************************************************
 Function prototypes
 */

#ifdef    __cplusplus
extern              "C"
{
#endif                          /* __cplusplus */

/* Setting the resources arena size */
extern RwBool       RwResourcesSetArenaSize(RwInt32 size);
extern RwInt32      RwResourcesGetArenaSize(void);
extern RwInt32      RwResourcesGetArenaUsage(void);
extern RwBool       RwResourcesEmptyArena(void);

/* Allocation */

/**
 * \ingroup rwresources
 * \def RwResourcesAllocateResEntry is a macro used to allocate 
 * a resources entry for the specified object of the given size. 
 * Also use this function to 
 * specify a callback function that will be executed immediately before the
 * resources entry is removed from the resources arena (pass NULL to indicate 
 * there is no callback).
 * 
 * \param owner  Pointer to the object that will own the resources entry.
 * \param ownerRef  Pointer to a pointer that will receive a reference to 
 *       the resources entry.
 * \param size  A RwInt32 value equal to the size of the resources entry 
 *       to allocate (in bytes).
 * \param destroyNotify  Pointer to destroy notify callback function. 
 *       Specify NULL to ignore.
 *
 * \return Returns pointer to the allocated resources block if successful
 *        or NULL if there is an error.
 * 
 * \see RwResourcesFreeResEntry
 * \see RwResourcesUseResEntry
 */
#define RwResourcesAllocateResEntry(_owner, _ownerRef, _size, _destroyNotify) \
       _rwResourcesAllocateResEntry(_owner,                                   \
                                    _ownerRef,                                \
                                    _size,                                    \
                                    rwMEMORYPOOLARENA,                        \
                                    _destroyNotify)

extern RwResEntry  *_rwResourcesAllocateResEntry(void *owner,
                                                 RwResEntry **
                                                 ownerRef,
                                                 RwInt32 size,
                                                 rwResEntryMemoryPool
                                                 pool,
                                                 RwResEntryDestroyNotify
                                                 destroyNotify);
/* Deallocation */
extern RwBool       RwResourcesFreeResEntry(RwResEntry * entry);
/* Mark all as unused */
extern void         _rwResourcesPurge(void);
/* Mark as used */
extern RwResEntry  *RwResourcesUseResEntry(RwResEntry * entry);

/* RWPUBLICEND */

/* Opening and closing */
extern void        *_rwResourcesOpen(void *instance, RwInt32 offset,
                                     RwInt32 size);
extern void        *_rwResourcesClose(void *instance,
                                      RwInt32 offset, RwInt32 size);

/* RWPUBLIC */
#ifdef    __cplusplus
}
#endif                          /* __cplusplus */

/* RWPUBLICEND */

#endif                          /* RWRESOUR_H */
