#include <workbench/startup.h>
#include <midi/kawai_k1.h>
#include <libraries/reqbase.h>

struct IntuitionBase	*IntuitionBase;
struct GfxBase			*GfxBase;
struct MidiBase			*MidiBase;
struct ReqBase			*ReqBase;

struct MDest			*dest;
struct MSource			*src;
struct MRoute			*inroute, *outroute;

struct FileRequester	MyFileReqStruct;
char					filename[FCHARS],
						directoryname[DSIZE],
						answerarray[DSIZE+FCHARS],
						*WriteError[4] =
						{ "Einfacher Schreibfehler","Der Synthspeicher ist schreibgeschützt!",
						  "Keine Cartridge vorhanden!","K1 antwortet nicht!" };
struct TRStructure		meintrs = { 0,0,0,0,0,0,"Sag mir:",0xFFFF,0,0,0,0,0,0 };

UBYTE					data[8082],		/* kplt. SoundBank 64 S + 32 M */
						request[9] = { MS_SYSEX,MID_KAWAI,0,K1_OBDR,K1_GROUP,KAWAI_K1,K1_INT,0,MS_EOX };

struct MRouteInfo		riin = { MMF_SYSEX, -1, 0, 0, { 0,0,0,0 }, { 0,0,0,0 } };
						/* d.h. nur SysExs passieren die Route */


/***************************************************************************/


int WoIsK1()					/* -1 bei nirgends Ack, sonst 0..15 */
{	static UBYTE req[5] = { MS_SYSEX,MID_KAWAI,0,K1_MIR,MS_EOX };
	UBYTE *ack;
	int chn;

	for(chn=0; chn<16; chn++)
	{	req[OFFS_CHAN] = chn;
		PutMidiMsg(src, req);
		Delay(25L);
		while(ack = GetMidiMsg(dest))
			if(ack[OFFS_FUNC] == K1_MIA) return chn;
	}
	return -1;
}

GetBlock(channel, ie, nr, data)		/* Einmal leersaugen, bitte */
  int channel,ie,nr;
  UBYTE *data;
{	UBYTE *msg;

	request[OFFS_CHAN] = channel;
	request[OFFS_FUNC] = K1_ABDR;
	request[OFFS_SUB1] = ie;
	request[OFFS_SUB2] = nr;
	PutMidiMsg(src, request);

	WaitPort(dest->DestPort);
	if(msg = GetMidiMsg(dest))
	{	if(msg[OFFS_FUNC]==K1_ABDD) movmem(msg+OFFS_DATA, data, (nr < 64) ? 32*88 : 32*76);
		FreeMidiMsg(msg);
	}
}

PutBlock(channel, ie, nr, data)		/* Einmal vollpumpen, bitte */
  int channel, ie, nr;
  UBYTE *data;
{	UBYTE *msg, *reply;
	int err = 4, bs = (nr < 64) ? 32*88 : 32*76;	/* BlockSize abh. von Single/Multi */
	register int i;

	if(msg = AllocMem(9+bs, MEMF_PUBLIC+MEMF_CLEAR))
	{	movmem(request, msg, 9);	/* den Header vom Request übernehmen */
		msg[OFFS_CHAN] = channel;
		msg[OFFS_FUNC] = K1_ABDD;
		msg[OFFS_SUB1] = ie;
		msg[OFFS_SUB2] = nr;
		movmem(data, msg+OFFS_DATA, bs);
		msg[OFFS_DATA+bs] = MS_EOX;
		PutMidiMsg(src, msg);		/* Hinfort! Weiche von mir, elender Dump! */
	}

	WaitPort(dest->DestPort);
	if(reply = GetMidiMsg(dest))
	{	err = reply[OFFS_FUNC];
		FreeMidiMsg(reply);
	}

	if(msg) FreeMem(msg, 9+bs);
	return(err & 7);
}

int UserRequest(text,a,b,c)
  char *text,*a,*b,*c;
{
	meintrs.Text = text;
	meintrs.NegativeText = a;		/* 0 (rechts) */
	meintrs.PositiveText = b;		/* 1 (links) */
	meintrs.MiddleText = c;			/* 2 (mitte) */

	return TextRequest(&meintrs);
}

