/*-------------------------------------------------------------------*/
/*!																	!*/
/*!		Module SNDSWTCH.C: management of TYPE_SWITCH resources		!*/
/*!																	!*/
/*-------------------------------------------------------------------*/
 
#include "SNDinc.h"
 
#include "sndres.h"
#include "sndswtch.h"
#include "sndplay.h"
 
#ifndef NO_ACP_SOUND
 
typedef struct switch_voice_ switch_voice;
struct switch_voice_{
	long		lLowVoice;	/*voice of low-level resource*/
	tduRefRes	res_low;
	tduRefRes	res_hi;
	long		prio;
	SND_td_pfn_vSoundCallback fn_callback;
	long		par_callback;
	SndBool		bValid;	/*TRUE while voice is active*/
	unsigned char ucVolume;	/*combined volumes for switch resources in the chain*/
};
 
 
/*----------------------------------------------------------------------------------
        Obtient la ressource de type NON-Switch associee à une ressource switch (ou à un switch de switch de ...switch)
-----------------------------------------------------------------------------------*/
tduRefRes SND_fn_tdGetEffectiveResourceSwitch(tduRefRes res_switch,SoundParam* par,unsigned char* pVolume)
{
        tdstSwitchElement*      pSwitchElement; 
        tdstTypeSwitchMem*         pSwitchList;
        tduRefRes       uRes;
        long            indice;
        int             i;
        SndBool         bFound;
		SwitchParam*	pstSwitch;
		unsigned long	ulVolume=1;
		int				iNbVolumes=0;
 
        uRes=res_switch;

        while ((uRes.pstPtr!=SND_C_RES_FANTOME_PTR) 
			&& (SND_fn_bIsResourceSwitch(uRes)))
        {
			ulVolume*=uRes.pstPtr->ucVolume;
			iNbVolumes++;

			{/*resolution of a switch stage*/
				if (par->iFlags & C_SOUNDPARAM_SWITCH)
				{
					pstSwitch=&(SND_M_GetExtraParamFromSoundParam(par))->stSwitch;
					indice=SND_fn_lGetSwitchIndice(pstSwitch->lObjectType,pstSwitch->lObjectId,uRes);
				}
				else
					indice=uRes.pstPtr->uRes.stSwitch.hDefault;
 
                pSwitchList=&(uRes.pstPtr->uRes.stSwitch);
                bFound=FALSE;
                SNDLST2_M_StaticForEachElementOf(pSwitchList,pSwitchElement,i)
                {
                        if (pSwitchElement->hIndice==indice)
                        {
                                uRes=pSwitchElement->uRes;
                                bFound=TRUE;
                                break;
                        }
                }
                if (bFound==FALSE)
                {/*on n'a pas trouve l'element "indice"*/
                        if (uRes.pstPtr->uRes.stSwitch.hDefault!=C_SWITCH_NODEFAULT)
                        {/*on se rabat sur le default*/
                                bFound=FALSE;
                                SNDLST2_M_StaticForEachElementOf(pSwitchList,pSwitchElement,i)
                                {
                                        if (pSwitchElement->hIndice==uRes.pstPtr->uRes.stSwitch.hDefault)
                                        {
                                                uRes=pSwitchElement->uRes;
                                                bFound=TRUE;
                                                break;
                                        }
                                }
                                if (bFound==FALSE)
                                        /*le defaut n'existe pas danbs la liste*/
                                        uRes.pstPtr=SND_C_RES_FANTOME_PTR;
                        }
                        else
                        {/*pas de default*/
                                uRes.pstPtr=SND_C_RES_FANTOME_PTR;
                        }
                }
			}
        }

		if (iNbVolumes>1)
			*pVolume=(unsigned char)(ulVolume/iNbVolumes);
		else
			*pVolume=(unsigned char)ulVolume;

        return uRes;
}
 
void SND_fn_vInitSwitch(void)
{
}
 
void SND_fn_vDesInitSwitch(void)
{
}
 
