/***************************************************************************
 * Module  : bastream.h                                                    *
 *                                                                         *
 * Purpose : Stream handling                                               *
 *                                                                         *
 **************************************************************************/

#ifndef RWSTREAM_H
#define RWSTREAM_H

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

#include "bamemory.h"

/* RWPUBLIC */

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

#define rwSTREAMSTACKSIZE    512

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

/**
 * \ingroup datatypes
 * \ref RwStreamType 
 * This type represents the different types of stream that 
 * can be used. 
 * See API section \ref rwstream 
 */
enum RwStreamType
{
    rwNASTREAM = 0,     /**<Invalid stream type */
    rwSTREAMFILE,       /**<File */
    rwSTREAMFILENAME,   /**<File name */
    rwSTREAMMEMORY,     /**<Memory*/
    rwSTREAMCUSTOM,     /**<Custom */
    rwSTREAMTYPEFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum RwStreamType RwStreamType;

/**
 * \ingroup datatypes
 * \ref RwStreamAccessType 
 * This type represents the options available for 
 * accessing a stream when it is opened.
 * See API section \ref rwstream */
enum RwStreamAccessType
{
    rwNASTREAMACCESS = 0,   /**<Invalid stream access */
    rwSTREAMREAD,           /**<Read */
    rwSTREAMWRITE,          /**<Write */
    rwSTREAMAPPEND,         /**<Append */
    rwSTREAMACCESSTYPEFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum RwStreamAccessType RwStreamAccessType;

/* Memory stream */
/**
 * \ingroup datatypes
 * \typedef RwStreamMemory
 * This should be considered an opaque type.
 * Use the RwStream API functions to access.
 */
typedef struct RwStreamMemory RwStreamMemory;
#if (!defined(DOXYGEN))
struct RwStreamMemory
{
    RwUInt32            position; /* Current 'memory' position 0 is first byte */
    RwUInt32            nSize;  /* Space allocated currently */
    RwUInt8            *memBlock; /* Current memory block pointer */
};
#endif /* (!defined(DOXYGEN)) */


typedef union RwStreamFile RwStreamFile;
/**
 * \ingroup datatypes
 * \union RwStreamFile 
 * This type is used to represent a file pointer for
 * accessing data on disk through the stream mechanism.
 * See API section \ref rwstream. */
union RwStreamFile
{
    void    *fpFile;               /**< file pointer */
    const void    *constfpFile;    /**< const file pointer */
};


/* Custom stream function pointer types */
typedef             RwBool(*rwCustomStreamFnClose) (void *data);
typedef             RwUInt32(*rwCustomStreamFnRead) (void *data, void *buffer,
                                                     RwUInt32 length);
typedef             RwBool(*rwCustomStreamFnWrite) (void *data,
                                                    const void *buffer,

                                                    RwUInt32 length);
typedef             RwBool(*rwCustomStreamFnSkip) (void *data,

                                                   RwUInt32 offset);

/* Custom stream */
/**
 * \ingroup datatypes
 * \typedef  RwStreamCustom
 * This should be considered an opaque type.
 * Use the RwStream API functions to access.
 */
typedef struct RwStreamCustom RwStreamCustom;
#if (!defined(DOXYGEN))
struct RwStreamCustom
{
    rwCustomStreamFnClose sfnclose;
    rwCustomStreamFnRead sfnread;
    rwCustomStreamFnWrite sfnwrite;
    rwCustomStreamFnSkip sfnskip;
    void               *data;
};
#endif /* (!defined(DOXYGEN)) */

/* Stream */

typedef union RwStreamUnion RwStreamUnion;
/**
 * \ingroup datatypes
 * \union RwStreamUnion
 * The union of all supported stream types
 */
union RwStreamUnion
{
    RwStreamMemory      memory; /**< memory */
    RwStreamFile        file; /**< file */
    RwStreamCustom      custom; /**< custom */
};

#ifdef RWASYNCSTREAMS

/* Blocking Mode */
enum RwStreamBlockMode
{
    rwSTREAMBLOCK = 0,
    rwSTREAMNOBLOCK,
    rwSTREAMBLOCKMODEFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
}
typedef enum RwStreamBlockMode RwStreamBlockMode;

typedef struct rwStreamStack rwStreamStack;
struct rwStreamStack
{
    RwBool              callbackRunning;
    RwBool              callbackDeferred;
    RwInt32             deferredIOResult;
    struct rwStreamStackEntry *stackpointer;
    RwUInt8             stack[rwSTREAMSTACKSIZE];
};



#endif /*RWASYNCSTREAMS*/

/**
 * \ingroup datatypes
 * \typedef RwStream 
 * Binary stream for reading or writing object data. 
 * This should be considered an opaque type.
 * Use the RwStream API functions to access.
 */
typedef struct RwStream RwStream;
#if (!defined(DOXYGEN))
struct RwStream
{
    RwStreamType        type;
    RwStreamAccessType  accessType;
    RwInt32             position;
    RwStreamUnion       Type;
#ifdef RWASYNCSTREAMS
    RwStreamBlockMode   blockMode;
    rwStreamStack       stack;
#endif                    /*RWASYNCSTREAMS*/
    RwBool              rwOwned;
};
#endif /* (!defined(DOXYGEN)) */

#ifdef RWASYNCSTREAMS

/* Stream Completion Callback Function Type*/
typedef void (*RwStreamCallback)(RwStream * stream, RwInt32 ioResult,
                                 void *userData);
#endif /*RWASYNCSTREAMS*/

typedef struct RwMemory RwMemory;
/**
 * \ingroup datatypes
 * \struct RwMemory
 * This type represents a block of allocated memory.
 * It is used to specify an area of memory connected to a stream of type
 * rwSTREAMMEMORY.
 * See \ref rwstream */
struct RwMemory
{
    RwUInt8     *start; /**< starting address */
    RwUInt32    length; /**< length in bytes*/
};

/* RWPUBLICEND */

typedef struct rwStreamGlobals rwStreamGlobals;
struct rwStreamGlobals
{
    RwFreeList         *streamFreeList;
};

/* RWPUBLIC */

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

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

/* Open/Close streams */

extern RwStream *
_rwStreamInitialize(RwStream *stream,
                    RwBool rwOwned,
                    RwStreamType type,
                    RwStreamAccessType accessType,
                    const void *pData);

extern RwStream *
RwStreamOpen(RwStreamType type,
             RwStreamAccessType accessType,
             const void *pData);

extern RwBool       
RwStreamClose(RwStream * stream,
              void *pData);


/* Stream read/write */
extern RwUInt32     
RwStreamRead(RwStream * stream,
             void *buffer,
             RwUInt32 length);

extern RwStream *
RwStreamWrite(RwStream * stream,
              const void *buffer,
              RwUInt32 length);


/* Stream skipping */
extern RwStream *
RwStreamSkip(RwStream * stream,
             RwUInt32 offset);


/* Stream Asynchronous Extensions */
#ifdef RWASYNCSTREAMS
extern RwBool       
RwStreamSetBlockMode(RwStream * stream,
                     RwStreamBlockMode mode);


extern void *
RwStreamAllocCallback(RwStream * stream,
                      RwStreamCallback callback,
                      RwInt16 userdatasize);

extern void         
RwStreamReleaseCallback(RwStream * stream,
                        RwInt32 result);


extern RwBool       
RwStreamSetCallbackBreakPoint(RwStream * stream,
                              RwBool enable);

#endif                    /*RWASYNCSTREAMS*/

/* RWPUBLICEND */

/* Opening and closing stream module */
extern void *
_rwStreamModuleOpen(void *instance,
                    RwInt32 offset,
                    RwInt32 size);

extern void *
_rwStreamModuleClose(void *instance,
                     RwInt32 offset,
                     RwInt32 size);


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

/* RWPUBLICEND */

#endif                          /* RWSTREAM_H */

