/*
//////////////////////////////////////////////////////////////
//      SNDERR.CXX - SOUNDxD Version 2.0                                                        
//////////////////////////////////////////////////////////////
//      Error managing functions.
/////////////////////////////////////////////////////////////
*/
#include <stdio.h>

#include "SND\snddef.h" 

#include "SND/snderr.h"

#define __DeclareGlobalVariableErrSnd_h__
#include "SNDext/errsnd.h"

//établir le niveau maxi des Warnings
#ifdef DEBUG_SON
#define SNDERR_MAX_DISPLAYED_ERROR E_uwSndErrNumber
#else
#define SNDERR_MAX_DISPLAYED_ERROR E_uwSndEndOfWarningLevel2
#endif

//#include "sndmusct.h"
#include "sndwin95.h"
#include "sndthrd.h"

#ifndef SNDERR_USE_ACP
#define NB_ERROR_MAX 5
int g_iNbError=0;
struct {
        unsigned long ulChannel;
        unsigned short uwErr;
} astErrDescriptor[NB_ERROR_MAX];
#endif

typedef struct _tdstSndErrorOccurElement
{
	SndBool bOccured;
	SndBool bDontDisplay;
	SndBool bDONTAskToBeDisplayed;
} tdstSndErrorOccurElement;
tdstSndErrorOccurElement SND_g_astErrorOccurArray[E_uwSndErrNumber];

HWND SNDERR_g_hwndMainWnd=NULL;

#ifdef DEBUG_SON
void liste_of_association(char *texte,long size);
void liste_of_voices(char* texte,long size);

//returns TRUE if errors yet occured in the past
SndBool fn_bHasErrorOccured(unsigned short uwErrNum)
{
	snd_assert(uwErrNum>0);snd_assert(uwErrNum<E_uwSndErrNumber);

	return SND_g_astErrorOccurArray[uwErrNum].bOccured;
}

void fn_vSetErrorOccured(unsigned short uwErrNum)
{
	snd_assert(uwErrNum>0);snd_assert(uwErrNum<E_uwSndErrNumber);

	SND_g_astErrorOccurArray[uwErrNum].bOccured=TRUE;
}

SndBool fn_bErrorToBeDisplayed(unsigned short uwErrNum)
{
	snd_assert(uwErrNum>0);snd_assert(uwErrNum<E_uwSndErrNumber);

	return !SND_g_astErrorOccurArray[uwErrNum].bDontDisplay;
}

void fn_vSetErrorToNOTBeDisplayed(unsigned short uwErrNum)
{
	snd_assert(uwErrNum>0);snd_assert(uwErrNum<E_uwSndErrNumber);

	SND_g_astErrorOccurArray[uwErrNum].bDontDisplay=TRUE;
}

SndBool fn_bErrorDONTAskToBeDisplayed(unsigned short uwErrNum)
{
	snd_assert(uwErrNum>0);snd_assert(uwErrNum<E_uwSndErrNumber);

	return SND_g_astErrorOccurArray[uwErrNum].bDONTAskToBeDisplayed;
}

void fn_vSetErrorDONTAskToBeDisplayed(unsigned short uwErrNum)
{
	snd_assert(uwErrNum>0);snd_assert(uwErrNum<E_uwSndErrNumber);

	SND_g_astErrorOccurArray[uwErrNum].bDONTAskToBeDisplayed=TRUE;
}