long SND_fn_lPlaySwitch(tduRefRes num_res,SoundParam* par,long prio,SND_td_pfn_vSoundCallback fn_callback,long par_callback)
{
	tduRefRes	low_res;
	switch_voice *pstSwitchVoice;
    SoundParam *pstSoundPar;
#ifdef NB_MICRO_MAX
    SoundParam stSoundPar;
#endif
	unsigned char ucVolume;
 
	pstSwitchVoice=SND_fn_pvMallocSndEx(E_ucSndBlockMain,sizeof(switch_voice));
	pstSwitchVoice->bValid=TRUE;
 
	low_res=SND_fn_tdGetEffectiveResourceSwitch(num_res,par,&ucVolume);
 
	pstSwitchVoice->res_hi=num_res;
	pstSwitchVoice->ucVolume = ucVolume;
	pstSwitchVoice->res_low=low_res;
	pstSwitchVoice->prio=prio;
	pstSwitchVoice->fn_callback=fn_callback;
	pstSwitchVoice->par_callback=par_callback;
 
	if (low_res.pstPtr!=SND_C_RES_FANTOME_PTR)
	{
#ifdef NB_MICRO_MAX
		pstSoundPar=&stSoundPar;
#else
		pstSoundPar=SND_fn_pCreateSoundParam(par->iNbLinks);
#endif
		memcpy(pstSoundPar,par,SND_M_lGetSizeOfSoundParam(par));
 
		/*sxd params are modified by Switch static params*/
		pstSoundPar->ucVol=(unsigned char)(((long)pstSoundPar->ucVol*ucVolume)>>7);
		pstSoundPar->iFlags|=C_SOUNDPARAM_COEF_VOL;

		pstSwitchVoice->lLowVoice=SND_fn_lPlaySnd(low_res,pstSoundPar,prio,NULL,0,&pstSwitchVoice->bValid);

#ifndef NB_MICRO_MAX
		SND_fn_vDestroySoundParam(pstSoundPar);
#endif

		if (pstSwitchVoice->lLowVoice!=C_PLAY_FAILED)
			return (long)pstSwitchVoice;
	}
 
	/*failed*/
	SND_fn_vFreeSndEx(E_ucSndBlockMain,pstSwitchVoice);
 
	return C_PLAY_FAILED;
}
 
SndBool SND_CALL SND_fn_bSetParamSwitch(long voice,SoundParam* par)
{
	switch_voice *pstSwitchVoice=(switch_voice*)voice;
	tduRefRes	new_res;
    SoundParam *pstSoundPar;
#ifdef NB_MICRO_MAX
    SoundParam stSoundPar;
#endif
	unsigned char ucVolume=127;
	SndBool	bRet=FALSE;

	if (pstSwitchVoice->res_hi.pstPtr->uRes.stSwitch.bDynamic)
		new_res=SND_fn_tdGetEffectiveResourceSwitch(pstSwitchVoice->res_hi,par,&ucVolume);
	else
		new_res=pstSwitchVoice->res_low;
 
	#ifdef NB_MICRO_MAX
	pstSoundPar=&stSoundPar;
	#else
	pstSoundPar=SND_fn_pCreateSoundParam(par->iNbLinks);
	#endif
	memcpy(pstSoundPar,par,SND_M_lGetSizeOfSoundParam(par));

	if (new_res.pstPtr==pstSwitchVoice->res_low.pstPtr)
	{
		/*sxd params are modified by Switch static params*/
		pstSoundPar->ucVol=(unsigned char)(((long)pstSoundPar->ucVol*pstSwitchVoice->ucVolume)>>7);
		pstSoundPar->iFlags|=C_SOUNDPARAM_COEF_VOL;

		if (pstSwitchVoice->bValid && SND_fn_bSetParamSnd(pstSwitchVoice->lLowVoice,pstSoundPar))
			bRet=TRUE;
	}
	else
	{
		SND_fn_vStopSnd(pstSwitchVoice->lLowVoice);
		/*sxd params are modified by Switch static params*/
		pstSoundPar->ucVol=(unsigned char)(((long)pstSoundPar->ucVol*ucVolume)>>7);
		pstSoundPar->iFlags|=C_SOUNDPARAM_COEF_VOL;

		pstSwitchVoice->lLowVoice=SND_fn_lPlaySnd(new_res,pstSoundPar,pstSwitchVoice->prio,NULL,0,&pstSwitchVoice->bValid);
		pstSwitchVoice->res_low=new_res;
		pstSwitchVoice->ucVolume=ucVolume;
 
		if (pstSwitchVoice->lLowVoice!=C_PLAY_FAILED)
			bRet=TRUE;
	}
 
	#ifndef NB_MICRO_MAX
	SND_fn_vDestroySoundParam(pstSoundPar);
	#endif

	if (bRet)
		return TRUE;

	if (pstSwitchVoice->fn_callback)
		(*pstSwitchVoice->fn_callback)(pstSwitchVoice->par_callback);
 
	SND_fn_vFreeSndEx(E_ucSndBlockMain,pstSwitchVoice);
 
	return FALSE;
}
 
