#ifndef UTILITIES_H
#define UTILITIES_H


#include <string>
#include <cstdint>
#include <algorithm>
#include "Macros.h"


enum yqResult
{
	R_Okay,                  // No errors occured
	R_UnknownResult,         // The result was not set, unknown result
	R_Uninitialized,         // Initialization required before calling
	R_UnsupportedVersion,    // The requested version not supported
	R_InvalidParameter,      // The parameter supplied was invalid
	R_IndexOutOfRange,       // The parameter supplied was out of range
	R_FileNotFound,          // The requested file was not found
	R_DeviceFailure,         // The requested device failed
	R_ReadFailure,           // The read request failed
	R_WriteFailure,          // The write request failed
	R_HeapFailure,           // The requested memory was unable to be allocated
	R_CorruptData,           // The data supplied is corrupt
	R_AuthenticationFailure, // The supplied credentials are incorrect
	R_Timeout,               // The requested operation has timed out
	R_Failure                // A generic failure occured
};


enum yqLogLevel
{
	LL_Error,    // Error messages
	LL_Warning,  // Warning messages
	LL_Info,     // Informational messages
	LL_Debug,    // Highest verbosity, programmer related messages
};


enum yqBuildType
{
#ifndef NDEBUG
	BT_IsRelease = 0,   // This enum should enable us to write code
	BT_IsDebug = 1      // which reduces the use of the preprocessor.
#else
	BT_IsDebug = 0,     // Compile time checking will be able to be
	BT_IsRelease = 1    // performed on both sides of the condition.
#endif
};



// Redirects to the installed logger/error/memory handler or a platform default
extern void yqLogMessage(yqLogLevel a_logLevel, const char *a_location, const char* a_func, const char *a_format, ...);
extern void yqHandleError(yqResult a_result, const char *a_location, const char* a_func, const char *a_format, ...);
extern void* yqAllocateMemory(size_t a_size);
extern void* yqReallocateMemory(void* a_ptr, size_t a_newSize);
extern void yqFreeMemory(void* a_ptr);
extern void yqConsolePrintString(const char* a_string);
extern void yqDebugBreak();
// Something related to file opening and redirector



// A user interface can display a localized error message based on the result enum value.
class ErrorHandler
{
public:
	virtual ~ErrorHandler() {}
	virtual void handleError(yqResult a_result, const char *a_location, const char *a_message);
};


// The logger messages are not intened to be localized, they are for diagnostics.
// See ErrorHandler for localized user interface messages.
class Logger
{
public:
	virtual ~Logger() {}
	virtual void logMessage(yqLogLevel a_logLevel, const char *a_location, const char *a_message);
};


// Customizable heap management (memory allocator and deallocator)
class HeapManager
{
public:
	virtual ~HeapManager() {}
	virtual void *malloc(size_t a_size);
	virtual void *realloc(void *a_ptr, size_t a_newSize);
	virtual void free(void *a_ptr);
};


class ResourceDevice
{
public:
	virtual ~ResourceDevice() {}
	virtual yqResult getResourceName(const char ** name);
	virtual yqResult getSize(uint64_t * a_size);
	virtual yqResult read(void * buffer, uint64_t resourceOffset, uint64_t byteReadCount);
	virtual yqResult readAsyncBegin(void * buffer, uint64_t resourceOffset, uint64_t byteReadCount, uintptr_t * readID);
	virtual yqResult readAsyncWait(uintptr_t readID);
	virtual yqResult write(const void * buffer, uint64_t resourceOffset, uint64_t byteWriteCount);
};


class ResourceDeviceFactory
{
public:
	enum WriterFlags
	{
		WF_PreserveExisting = 1 // Preserve existing contents if opening an existing file, else, create a new file
	};
	virtual ~ResourceDeviceFactory() {}
	virtual yqResult CreateResourceDevice(const char * resourceID, uint32_t writerFlags, ResourceDevice **newDevice);
};


class Module
{
public:
	bool                   m_initialized;
    const char*            m_moduleName;
	ErrorHandler*          m_errorHandler;
	Logger*                m_messageLogger;
	HeapManager*           m_heapManager;
	ResourceDeviceFactory* m_deviceFactory;
};


extern Module g_currentModule;


#endif // UTILITIES_H