//--------------------------------------------------------------
//	Rapport complet pour déboguage
//--------------------------------------------------------------
/*
void SND_fn_vDebuggingReport()
{
	char blabla[256]="";
	char lst_evt[10000]="";
	char lst_rsv[10000]="";
	char file_name[256]="";
	WIN32_FIND_DATA FindFileData;
	HANDLE handle;
	BOOL idOK;
	int id;
	SYSTEMTIME time;
	DWORD nb;

	//liste des events
	liste_of_association(lst_evt,sizeof(lst_evt));
	//liste des ressources
	liste_of_voices(lst_rsv,sizeof(lst_rsv));

	//recherche du nom de fichier dispo
	id=0;idOK=FALSE;
	while (!idOK && (id<1000))
	{
		sprintf(file_name,"SNDdbg%d.txt",id);
		memset(&FindFileData,0,sizeof(FindFileData));
		if ((handle=FindFirstFile(file_name,&FindFileData))==INVALID_HANDLE_VALUE)
			idOK=TRUE;
		else
		{
			id++;
			FindClose(handle);
		}
	}
	if (!idOK) id=0;

	//création du fichier de report
	handle=CreateFile(file_name,GENERIC_WRITE,0,NULL,CREATE_NEW,0,NULL);
	GetLocalTime(&time);
	sprintf(blabla,"Report file created %d:%d:%d on %d %d %d\n\n",time.wHour,time.wMinute,time.wSecond
		,time.wDay,time.wMonth,time.wYear);
	WriteFile(handle,blabla,strlen(blabla),&nb,NULL);
	sprintf(blabla,"\nEVENTS LIST***************************\n");
	WriteFile(handle,blabla,strlen(blabla),&nb,NULL);
	WriteFile(handle,lst_evt,strlen(lst_evt),&nb,NULL);
	sprintf(blabla,"\nVOICES LIST***************************\n");
	WriteFile(handle,blabla,strlen(blabla),&nb,NULL);
	WriteFile(handle,lst_rsv,strlen(lst_rsv),&nb,NULL);
	sprintf(blabla,"\nEND***************************\n");
	WriteFile(handle,blabla,strlen(blabla),&nb,NULL);
	CloseHandle(handle);
}*/
#else
/*
void SND_fn_vDebuggingReport()
{
}
*/
#endif


//--------------------------------------------------------------
//      DisplayError : display an error message
//      Entrée: id de l'erreur
//      Sortie: néant
//--------------------------------------------------------------
void SND_CALL SND_fn_vDisplayError(unsigned short uwErrNum,char *message)
{
	/*
	char texte[256];

	sprintf(texte,"%d : %s",uwErrNum,message);
	MessageBox(SNDERR_g_hwndMainWnd,texte,"Erreur SND hyper-importante !!!",MB_OK);
	*/
	SND_fn_vEnterCriticalSectionForErrorDisplay();

    SND_M_UpdateLastError((unsigned long)GetCurrentThreadId(),uwErrNum, C_lErmNoDebugData,C_ucErmOpenInfoWindow,C_ucAllowStopForDebug,message);
    SND_M_CheckError((unsigned long)GetCurrentThreadId());
    SND_M_ClearLastError((unsigned long)GetCurrentThreadId());

	SND_fn_vQuitCriticalSectionForErrorDisplay();
}

void SND_CALL SND_fn_vDisplayErrorEx(unsigned short uwErrNum,char *message,int flags)
{
#ifdef DEBUG_SON
	int ret;

	SND_fn_vEnterCriticalSectionForErrorDisplay();

	if ((flags==SNDERR_DISPLAY_ALLWAYS)
		|| ((flags==SNDERR_DISPLAY_ONLY_ONCE) && !fn_bHasErrorOccured(uwErrNum))
		|| ((flags==SNDERR_DISPLAY_IF_WANTED) && fn_bErrorToBeDisplayed(uwErrNum)))
	{
		SND_M_UpdateLastError((unsigned long)GetCurrentThreadId(),uwErrNum, C_lErmNoDebugData,C_ucErmOpenInfoWindow,C_ucAllowStopForDebug,message);
		SND_M_CheckError((unsigned long)GetCurrentThreadId());
		fn_vSetErrorOccured(uwErrNum);
	}
	else
	{
		SND_M_UpdateLastError((unsigned long)GetCurrentThreadId(),uwErrNum, C_lErmNoDebugData,0,0,message);
		SND_M_CheckError((unsigned long)GetCurrentThreadId());
	}

	//"May error be displayed next time?"
	if ((flags==SNDERR_DISPLAY_IF_WANTED) && fn_bErrorToBeDisplayed(uwErrNum) && !fn_bErrorDONTAskToBeDisplayed(uwErrNum))
	{
		ret=Erm_fn_iMessageBox(
			"Do you want this error to be displayed next time ?\nCancel=don't ask this question any more"
			,"This error may occur many time from now !"
			,MB_YESNOCANCEL);
		if (ret==IDNO)
			fn_vSetErrorToNOTBeDisplayed(uwErrNum);
		else
			if (ret==IDCANCEL)
				fn_vSetErrorDONTAskToBeDisplayed(uwErrNum);
	}

    SND_M_ClearLastError((unsigned long)GetCurrentThreadId());

	SND_fn_vQuitCriticalSectionForErrorDisplay();
#else
	SND_fn_vDisplayError(uwErrNum,message);
#endif
}

