#include "SND\snddef.H"

#include "SNDinc.h"
#include "SND.h"

#include <io.h>
#include <fcntl.h>
#include "sndlst2.h"


typedef struct SOUNDDATA_DIRECTORY_ {
        char szDirectory[256];
} SOUNDDATA_DIRECTORY;
#define NB_DIRECTORY_MAX 16
static SOUNDDATA_DIRECTORY g_SoundDataDirectoryTab[NB_DIRECTORY_MAX];
static int g_NbSoundDataDirectory=0;

static char g_SoundSoftDirectory[256]=".";

//---------------------------------------------------------------
//	SetSoftDirectory:mémorise une chaine décrivant le repértoire des DLL
//	Entrée:czDir=chaine à mémoriser
//	Sortie:néant
//---------------------------------------------------------------
void SND_CALL SND_fn_vSetSoftDirectory(char* czDir)
{
	strcpy(g_SoundSoftDirectory,czDir);
}

//---------------------------------------------------------------
//	SetDataDirectory:mémorise une chaine décrivant le repértoire des données sons
//	Entrée:czDir=chaine à mémoriser
//	Sortie:néant
//---------------------------------------------------------------
char* SND_CALL SND_fn_szGetSoftDirectory(void)
{
	return g_SoundSoftDirectory;
}


//---------------------------------------------------------------
//	SetDataDirectory:mémorise une chaine décrivant le repértoire des données sons
//	Entrée:czDir=chaine à mémoriser
//	Sortie:néant
//---------------------------------------------------------------
void SND_CALL SND_fn_vAddDataDirectory(const char* czDir)
{
#ifndef NO_ACP_SOUND
	/* version 1:liste dynamic
    pSOUNDDATA_DIRECTORY pDir;
        
    pDir=SND_fn_pvMallocSnd(sizeof(SOUNDDATA_DIRECTORY));
    strcpy(pDir->szDirectory,czDir);
    SNDLST2_M_DynamicInitElement(pDir);

    if (!g_bSoundDataDirectoryListInitialized)
    {
        g_bSoundDataDirectoryListInitialized=TRUE;
        SNDLST2_M_DynamicInitAnchor(&g_SoundDataDirectoryList.pList);
    }
    SNDLST2_M_DynamicAddTail(&g_SoundDataDirectoryList.pList,pDir);
	*/
	/* version 2:tableau dynamic
	if (g_NbSoundDataDirectory)
	{
		g_SoundDataDirectoryList=(SOUNDDATA_DIRECTORY*)SND_fn_pvReAllocSnd(g_SoundDataDirectoryList,sizeof(SOUNDDATA_DIRECTORY)*(g_NbSoundDataDirectory+1));
	}
	else
	{
		g_SoundDataDirectoryList=(SOUNDDATA_DIRECTORY*)SND_fn_pvMallocSnd(sizeof(SOUNDDATA_DIRECTORY)*1);
	}

	strcpy(g_SoundDataDirectoryList[g_NbSoundDataDirectory].szDirectory,czDir);
	*/
	if (!SND_fn_bIsDataDirectory(czDir))
	{
		if (g_NbSoundDataDirectory<NB_DIRECTORY_MAX)
		{
			strcpy(g_SoundDataDirectoryTab[g_NbSoundDataDirectory].szDirectory,czDir);

			g_NbSoundDataDirectory++;
		}
		else
			SND_fn_vDisplayError(E_uwSndMemoryAllocError,"Too many SoundData directories");
	}
#endif
}

void SND_CALL SND_fn_vRemoveDataDirectory(const char* czDir)
{
	int i;

	for (i=0;i<g_NbSoundDataDirectory;i++)
	{
		if (!stricmp(g_SoundDataDirectoryTab[i].szDirectory,czDir))
			break;
	}

	if (i!=g_NbSoundDataDirectory)
	{
		if (g_NbSoundDataDirectory)
		{
			g_NbSoundDataDirectory--;
			memcpy(&g_SoundDataDirectoryTab[i],&g_SoundDataDirectoryTab[g_NbSoundDataDirectory],sizeof(SOUNDDATA_DIRECTORY));
			//g_SoundDataDirectoryList=SND_fn_pvReAllocSnd(g_SoundDataDirectoryList,sizeof(SOUNDDATA_DIRECTORY)*g_NbSoundDataDirectory);
		}
	}
}