SndBool SND_CALL SND_fn_bTestIsPlayingSwitch(long voice)
{
	switch_voice *pstSwitchVoice=(switch_voice*)voice;
 
	if (pstSwitchVoice->bValid && SND_fn_bTestIsPlayingSnd(pstSwitchVoice->lLowVoice))
		return TRUE;
	else
	{
		if (pstSwitchVoice->fn_callback)
			(*pstSwitchVoice->fn_callback)(pstSwitchVoice->par_callback);
 
		SND_fn_vFreeSndEx(E_ucSndBlockMain,pstSwitchVoice);
 
		return FALSE;
	}
}
 
void SND_CALL SND_fn_vStopSwitch(long voice)
{
	switch_voice *pstSwitchVoice=(switch_voice*)voice;
 
	if (pstSwitchVoice->bValid)
		SND_fn_vStopSnd(pstSwitchVoice->lLowVoice);
 
	if (pstSwitchVoice->fn_callback)
		(*pstSwitchVoice->fn_callback)(pstSwitchVoice->par_callback);
 
	SND_fn_vFreeSndEx(E_ucSndBlockMain,pstSwitchVoice);
}
 
void SND_CALL SND_fn_vPauseSwitch(long voice)
{
	switch_voice *pstSwitchVoice=(switch_voice*)voice;
 
	if (pstSwitchVoice->bValid)
		SND_fn_vPauseSnd(pstSwitchVoice->lLowVoice);
}
 
void SND_CALL SND_fn_vResumeSwitch(long voice)
{
	switch_voice *pstSwitchVoice=(switch_voice*)voice;
 
	if (pstSwitchVoice->bValid)
		SND_fn_vResumeSnd(pstSwitchVoice->lLowVoice);
}
 
void SND_fn_vRemoveCallbackSwitch(long voice)
{
	switch_voice *pstSwitchVoice=(switch_voice*)voice;
 
	pstSwitchVoice->fn_callback=NULL;
}
 
void SND_fn_vUnLoadResSwitch(tdstBlockResourceMem* mem)
{
}
 
SndReal SND_CALL SND_fn_rGetPosSwitch(long voice)
{
	switch_voice *pstSwitchVoice=(switch_voice*)voice;
 
	if (pstSwitchVoice->bValid)
		return SND_fn_rGetPosSnd(pstSwitchVoice->lLowVoice);
	else
		return SND_C_POS_UNKNOWN;
}
 
SndReal SND_CALL SND_fn_rGetLengthSwitch(long voice)
{
	switch_voice *pstSwitchVoice=(switch_voice*)voice;
 
	if (pstSwitchVoice->bValid)
		return SND_fn_rGetLengthSnd(pstSwitchVoice->lLowVoice);
	else
		return SND_C_LENGTH_UNKNOWN;
}
 
 
void SND_fn_vConvertResDiskToMemSwitch(tdstBlockResourceDisk* disk,tdstBlockResourceMem* mem,void* ptrBegin)
{
        mem->Id=disk->Id;
        mem->eType=disk->eType;
        mem->eStorage=disk->eStorage;
        mem->ucVolume=disk->ucVolume;
        mem->bIsLoaded=TRUE;
        
        /*partie specifique au type de ressource*/
        mem->uRes.stSwitch.ulNbElements = disk->uRes.stSwitch.ulNbElements;
        mem->uRes.stSwitch.lTypeSwitch = disk->uRes.stSwitch.lTypeSwitch;
        mem->uRes.stSwitch.hDefault = disk->uRes.stSwitch.hDefault;
		mem->uRes.stSwitch.bDynamic=disk->uRes.stSwitch.bDynamic;
}
 
 
#ifndef NO_ACP_SCRIPT
SndBool SND_fn_bLoadResScriptSwitch(tdstBlockResourceDisk *disk,tdstBlockResourceMem *mem)
{
        SND_fn_vConvertResDiskToMemSwitch(disk,mem,NULL);
        return TRUE;
}
#endif
 
