#include <clib/alib_protos.h>
#include <clib/dlib_protos.h>
#include <clib/datatypes_protos.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/iffparse_protos.h>
#include <clib/utility_protos.h>
#include <clib/xpkmaster_protos.h>
#include <datatypes/soundclassext.h>
#include <exec/memory.h>
#include <intuition/icclass.h>
#include <string.h>
#include "class.h"
#include "rsnd.h"

struct Arg1
{
char *xpk;
long *xpkmode;
char *password;
};

ULONG SaveRSND(IClass *cl,Object *obj,dtWrite *msg);

static long iff2dos[]=
{
0,
0,
DTERROR_INVALID_DATA,
ERROR_NO_FREE_STORE,
ERROR_SEEK_ERROR,
ERROR_SEEK_ERROR,
ERROR_SEEK_ERROR,
DTERROR_INVALID_DATA,
DTERROR_INVALID_DATA,
ERROR_OBJECT_WRONG_TYPE,
ERROR_REQUIRED_ARG_MISSING,
0xDEADDEAD
};

static long chunks[]=
{
ID_RSND,ID_RSHD,
ID_RSND,ID_NAME,
ID_RSND,ID_AUTH,
ID_RSND,ID_ANNO,
ID_RSND,ID_Copyright,
ID_RSND,ID_FVER
};

void ReadPrefs(Data *data)
{
char *var;
strcpy(data->xpk,"NUKE");
data->xpkmode=100;
if(data->password)
	{
	FreeVec(data->password);
	data->password=0;
	}
if(var=(char *)AllocVec(256,0))
	{
	if(GetVar("ENV:DataTypes/rsnd.prefs",var,256,LV_VAR|GVF_GLOBAL_ONLY)>=0)
		{
		RDArgs *rdargs;
      if(rdargs=(RDArgs *)AllocDosObject(DOS_RDARGS,0))
			{
			RDArgs *args;
			Arg1 para;
			rdargs->RDA_Source.CS_Buffer=var;
			rdargs->RDA_Source.CS_Length=strlen(var);
			rdargs->RDA_Source.CS_CurChr=0;
			memset(&para,0,sizeof(Arg1));
			if(args=ReadArgs("XPK/A,XPKMODE/A/N,PASSWORD",(long *)&para,rdargs))
				{
				strncpy(data->xpk,para.xpk,4);
				data->xpk[4]=0;
				data->xpkmode=*para.xpkmode;
				if(data->xpkmode<0) data->xpkmode=0;
				else if(data->xpkmode>100) data->xpkmode=100;
				if(para.password)
					{
					if(data->password=(char *)AllocVec(strlen(para.password)+1,MEMF_CLEAR)) strcpy(data->password,para.password);
					}
				FreeArgs(args);
				}
			FreeDosObject(DOS_RDARGS,rdargs);
			}
		}
	FreeVec(var);
	}
}

static ULONG GetSample(Object *obj,IFFHandle *iff,RSHD *rh)
{
ULONG error=0,len;
UBYTE *sample,*sam;
XpkFib *fib;
if(!XpkUnpackTags(XPK_InFH,iff->iff_Stream,XPK_GetOutBuf,&sam,XPK_GetOutBufLen,&len,TAG_END))
	{
	if(sample=(UBYTE *)AllocVec(len,MEMF_PUBLIC)) CopyMem(sam,sample,len);
	else error=ERROR_NO_FREE_STORE;
	}
else if(!XpkOpenTags(&fib,XPK_InFH,iff->iff_Stream,TAG_END))
	{
	if(sample=(UBYTE *)AllocVec(fib->xf_ULen,MEMF_PUBLIC))
		{
		long clen;
		sam=sample;
		len=0;
		while(len<fib->xf_ULen)
			{
			if((clen=XpkRead(fib,sam,fib->xf_NLen))<0)
				{
				error=DTERROR_INVALID_DATA;
				break;
				}
			sam+=clen;
			len+=clen;
			}
		}
	else error=ERROR_NO_FREE_STORE;
	XpkClose(fib);
	}
else error=DTERROR_INVALID_DATA;
if(!error) SetDTAttrs(obj,0,0,SDTA_Sample,sample,TAG_END);
return error;
}