void SND_CALL SND_fn_vPurgeDataDirectory()
{
	/*
	if (g_NbSoundDataDirectory)
		SND_fn_vFreeSnd(g_SoundDataDirectoryList);
		*/
	g_NbSoundDataDirectory=0;
}

//---------------------------------------------------------------
//	GetOneDataDirectory:copie dans une chaine le n° repértoire des données sons memorisé plus tôt
//	Entrée:n=indice du répertoire
//      czDir=chaine à mémoriser
//		iMaxChar=taille de czDir
//	Sortie:FALSE si n invalide; TRUE si OK
//---------------------------------------------------------------
SndBool SND_CALL SND_fn_bGetOneDataDirectory(int id,char* czDir,int iMaxChar)
{
	/*
    pSOUNDDATA_DIRECTORY pDir;
    int i;

    SNDLST2_M_DynamicGetElementNumber(&g_SoundDataDirectoryList.pList,pDir,id,i);
    if (pDir!=NULL)
    {
	    strncpy(czDir,pDir->szDirectory,iMaxChar);
        return TRUE;
    }
    else
        return FALSE;
		*/
	if (id<g_NbSoundDataDirectory)
    {
	    strncpy(czDir,g_SoundDataDirectoryTab[id].szDirectory,iMaxChar);
        return TRUE;
    }
    else
        return FALSE;

}

//---------------------------------------------------------------
//	GetNumberOfDataDirectory:donne le nb de directiry de la liste
//	Entrée:néant
//	Sortie:nb d'élément
//---------------------------------------------------------------
int SND_CALL SND_fn_iGetNumberOfDataDirectory(void)
{
    /*return SNDLST2_M_DynamicGetNumberOfElements(&g_SoundDataDirectoryList.pList);*/
	return g_NbSoundDataDirectory;
}

//---------------------------------------------------------------
//	GetIdDataDirectory:retourne l'id d'un répertoire dans la liste (si il y est)
//	Entrée:répertoire
//	Sortie:id du repértoire dans la liste (-1 si non présent dans la liste)
//---------------------------------------------------------------
int SND_CALL SND_fn_iGetIdDataDirectory(const char* szDir)
{
	/*
    pSOUNDDATA_DIRECTORY pDir;
    int i;

    SNDLST2_M_DynamicForEachElementOf(&g_SoundDataDirectoryList.pList,pDir,i)
    {
        if (!_stricmp(pDir->szDirectory,szDir))
            return i;
    }
    return -1;
	*/
	int i;

	for (i=0;i<g_NbSoundDataDirectory;i++)
	{
        if (!_stricmp(g_SoundDataDirectoryTab[i].szDirectory,szDir))
            return i;
	}
    return -1;
}

//---------------------------------------------------------------
//	IsDataDirectory:indique si un répertoire fait partie de la liste
//	Entrée:répertoire
//	Sortie:TRUE si répertoire présent dans la liste, FALSE sinon
//---------------------------------------------------------------
SndBool SND_CALL SND_fn_bIsDataDirectory(const char* szDir)
{
    if (SND_fn_iGetIdDataDirectory(szDir)!=-1)
        return TRUE;
    else
        return FALSE;
}

//---------------------------------------------------------------
//	Resolve FileName:convertit un nom relatif en nom absolu en cherchant dans la liste
//	Entrée:RelativeName=nom court
//	Sortie:Absolute=nom complet (avec chemin résolu)
//---------------------------------------------------------------
void SND_CALL SND_fn_vResolveFileName(char* RelativeName,char* AbsoluteName)
{
#ifndef NO_ACP_SOUND
    int i;
    char name[256];
    tdhSndFile hFile;
	char texte[256];
/*
    pSOUNDDATA_DIRECTORY pDir;

    SNDLST2_M_DynamicForEachElementOf(&g_SoundDataDirectoryList.pList,pDir,i)
    {
        strcpy(name,pDir->szDirectory);
        strcat(name,RelativeName);
        if ((hFile=SND_fn_hOpenFileReadSnd(name))!=OPENFILESND_FAILED)
        {
            SND_fn_vCloseFileSnd(hFile);
            strcpy(AbsoluteName,name);
            return;
        }
    }
*/
	for (i=0;i<g_NbSoundDataDirectory;i++)
	{
        strcpy(name,g_SoundDataDirectoryTab[i].szDirectory);
        strcat(name,RelativeName);
        if ((hFile=SND_fn_hOpenFileReadSnd(name))!=OPENFILESND_FAILED)
        {
            SND_fn_vCloseFileSnd(hFile);
            strncpy(AbsoluteName,name,256);
            return;
        }
	}

	sprintf(texte,"File %s cannot be found in any DataDirectory",RelativeName);
    SND_fn_vDisplayError(E_uwSndCannotOpenFile,texte);

    strncpy(AbsoluteName,RelativeName,256);
#endif
}