#ifdef SNDERR_USE_ACP
void SND_CALL SND_fn_vInitErrorSnd(SND_tdstInitStruct *pInitStruct)
{
	SNDERR_g_hwndMainWnd=pInitStruct->hMainWindow;

	Erm_M_InitErrMsg(Snd);
	memset(&SND_g_astErrorOccurArray,0,sizeof(SND_g_astErrorOccurArray));
}

void SND_CALL SND_fn_vDesInitErrorSnd(void)
{
}

void SND_fn_vUpdateLastError(unsigned long ulChannelId,
							 unsigned short uwErrNum,
							 long lDebugData,
							 unsigned char ucOpenInfoWindow,
							 unsigned char ucStopForDebug,
                             char* message)
{
	if (uwErrNum>SNDERR_MAX_DISPLAYED_ERROR)															
	{
		Erm_M_UpdateLastError(Snd, ulChannelId, uwErrNum, lDebugData, 0, 0,message);					
	}
	else																								
	{
		Erm_M_UpdateLastError(Snd, ulChannelId, uwErrNum, lDebugData, ucOpenInfoWindow, ucStopForDebug,message);
	}
}
#else // SNDERR_USE_ACP

//non using ERM module
void SND_CALL SND_fn_vInitErrorSnd(SND_tdstInitStruct *pInitStruct)
{
		SNDERR_g_hwndMainWnd=pInitStruct->hMainWindow;
}

void SND_CALL SND_fn_vDesInitErrorSnd(void)
{
}

//--------------------------------------------------------------
//      UpdateLastError : display and save an error message
//      Entrée:ulChannelId=channel of error occurence (up to NB_ERROR_MAX)
//              uwErrNum=error id
//              lDebugData,ucOpenInfoWindow,ucStopForDebug=not used
//      Sortie: néant
//--------------------------------------------------------------
void SND_fn_vUpdateLastError(unsigned long ulChannelId,
                                                         unsigned short uwErrNum,
                                                         long lDebugData,
                                                         unsigned char ucOpenInfoWindow,
                                                         unsigned char ucStopForDebug,
                             char* message)
{
        int i;
        char texte[128];

        i=0;
        while ((g_a_stSndTabErr[i].uwErrorId!=uwErrNum) && (g_a_stSndTabErr[i].uwErrorId!=0xFFFF))
                i++;

        //--affichage
        if (g_a_stSndTabErr[i].uwErrorId==0xFFFF)
                sprintf(texte,"Unknown error #%d",uwErrNum);
        else
                sprintf(texte,"%s",g_a_stSndTabErr[i].szErrorText);
        if (message!=NULL) strncat(texte,message,sizeof(texte)-strlen(texte)-1);

        MessageBox(SNDERR_g_hwndMainWnd,texte,"Sound Error",MB_OK|MB_TOPMOST);

        //---stockage de l'erreur
        i=0;
        while ((i<g_iNbError) && (astErrDescriptor[i].ulChannel!=ulChannelId)) i++;
        if (i<g_iNbError)
        {
                sprintf(texte,"Channel %d is still busy !!",i);
                MessageBox(SNDERR_g_hwndMainWnd,texte,"Sound Error anomaly",MB_OK|MB_TOPMOST);
        }
        else
        {
                if (g_iNbError<NB_ERROR_MAX)
                {
                        astErrDescriptor[g_iNbError].ulChannel=ulChannelId;
                        astErrDescriptor[g_iNbError++].uwErr=uwErrNum;
                }
                else
                {
                        strcpy(texte,"Too many channel busy !!");
                        MessageBox(SNDERR_g_hwndMainWnd,texte,"Sound Error anomaly",MB_OK|MB_TOPMOST);
                }
        }

#ifdef _DEBUG
		if (MessageBox(SNDERR_g_hwndMainWnd,"","Do you want to debug ?",MB_YESNO)==IDYES)
			DebugBreak();
#endif
}

