#ifndef RT_AIO_H
#define RT_AIO_H

#include <stdint.h>

#include "file_tab.h"
#include "runtime.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
    size_t offset;    /**< Starting offset inside the file in bytes */
    size_t num_bytes; /**< Number of bytes to load */
    /** Destination buffer with at least @ num_bytes bytes.
     *  Must be valid until the load is finished.
     */
    void *dest;
    rt_file_id file; /**< Unique identifier for the file */
} rt_file_load;

#define RT_LOAD_BATCH_MAX_SIZE 64

/** A batch of loads that will be started together.
 *
 * The aio system will hand these to the OS.
 */
typedef struct {
    rt_file_load loads[RT_LOAD_BATCH_MAX_SIZE];

    /** Must be smaller or equal to @c RT_LOAD_BATCH_MAX_SIZE */
    unsigned int num_loads;
} rt_load_batch;

typedef struct {
    size_t num_bytes; /** Number of bytes to write */
    size_t offset;    /** Offset at which to start writing */
    /* Source buffer with at least num_bytes bytes.
     * Must be valid until the write is finished.
     */
    const void *buffer;
    rt_file_id file;
} rt_file_write;

#define RT_WRITE_OFFSET_APPEND ((size_t)-1)

#define RT_WRITE_BATCH_MAX_SIZE 64

/* A batch of writes that will be started together.
 * The aio system will hand these to the OS. */
typedef struct {
    rt_file_write writes[RT_WRITE_BATCH_MAX_SIZE];
    unsigned int num_writes;
} rt_write_batch;

#define RT_AIO_INVALID_HANDLE 0

/** Handle for an async io operation. Can be used to query the state and result. */
typedef uint32_t rt_aio_handle;

enum {
    RT_AIO_LOAD_TOO_LARGE = RT_CUSTOM_ERROR_START,
    RT_AIO_WRITE_TOO_LARGE,
    RT_AIO_TOO_MANY_OPERATIONS,
    RT_AIO_OUT_OF_MEMORY,
};

typedef enum {
    RT_AIO_STATE_INVALID,
    RT_AIO_STATE_PENDING,
    RT_AIO_STATE_FINISHED,
    RT_AIO_STATE_FAILED,
} rt_aio_state;

RT_DLLEXPORT rt_aio_state rtGetAIOState(rt_aio_handle handle);

/* Blocks until the given operation is no longer pending.
 * Returns the state that caused the wait to end. The handle is still valid after this function
 * returned. */
RT_DLLEXPORT rt_aio_state rtWaitForAIOCompletion(rt_aio_handle handle);

RT_DLLEXPORT rt_result rtSubmitLoadBatch(const rt_load_batch *batch, rt_aio_handle *handles);

/* Releases the internal storage for the operation.
 * The system is allowed to re-use the same handle value for new operations after this was called.
 */
RT_DLLEXPORT void rtReleaseAIO(rt_aio_handle handle);

RT_DLLEXPORT rt_result rtSubmitSingleLoad(rt_file_load load, rt_aio_handle *handle);

/* Convenience wrapper for a single synchronous file load.
 * Returns the state that caused the wait for completion to return. */
RT_DLLEXPORT rt_aio_state rtSubmitSingleLoadSync(rt_file_load load);

RT_DLLEXPORT rt_result rtSubmitWriteBatch(const rt_write_batch *batch, rt_aio_handle *handles);

#ifdef __cplusplus
}
#endif

#endif