//----------- Fonctions privées
//---------------------------------------------------------------
//	SetCurrentDirectory:modifie le répertoire courant
//	Entrée:czDir=nouveau repértoire
//	Sortie:TRUE si OK
//---------------------------------------------------------------
SndBool SND_CALL SND_fn_bSetCurrentDirectory(char* czDir)
{
	return SetCurrentDirectory(czDir);
}

//---------------------------------------------------------------
//	SetDataDirectory:mémorise une chaine décrivant le repértoire des données sons
//	Entrée:czDir=chaine à mémoriser
//	Sortie:néant
//---------------------------------------------------------------
SndBool SND_CALL SND_fn_bGetCurrentDirectory(char* czDir,int iMaxChar)
{
	return GetCurrentDirectory(iMaxChar,czDir);
}


//----------------------------------------------------------------------
//	LoadDataInMemAndSwap;charge n octets d'une fichier
//	Entrées:
//		adr = cible de données à charger
//		nb_bytes = nb d'octets à charger
//		name = nom absolu du fichier (ou dans répertoire courant)
//		offset = offset des données dans le fichier
//		swap = TRUE s'il faut byte swappé chaque WORD
//	Sortie : True, False suivant la reussite ou non 
//---------------------------------------------------------------------
SndBool SND_CALL SND_fn_bLoadDataInMemAndSwap(void* adr,unsigned long ulNbBytes,char* czFileName,unsigned long ulOffset,SndBool bSwap)
{
	tdhSndFile hSndFile;
	unsigned long ulNbReadBytes = 0;
	WORD *pWord;
	char Char;
	int i;
	

	if ((hSndFile = SND_fn_hOpenFileReadSnd(czFileName))!=OPENFILESND_FAILED) 
	{
		SND_fn_dwSeekFileSnd(hSndFile,ulOffset,FILE_BEGIN);
		ulNbReadBytes = SND_fn_dwReadFileSnd(hSndFile,ulNbBytes,adr);
		SND_fn_vCloseFileSnd(hSndFile);
	}
	else
	{
		return FALSE;
	}

	//--byte swap
	if (bSwap)
	{
		for (pWord=adr,i=ulNbBytes/2;i>0;pWord++,i--)
		{
			Char=*(char*)pWord;
			*(char*)pWord=*((char*)pWord+1);
			*((char*)pWord+1)=Char;
		}
	}

	if (ulNbReadBytes != ulNbBytes)
		return FALSE;
	else
		return TRUE;
}

SndBool SND_CALL SND_fn_bLoadDataInMem(void* adr,unsigned long ulNbBytes,char* czFileName,unsigned long ulOffset)
{
	return SND_fn_bLoadDataInMemAndSwap(adr,ulNbBytes,czFileName,ulOffset,FALSE);
}


#ifdef FILE_MODE_C_STANDARD


unsigned long SND_fn_dwFileSndLength(tdhSndFile	hSndFile)
{
	return (_filelength(hSndFile));
}

tdhSndFile SND_fn_hOpenFileReadSnd(char * czFileName) 
{
	//tdhSndFile h = 0;
	
	return (_open(czFileName,_O_RDONLY))
	/*
	if (h = _open(czFileName,dwOpenMode) == -1)
		return (OPENFILESND_FAILED);
	else
		return h;
	*/
}

unsigned long SND_fn_dwReadFileSnd(tdhSndFile hSndFile,unsigned long dwNbBytes,void * ptr)
{
	return (_read(hSndFile,ptr,dwNbBytes));
}