//------------------------------------------------------------
//       ClearLastError: clear last error raised on channel ulChannelID
//--------------------------------------------------------
void SND_fn_vClearLastError(unsigned long ulChannelId)
{
        int i;

        i=0;
        while ((astErrDescriptor[i].ulChannel!=ulChannelId) && (i<g_iNbError)) i++;
        if (i<g_iNbError)
        {
                        astErrDescriptor[i].ulChannel=astErrDescriptor[g_iNbError].ulChannel;
                        astErrDescriptor[i].uwErr=astErrDescriptor[g_iNbError--].uwErr;
        }
}

//-------------------------------------------------------------
//      CheckError:returns last error raised on ulChannelID
//-------------------------------------------------------------
unsigned short SND_fn_vCheckError(unsigned long ulChannelId)
{
        int i;

        i=0;
        while ((astErrDescriptor[i].ulChannel!=ulChannelId) && (i<g_iNbError)) i++;
        if (i<g_iNbError)
                return astErrDescriptor[i].uwErr;
        else
                return 0xFFFF;
}
#endif

//----- this part is not ACP complient
void SND_CALL _snd_assert(char* test,char* file,int line)
{
        char titre[256];
        char texte[256];

		// Assertion Failed in SND !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        DebugBreak();
		// Assertion Failed in SND !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

        strcpy(titre,"Sound-Assertion failed in ");
        strcat(titre,file);
        sprintf(texte," (Line n° %d)",line);
        strcat(titre,texte);
	
		SND_fn_vEnterCriticalSectionForErrorDisplay();

        MessageBox(SNDERR_g_hwndMainWnd,test,titre,MB_OK|MB_TOPMOST);

		SND_fn_vQuitCriticalSectionForErrorDisplay();

        DebugBreak();
}

/*************************************************************************************
        traitement des erreurs d'init de driver
*************************************************************************************/

/*-------------------------------------------------------------------------
    Traitement de l'échec de l'init
    Entrée:num_err=indice de l'erreur
    Sortie:INIT_RETRY pour réessayer
        INIT_CONTINUE pour continuer malgré tout
        INIT_FAILED pour abandon
--------------------------------------------------------------------------*/
int SND_CALL snd_erreur_init(int num_err)
{
    int ret,code;

	SND_fn_vEnterCriticalSectionForErrorDisplay();

    ret=Erm_fn_iMessageBox("To continue with sound, close the application that is using the sound driver, and select Retry.\nTo continue without sound, select Cancel."
		,"Sound-Driver is busy"
		,MB_RETRYCANCEL |MB_TOPMOST);
    switch (ret)
    {
    case IDABORT:
        code=INIT_FAILED;
		break;
    case IDIGNORE:
	case IDCANCEL:
        code=INIT_IGNORE;
		break;
    case IDRETRY:
        code=INIT_RETRY;
		break;
    default:
        code=INIT_IGNORE;
		break;
    }

	SND_fn_vQuitCriticalSectionForErrorDisplay();

	return code;
}

//-----------------------------------------------------------
//      SND_fn_iErreurInit
//
//      But                     : Initialisation de la fenetre de dialogue 
//                                              des erreurs a l'init du driver CD
//      Entrées : constantes numero d'erreur
//      Sorties : code de retour de la boite de dialogue
//------------------------------------------------------------
int SND_CALL SND_fn_iErreurInit(int num_err)
{
    int ret,code;

	SND_fn_vEnterCriticalSectionForErrorDisplay();

    ret=Erm_fn_iMessageBox("Insert a CD or\nClose the application using your CD and try again ...\nelse you'll not be able to hear any music"
		,"CD-Driver Problem"
		,MB_RETRYCANCEL |MB_TOPMOST);
    switch (ret)
    {
    case IDABORT:
        code=INIT_FAILED;
		break;
    case IDIGNORE:
	case IDCANCEL:
        code=INIT_IGNORE;
		break;
    case IDRETRY:
        code=INIT_RETRY;
		break;
    default:
        code=INIT_IGNORE;
		break;
    }

	SND_fn_vQuitCriticalSectionForErrorDisplay();

	return code;
}


