///////////////////////////////////////////////////////////////////////////////
/// @file deWAV.cpp
///
/// @brief Destiny Sound System WAV file
///
/// @author paradoxnj
///
/// This file is the intellectual property of Novus Delta, LLC.. Usage of the
/// contents of this file is subject to the Destiny3D Member License which
/// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
///
/// This file is distributed "AS IS" without warranty of any kind.  Novus
/// Delta, LLC. does not guarantee the fitness of the contents of this file
/// for any particular purpose.
///
/// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.
///
/// <hr>
///                                 Change History
/// <hr>
///
/// @date Jan 2002
/// @author paradoxnj
/// @remarks Creation
///
///////////////////////////////////////////////////////////////////////////////

#include <windows.h> // for various stuff
#include "deWAV.hpp"
#include "deSound.hpp"
#include "deFileSystem.hpp"
#include "deFile.hpp"

deWAV::deWAV()
:	deSoundData()
{
	m_InterfaceType = IdeSoundData::iface_WAV;
	m_pSource = NULL;
	m_RefCount = 1;
	m_DataSize = 0;
	m_DataOffset = 0;
}

deWAV::deWAV(const char *filename)
:	deSoundData(filename)
{
	m_InterfaceType = IdeSoundData::iface_WAV;
	m_pSource = NULL;
	m_RefCount = 1;
	m_DataSize = 0;
	m_DataOffset = 0;

	if (!Initialize(filename))
		throw;
}

deWAV::~deWAV()
{
	Destroy();
}

void *deWAV::GetRscInterface(long interface_id)
{
	if (interface_id == IdeSoundData_GetInterfaceID())
		return (IdeSoundData*)this;

	return NULL;
}

#define deMAKEFOURCC(ch0, ch1, ch2, ch3)                            \
	((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) |       \
	((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24 ))
deBoolean deWAV::Initialize(const char *filename)
{
	m_pSourceSystem = IdeFileSystem_CreateFSReal();
	if (!m_pSourceSystem)
		return deFALSE;
	
	m_pSource = m_pSourceSystem->Open((const char*)filename, deFile_Open_Existing | deFile_Open_Read);
	if (!m_pSource)
	{
		DE3D_SAFE_RELEASE(m_pSourceSystem);
		return deFALSE;
	}

	while (1)
	{
		RiffHeader head;
		if (sizeof(RiffHeader) != m_pSource->Read(&head, sizeof(RiffHeader)))
		{
			Destroy();
			return deFALSE;
		}

		switch(head.Tag)
		{
		default:
			m_pSource->SetPosition(head.Size, IdeFile::SEEKF_CURRENT);
			break;
		case deMAKEFOURCC('R','I','F','F'):
			{
				char wavetag[4];
				if (4 != m_pSource->Read(wavetag, 4) || memcmp(wavetag, "WAVE", 4))
				{
					Destroy();
					return deFALSE;
				}
			}
			//m_pSource->SetPosition(head.Size - 4, IdeFile::SEEKF_CURRENT);
			break;
		case deMAKEFOURCC('f','m','t',' '):
			if (sizeof(WaveFormatInfo) != m_pSource->Read(&m_WaveHeader, sizeof(WaveFormatInfo)))
			{
				Destroy();
				return deFALSE;
			}
			m_pSource->SetPosition(head.Size - sizeof(WaveFormatInfo), IdeFile::SEEKF_CURRENT);
			break;
		case deMAKEFOURCC('d','a','t','a'):
			m_DataOffset = m_pSource->GetPosition();
			m_DataSize = head.Size;
			return deTRUE;
			break;
		}
	}
	return deFALSE;
}

void deWAV::Destroy()
{
	if (m_pSource)
		m_pSource->Close();
	DE3D_SAFE_RELEASE(m_pSource);
	DE3D_SAFE_RELEASE(m_pSourceSystem);
}

int deWAV::GetDataChunk(void *ptr, long size, s32 DataOffset)
{
	if (DataOffset >= 0)
		m_pSource->SetPosition(m_DataOffset + DataOffset, IdeFile::SEEKF_START);
	return m_pSource->Read(ptr, size);
}

uint8 *deWAV::GetAllData()
{
	DEBUGRETURN(NULL, "deWAV::GetAllData is a bad function");
	/*
	uint8		*data;

	data = new uint8[m_DataSize];
	if (!data)
		return NULL;

	m_pSource->SetPosition(sizeof(WaveHeader), deFile_Seek_Start);
	m_pSource->Read((void*)data, m_DataSize);

	return data;
	*/
}

void deWAV::GetFormat(WAVEFORMATEX *format)
{
	DE_ASSERT(format != NULL);
	ZeroMemory(format, sizeof(WAVEFORMATEX));

	format->cbSize = 0;
	format->nChannels = m_WaveHeader.Channels;
	format->nSamplesPerSec = m_WaveHeader.SampleRate;
	format->wBitsPerSample = m_WaveHeader.BitsPerSample;
	format->wFormatTag = WAVE_FORMAT_PCM;
	format->nBlockAlign = (unsigned short)(format->wBitsPerSample / 8 * format->nChannels);
	format->nAvgBytesPerSec = format->nSamplesPerSec * format->nBlockAlign;
}

IdeResourceBase *deWAV::MakeCopy()
{
	return (IdeResourceBase*)new deWAV((char*)GetFilename());
}

deBoolean deWAV::AtEndOfStream()
{
	if (m_pSource->GetPosition() >= m_pSource->GetSize())
		return deTRUE;
	else
		return deFALSE;
}

void deWAV::SetPosition(long NewPos)
{
	m_pSource->SetPosition(m_DataOffset + NewPos, IdeFile::SEEKF_START);
}