#ifndef NO_ACP_LDBIN
SndBool SND_fn_bLoadResBinarySwitch(tdstBlockResourceDisk *_pBRDisk,tdstBlockResourceMem *_pBRMem,char *pDataBloc)
{
        tdstSwitchElement *pSwitchArray,*pSwitchElement;
        
        int iPos;
        /* Convert the ulDataOffset member to a pointer:*/
        pSwitchArray=(tdstSwitchElement *)(pDataBloc + _pBRDisk->ulDataOffset);
 
        /* Set pointers to range list:*/
        /*SNDLST2_M_StaticSetFirstElement(&_pBRMem->uRes.stSplit.stRangeList,pRangeArray);*/
        SNDLST2_M_StaticSetMember(&_pBRMem->uRes.stSwitch,hFirstElement,pSwitchArray);
        /*SNDLST2_M_StaticSetMember( &_pBRMem->uRes.stSplit.stRangeList, hFirstElement, pRangeArray);*/
        SNDLST2_M_StaticSetMember(&_pBRMem->uRes.stSwitch, lNumberOfElements, _pBRDisk->uRes.stSwitch.ulNbElements);
 
        /* Reset pointers in range:*/
        SNDLST2_M_StaticForEachElementOf( &_pBRMem->uRes.stSwitch, pSwitchElement, iPos)
        {
            pSwitchElement->uRes.pstPtr=SND_fn_pGetBinRes(pSwitchElement->uRes.Id);
        }
 
        SND_fn_vConvertResDiskToMemSwitch(_pBRDisk,_pBRMem,NULL);
        return TRUE;
}
 
/*loads Switch resource of previous version*/
SndBool SND_fn_bLoadResBinarySwitchOld(tdstBlockResourceDisk *_pBRDisk,tdstBlockResourceMem *_pBRMem,char *pDataBloc)
{
	tdstBlockResourceDisk stDisk;
 
	/*conversion du SWITCH_OLD en SWITCH*/
	memcpy(&stDisk,_pBRDisk,sizeof(stDisk));
 
	stDisk.eType=TYPE_SWITCH;
 
    stDisk.uRes.stSwitch.ulNbElements=_pBRDisk->uRes.stSwitchOld.ulNbElements;
    stDisk.uRes.stSwitch.lTypeSwitch=_pBRDisk->uRes.stSwitchOld.lTypeSwitch;
    stDisk.uRes.stSwitch.hDefault=_pBRDisk->uRes.stSwitchOld.hDefault;
	stDisk.uRes.stSwitch.bDynamic=_pBRDisk->uRes.stSwitchOld.bDynamic;
	
	stDisk.uRes.stSwitch.bMaintainIfSwitched=FALSE;
 
	return SND_fn_bLoadResBinarySwitch(&stDisk,_pBRMem,pDataBloc);
}
#endif
 
/*get the final simple resource*/
tduRefRes SND_fn_tduGetLowestResourceSwitch(tduRefRes uHighRes,SoundParam* par,SndBool eval)
{
	unsigned char uvVolumeBidon;/*not used*/

	return SND_fn_tduGetLowestResourceSnd(SND_fn_tdGetEffectiveResourceSwitch(uHighRes,par,&uvVolumeBidon),par,eval);
}
 
/*-------------------------------------------------------------*/
/*  Retourne TRUE si ressource de type SWITCH*/
/*-------------------------------------------------------------*/
SndBool SND_fn_bIsResourceSwitch(tduRefRes res)
{
    if ((res.pstPtr!=NULL) && (res.pstPtr->eType==TYPE_SWITCH))
        return TRUE;
    else
        return FALSE;
}

SndBool  SND_fn_bSetResourceStaticVolumeSwitch(tdstBlockResourceMem* pstRes,unsigned char ucVolume)
{
	pstRes->ucVolume=ucVolume;

	return TRUE;
}

 
#endif /*NO_ACP_SOUND*/
 
