#ifndef __Media__H
#define __Media__H

#include "std.h"
#include <stdint.h>
#include "kernel.h"
#include <stdbool.h>
#include "MediaLst.h"
#include "MetaData.h"

typedef enum
{ Media_CfgVolume
, Media_CfgFrequency
, Media_CfgInterpol
, Media_CfgBalance
, Media_CfgStereoSeparation
, Media_CfgVolumeRamping
, Media_CfgEqualizer
, Media_CfgHardwareType
, Media_CfgVolumeScale
, Media_CfgDMASize
, Media_CfgParams
} Media_Config;

typedef enum
{ status_undef
, status_empty
, status_stop
, status_pause
, status_play
, status_busy
, status_error
} Media_Status;

typedef enum
{ loop_volume_play
, loop_volume_loop
, loop_section_loop
, loop_section_play
} Media_LoopMode;

typedef enum
{ Media_HType_File     = 0
, Media_HType_External = 1
, Media_HType_Midi     = 2
, Media_HType_CD0      = 3/* 1, 2, ... */
} Media_HType;

#define Media_Updated_Length 0x01
#define Media_Updated_Type   0x02
#define Media_Updated_Title  0x04
#define Media_Updated_Meta   0x08
#define Media_Updated_All    0x0F
#define Media_New_Song       0x10

typedef enum
{ EMedia_Seek_Start
, EMedia_Seek_SectionStart
, EMedia_Seek_PreviousSection
, EMedia_Seek_NextSection
, EMedia_Seek_PreviousPos
, EMedia_Seek_NextPos
} EMedia_Seek;

extern const _kernel_oserror Media_ErrorModuleInUse;
struct MediaDriver;
typedef struct MediaDriver MediaDriver;

typedef struct MediaPosition
{
	// Media internal units
	struct
	{
		uint64_t     start;
		uint64_t     pos;
		uint64_t     end;
	} driver;
	// Media global timing in ms
	struct
	{
		unsigned int pos;
		unsigned int len;
		unsigned int sections;
	} volume;
	// Media section timing in ms
	struct
	{
		unsigned int pos;
		unsigned int len;
		unsigned int nr;
	} section;
} MediaPosition;

typedef struct
{
	unsigned int raw;
	unsigned int sysscaled;
} MediaVolume;

typedef struct MediaObject
{
	const struct MediaDriver*  m_pDriver;
	const char*                m_pFile;
	unsigned int               m_Params;
	void*                      m_pData;
	Media_Status               m_Status;
	Media_LoopMode             m_LoopMode;
	Media_HType                m_HardwareType;
	uint64_t                   m_iCurrentPos;
	unsigned int               m_iSpeed;
	unsigned int               m_Updates;
	MetaList*                  m_metas;
	unsigned int               m_timestamp;
	unsigned int               m_readtimestamp;
	bool                       m_bSeekable;
	_kernel_oserror            m_Err;
} MediaObject;

void MediaObject_SetTimestamp(MediaObject* pobj, unsigned int stamp);
int MediaObject_CountMeta(MediaObject* pobj);
const MetaData* MediaObject_FindMeta(MediaObject* pobj, EMetaId id);
const MetaData* MediaObject_GetMeta(MediaObject* pobj, int index);
bool throw_MediaObject_MergeMeta(MediaObject* pobj, const MetaList* pOld);
bool throw_MediaObject_SetMeta
	( MediaObject* pobj
	, EMetaId id
	, EMetaOrigin origin
	, const void* data
	, unsigned int size
	);
bool throw_MediaObject_SetText
	( MediaObject* pobj
	, EMetaId id
	, EMetaOrigin origin
	, const char* data
	);

typedef struct Media
{
	MediaDriverList* m_pDrivers;
	MediaObjectList* m_pObjects;
} Media;

void throw_Media_Media(void);
void Media_NotMedia(void);

void throw_Media_RegisterDriver(const MediaDriver* pDriver);
void Media_UnregisterDriver(const MediaDriver* pDriver);

const _kernel_oserror* Media_LoadObject(MediaObject** ppobj, const char* pObjectName, unsigned int Params, const MediaDriver* pDriver);
void Media_UnLoadObject(MediaObject*);
void Media_Chain(MediaObject*, MediaObject*);
void Media_Attach(MediaObject*, void*, Media_HType);

void Media_Play(MediaObject*, uint64_t pos);
void Media_Freeze(MediaObject*, bool on);
void Media_Stop(MediaObject*);

void Media_Seek(MediaObject*, EMedia_Seek set);
void Media_SetSeekable(MediaObject*, bool);
bool Media_GetSeekable(MediaObject*);

void Media_SetLoopMode(MediaObject*, Media_LoopMode mode);
Media_LoopMode Media_GetLoopMode(MediaObject*);

Media_Status Media_GetStatus(MediaObject*);
unsigned int Media_GetUpdates(MediaObject*);
void Media_GetPosition(MediaObject*, MediaPosition*);
uint64_t Media_GetSectionPos(MediaObject* pobj, unsigned int section);

void Media_SetConfig(MediaObject*, Media_Config type, const void* value);
unsigned int Media_GetConfig(MediaObject*, Media_Config type);

#endif