unsigned long SND_fn_dwWriteFileSnd(tdhSndFile hSndFile,unsigned long dwNbBytes,void * ptr)
{
	return (_write(hSndFile,ptr,dwNbBytes));
}

unsigned long SND_fn_dwSeekFileSnd(tdhSndFile hSndFile,unsigned long dwOffset,unsigned long dwOrigin)
{
	return (_lseek(hSndFile,dwOffset,dwOrigin));
}

void SND_fn_vCloseFileSnd(tdhSndFile hSndFile) 
{
	_close(hSndFile);
}

#endif

#ifdef FILE_MODE_C_WIN95

unsigned long SND_CALL SND_fn_dwFileSndLength(tdhSndFile	hSndFile)
{
	return ((unsigned long)GetFileSize(hSndFile,NULL));
}

//-----------------------------------------------------------------------------
//	Ouvre un fichier
//	Entrées:csFileName=nom du fichier
//		dwOpenMode=OPENFILESND_READ	ou OPENFILESND_WRITE	
//	Retour:handle sur un fichier (OPENFILESND_FAILED si échec)
//-----------------------------------------------------------------------------
tdhSndFile SND_CALL SND_fn_hOpenFileReadSnd(char * czFilename) 
{
	tdhSndFile h;
	LPVOID lpMsgBuf;
	char texte[256],texte2[80];
	DWORD err;

	h = CreateFile(
			(LPCTSTR)czFilename,	// pointer to name of the file 
			GENERIC_READ,				// access (read-write) mode 
			FILE_SHARE_READ,								// share mode 
			NULL,							// pointer to security descriptor 
			OPEN_EXISTING,		// how to create 
			0,//FILE_ATTRIBUTE_ARCHIVE,	// file attributes 
			NULL); 						// handle to file with attributes to copy  

	if (h==INVALID_HANDLE_VALUE)
	{
		GetCurrentDirectory(sizeof(texte2),texte2);
		err=GetLastError();

		if (err!=ERROR_FILE_NOT_FOUND)
		{//strange message
			FormatMessage( 
				FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
				NULL,
				err,
				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
				(LPTSTR) &lpMsgBuf,
				0,
				NULL 
			);

			// Display the string.
			strcpy(texte,czFilename);strcat(texte," -> ");strncat(texte,lpMsgBuf,sizeof(texte)-strlen(texte)-1);
			//no more error: caller must display in own warning
			//SND_fn_vDisplayError(E_uwSndCannotOpenFile,texte);

			// Free the buffer.
			LocalFree( lpMsgBuf );
		}
	}

	return h;
}



unsigned long SND_CALL SND_fn_dwReadFileSnd(tdhSndFile hSndFile,unsigned long dwNbBytes,void * ptr)
{
	SndBool bResult;
	DWORD dwNbBytesRead = 0,err;
	
	bResult = ReadFile(
    hSndFile,	// handle of file to read 
    ptr,	// address of buffer that receives data  
    dwNbBytes,	// number of bytes to read 
    &dwNbBytesRead,	// address of number of bytes read 
    NULL);	// address of structure for data 

	if (!bResult)
		err=GetLastError();
 	
	return (dwNbBytesRead);
}

unsigned long SND_CALL SND_fn_dwWriteFileSnd(tdhSndFile hSndFile,unsigned long dwNbBytes,void * ptr)
{
	SndBool bResult;
	DWORD dwNbBytesWritten = 0;
	
	bResult = WriteFile(
    hSndFile,	// handle of file to read 
    ptr,	// address of buffer that receives data  
    dwNbBytes,	// number of bytes to read 
    &dwNbBytesWritten,	// address of number of bytes read 
    NULL);	// address of structure for data 
 	
	return  (dwNbBytesWritten);
}

unsigned long SND_CALL SND_fn_dwSeekFileSnd(tdhSndFile hSndFile,unsigned long dwOffset,unsigned long dwOrigin)
{
	return (SetFilePointer(hSndFile, dwOffset, NULL, dwOrigin));
}

void SND_CALL SND_fn_vCloseFileSnd(tdhSndFile hSndFile) 
{
	CloseHandle(hSndFile);
}
#endif