MakeInfo(s)
  char *s;
{	UBYTE info[2048];
	FILE *ifp, *fi;
	int l;
	char t[64];

	strcpy(t,s); strcat(t,".info");
	if(ifp=fopen("T:MIDIicon","r"))
	{	l = fread(info, 1, 2048, ifp);
		if(fi=fopen(t,"w"))
		{	fwrite(info, l, 1, fi);
			fclose(fi);
		}
		fclose(ifp);
	}
}

Init()
{
	if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0L)))
		shit(NULL);
	GfxBase=IntuitionBase->GfxBase;
	if(!(ReqBase = (struct ReqBase *)OpenLibrary("req.library", 0L)))
	{	DisplayBeep(0L);
		shit(NULL);
	}
	if(!(MidiBase = OpenLibrary(MIDINAME, MIDIVERSION)))
		shit("Keine midi.library!");
	dest = CreateMDest(NULL, NULL);
	src = CreateMSource(NULL, NULL);
	inroute = MRouteDest("MidiIn", dest, &riin);
	outroute = MRouteSource(src, "MidiOut", &riin);

	MyFileReqStruct.PathName = answerarray;
	MyFileReqStruct.Dir = directoryname;
	MyFileReqStruct.File = filename;
	MyFileReqStruct.dirnamescolor = 2;
	MyFileReqStruct.devicenamescolor = 2;
}

shit(t)
  char *t;
{
	if(t) UserRequest(t,NULL,NULL," Tschüß! ");
    if(inroute) DeleteMRoute(inroute);
    if(outroute) DeleteMRoute(outroute);
    if(dest) DeleteMDest(dest);
    if(src) DeleteMSource(src);
    if(ReqBase) { PurgeFiles(&MyFileReqStruct); CloseLibrary(ReqBase); }
    if(MidiBase) CloseLibrary(MidiBase);
	if(IntuitionBase) CloseLibrary(IntuitionBase);
	exit(0);
}

char *extend(name,ext)
  char *name, *ext;
{	static char buffer[64];
	char *s;

	if(s = rindex(name, '.'))
		if(strncmp(s, ext) == 0) return name;

	strcpy(buffer,name);
	strcat(buffer,ext);
	return buffer;
}

main(argc, argv)
  int argc;
  char *argv[];
{	int c, e, err;
	char *s;
	FILE *fp;

	Init();
	if((c = WoIsK1()) == -1)
		shit("Kein K1 gefunden.");

	do
	{	e = UserRequest("GET von welcher Bank?"," INT "," EXT ",NULL);
		GetBlock(c, e, 0 , data);
		GetBlock(c, e, 32, &data[2816]);
		GetBlock(c, e, 64, &data[5650]);

		if(UserRequest("Was tun mit den Daten?"," PUT "," SAVE ",NULL))
		{	/* SAVE */
			MyFileReqStruct.Flags = FRQCACHINGM+FRQINFOGADGETM+FRQSAVINGM;
			MyFileReqStruct.Title = "Dumpdatei abspeichern:";
			MyFileReqStruct.Show[0] = '*';
			strcpy(MyFileReqStruct.Show + 1, ".dump");
			if(FileRequester(&MyFileReqStruct))
			{	if(fp = fopen(s = extend(answerarray, ".dump"), "w+"))
				{	fwrite(data, 8082, 1, fp);
					fclose(fp);
					MakeInfo(s);		/* Icon erstellen für PutDump-Programm */
				}
				else SimpleRequest("Ich kann %s nicht öffnen.", s);
			}
		}
		else	/* PUT */
		{	e = UserRequest("PUT in welche Bank?"," INT "," EXT ",NULL);
			if(!(err = PutBlock(c, e, 0 , data)))
				if(!(err = PutBlock(c, e, 32, &data[2816])))
					err = PutBlock(c, e, 64, &data[5650]);
			if(err) SimpleRequest("%s", WriteError[err]);
		}
	} while(UserRequest("Noch einen GET?"," NEIN ","  JA  ",NULL));

	shit(NULL);
}
