//
// Asura_Wii_Streaming_ADPCM.h
//
// Created by KOR - 03 October 2008
//
// Copyright (C) 2008 Rebellion, All Rights Reserved.
//

#ifdef ASURA_USE_PRAGMA_ONCE
#pragma once
#endif

#ifndef __ASURA_WII_STREAMING_ADPCM_H__
#define __ASURA_WII_STREAMING_ADPCM_H__

// Asura
#include "Sound/Asura_Sound.h"

// Lib
//#include <revolution/os.h>
//#include <revolution/ax.h>
#include <revolution/dvd.h>

// Value taken from axstream.c
#define STREAM_CHUNK_BYTES (32 * 1024)
#define STREAM_NUM_CHUNKS (3)
#define STREAM_BUFFER_BYTES (STREAM_CHUNK_BYTES * STREAM_NUM_CHUNKS)
#define STREAM_MAX_BUFFERS (8)
#define STREAM_MAX_CHANNELS (2)

class Asura_Wii_Streaming_ADPCM
{
public:
	enum STREAM_STATE
	{
		STREAM_IDLE = 0,
		STREAM_LOADING_HEADER,
		STREAM_LOADED_HEADER,
		STREAM_PLAYING,
	};
	static void Initialise();

	Asura_Wii_Streaming_ADPCM()
	: m_eStreamState(STREAM_IDLE)
	, m_uFlags(0)
	, m_uCurrentFileOffset(0)
	, m_uRemainingBytes(0)
	, m_uEndChunk(0)
	, m_uCurrentPlayChunk(0)
	, m_uCurrentLoadChunk(0)
	, m_uCurrentLoadChannel(0)
	, m_uBufferOffset(0)
	, m_uCurrentBuffer(0)
	, m_fVolume(1.f)
	{
		for(u_int u = 0; u < STREAM_MAX_CHANNELS; ++u)
		{
			m_apcBuffer[u] = NULL;
			m_apxAXVPB[u] = NULL;
			m_auEndAddress[u] = NULL;
		}
	}

	bool Create(const char* szFilename);
	bool CreateFromResource(const char* szResourceFilename, int iOffset, bool bStereo = false);
	bool CreateFromResource(int iDVDEntryNum, int iOffset, int iSize = -1, bool bStereo = false);
	void Play(bool bLooping);
	void Update();
	void Stop();
	void Release();
	void Pause();
	void Resume();
	void SetVolume(float fVol);
	void UpdateVolume();
	float GetLength() const;
	float GetPosition() const;
	bool IsFinished() const;

#ifndef ASURA_SUBMISSION_BUILD
	void DebugRender() const;
#endif

private:
	void BeginPlay();
	u_int GetCurrentPlayPos(u_int uChannel) const;
	u_int GetBufferFromPosition(u_int uPosition, u_int uChannel) const;
	u_int GetCurrentBuffer() const;
	void CalculateLength();
	bool IsDVDCommandFinished() const;
	void LoadNextChunk(u_int uBufferToLoad);
	void FillAvailableChunks();
	void InitialiseChannel(u_int uChannel);
	void InitialiseVoice(u_int uChannel);
	u_int GetNumChannels() const { return m_bStereo ? 2 : 1; }

	STREAM_STATE m_eStreamState;
	union
	{
		struct  
		{
			u_int m_bLooping:1;
			u_int m_bPaused:1;
			u_int m_bFinished:1;
			u_int m_bEntirelyInMemory:1; // 4
			u_int m_bSetEndAddress:1;
			u_int m_bStereo:1;
		};
		u_int m_uFlags;
	};
	// Per channel information
	char* m_apcBuffer[STREAM_MAX_CHANNELS];
	struct _AXVPB* m_apxAXVPB[STREAM_MAX_CHANNELS];
	u_int m_auEndAddress[STREAM_MAX_CHANNELS];
	// Shared information
	DVDFileInfo m_xFileInfo;
	u_int m_uCurrentFileOffset;
	u_int m_uRemainingBytes;
	u_int m_uEndChunk;
	u_int m_uCurrentPlayChunk;
	u_int m_uCurrentLoadChunk;
	u_int m_uCurrentLoadChannel;
	u_int m_uBufferOffset;
	u_int m_uCurrentBuffer;
	float m_fVolume;
};

#endif//__ASURA_WII_STREAMING_ADPCM_H__