static ULONG GetSound(IClass *cl,Object *obj)
{
ULONG error=0;
long err;
IFFHandle *iff;
GetDTAttrs(obj,DTA_Name,&iff,TAG_END);
if(iff) SetDTAttrs(obj,0,0,DTA_ObjName,iff,TAG_END);
GetDTAttrs(obj,DTA_Handle,&iff,TAG_END);
if(!iff)
	{
	GetDTAttrs(obj,DTA_SourceType,&err,TAG_END);
	if(err!=DTST_RAM) return ERROR_REQUIRED_ARG_MISSING;
	else return 0;
	}
if((err=PropChunks(iff,chunks,sizeof(chunks)/(2*sizeof(long))))<0) return iff2dos[-err];
if((err=StopOnExit(iff,ID_RSND,ID_RBOD))<0) return iff2dos[-err];
for(;;)
	{
	StoredProperty *sp;
	if((err=ParseIFF(iff,IFFPARSE_SCAN))!=IFFERR_EOC)
		{
		error=iff2dos[-err];
		break;
		}
	if(sp=FindProp(iff,ID_RSND,ID_NAME)) SetDTAttrs(obj,0,0,DTA_ObjName,sp->sp_Data,TAG_END);
	if(sp=FindProp(iff,ID_RSND,ID_AUTH)) SetDTAttrs(obj,0,0,DTA_ObjAuthor,sp->sp_Data,TAG_END);
	if(sp=FindProp(iff,ID_RSND,ID_ANNO)) SetDTAttrs(obj,0,0,DTA_ObjAnnotation,sp->sp_Data,TAG_END);
	if(sp=FindProp(iff,ID_RSND,ID_Copyright)) SetDTAttrs(obj,0,0,DTA_ObjCopyright,sp->sp_Data,TAG_END);
	if(sp=FindProp(iff,ID_RSND,ID_FVER)) SetDTAttrs(obj,0,0,DTA_ObjVersion,sp->sp_Data,TAG_END);
	if(sp=FindProp(iff,ID_RSND,ID_RSHD))
		{
		ULONG type;
		ContextNode *cn;
		Data *data=(Data *)INST_DATA(cl,obj);
		RSHD rh=*((RSHD *)sp->sp_Data);
		VoiceHeader *vh;
		ReadPrefs(data);
		GetDTAttrs(obj,SDTA_VoiceHeader,&vh,TAG_END);
		type=((rh.rshd_BitsPerSample/8-1)*2)|(rh.rshd_NumChannels-1);
		if(type<=3)
			{
			SetDTAttrs(obj,0,0,SDTA_SampleLength,rh.rshd_Length,SDTA_Frequency,rh.rshd_Frequency,SDTA_SampleType,type,SDTA_Cycles,1,TAG_END);
			vh->vh_OneShotHiSamples=rh.rshd_Length;
			vh->vh_RepeatHiSamples=0;
			vh->vh_SamplesPerHiCycle=0;
			vh->vh_SamplesPerSec=rh.rshd_Frequency;
			vh->vh_Octaves=1;
			vh->vh_Compression=1;
			vh->vh_Volume=64;
			if((cn=CurrentChunk(iff))&&(cn->cn_ID=='RBOD')) error=GetSample(obj,iff,&rh);
			else error=ERROR_REQUIRED_ARG_MISSING;
			}
		else error=ERROR_NOT_IMPLEMENTED;
		break;
		}
	else error=DTERROR_INVALID_DATA;
	}
return error;
}

static ULONG mNew(IClass *cl,Object *obj,opSet *msg)
{
TagItem *ti;
if(ti=FindTagItem(DTA_SourceType,(((opSet *)msg)->ops_AttrList)))
	{
	if(ti->ti_Data!=DTST_FILE&&ti->ti_Data!=DTST_CLIPBOARD&&ti->ti_Data!=DTST_RAM)
		{
		SetIoErr(ERROR_OBJECT_WRONG_TYPE);
		return 0;
		}
	}
if(obj==(Object *)cl)
	{
	if(obj=(Object *)DoSuperMethodA(cl,obj,Msg(msg)))
		{
		ULONG error;
		if(error=GetSound(cl,obj))
			{
			SetIoErr(error);
			CoerceMethod(cl,obj,OM_DISPOSE);
			obj=0;
			}
		}
	}
else
	{
	SetIoErr(ERROR_NOT_IMPLEMENTED);
	obj=0;
	}
return ULONG(obj);
}

ULONG mDispose(IClass *cl,Object *obj,Msg msg)
{
Data *data=(Data *)INST_DATA(cl,obj);
if(data->password) FreeVec(data->password);
return DoSuperMethodA(cl,obj,msg);
}

static ULONG mWrite(IClass *cl,Object *obj,dtWrite *msg)
{
return (msg->dtw_Mode==DTWM_IFF)?DoSuperMethodA(cl,obj,Msg(msg)):SaveRSND(cl,obj,msg);
}

extern "C" ULONG Dispatcher(IClass *cl,Object *obj,Msg msg)
{
ULONG retval;
switch(msg->MethodID)
	{
	case OM_NEW:
		retval=mNew(cl,obj,(opSet *)msg);
		break;
	case OM_DISPOSE:
		retval=mDispose(cl,obj,msg);
		break;
	case DTM_WRITE:
		retval=mWrite(cl,obj,(dtWrite *)msg);
		break;
	default:
		retval=DoSuperMethodA(cl,obj,msg);
		}
return retval;
}

