#include "microdot.h"

#include "ogre_protos.h"
#include "ogre.h"

#include "asyncio.h"

#include <devices/serial.h>

#include "xproto.h"
#include "zmodem.h"
#include "xprzmodem.h"

static struct IOExtSer *ior,*iow;
static char **filearray;
static long fac;

extern ULONG tvsig;

static struct timerequest treq;
static long timeropen;
static struct MsgPort *tport;

static struct Window *tw;
static struct RastPort *lrp;
static long inabortion,docheckcd;
static struct ogwin *ogw;

static struct XPR_IO xprio;

extern int testcarrier( void );

/* The timer functions */
static long opentimer(void)
{
    tport = CreatePort( 0, 0 );
    if( !tport )
		return( -1 );
    treq.tr_node.io_Message.mn_ReplyPort = tport;
    if( OpenDevice( "timer.device", UNIT_VBLANK, &treq, 0 ) )
		return( -1 );
    timeropen = 1;
    return( 0 );
}
static void closetimer(void)
{
    if( timeropen )
		CloseDevice( &treq );
    if( tport )
		DeletePort( tport );
    timeropen = 0;
	tport = 0;
}

static void __saveds qtimer(long micros)
{
    long secs=0;
    if( micros > 1000000 )
	{
		secs	= micros / 1000000;
		micros	= micros % 1000000;
    }
    treq.tr_time.tv_micro   = micros;
    treq.tr_time.tv_secs    = secs;
    treq.tr_node.io_Command = TR_ADDREQUEST;
    SendIO( &treq );
}

long xpr_finfo(char *name,long type)
{
	struct FileInfoBlock *fib=allocfib();
	BPTR lock;
	long result=0;

	if(!fib) return(0);
	if(!(lock=Lock(name,SHARED_LOCK))) goto xit;
	if(type==1) {
		Examine(lock,fib);
		result=fib->fib_Size;
	}
	else if(type==2) result=1;
	UnLock(lock);
xit:
	freefib( fib );
	return(result);
}
long xpr_ffirst(char *buffer,char *pattern)
{
	if(!filearray) return(0);

	strcpy(buffer,filearray[0]);
	fac=0;
	return(1);
}
long xpr_fnext(long fac,char *buffer,char *pattern)
{
	if(!filearray || !filearray[fac]) return(0);
	strcpy(buffer,filearray[fac++]);
	return(fac);
}

long xpr_swrite(char *buffer,long size)
{
	iow->IOSer.io_Length=size;
	iow->IOSer.io_Data=buffer;
	iow->IOSer.io_Command=CMD_WRITE;
	return(DoIO(iow));
}
long xpr_sflush(void)
{
	iow->IOSer.io_Command=CMD_CLEAR;
	return(DoIO(iow));
}
long xpr_sread(char *buffer,long size,long timeout)
{
    long flag=(1L<<ior->IOSer.io_Message.mn_ReplyPort->mp_SigBit);
    long len,nflag;
    long gotlen;

    if( inabortion )
		return(0);
    if( docheckcd )
	{
		if(!testcarrier())
		{
			inabortion=1;
			return(0);
		}
    }
	SetSignal( 0, flag );
    flag|=1L<<(tw->UserPort->mp_SigBit);
	gotlen = 0;
	while( size > 0 )
	{
		ior->IOSer.io_Command = SDCMD_QUERY;
		DoIO( ior );
		len = ior->IOSer.io_Actual;
		if( !len )
			break;
        if( len > size )
			len = size;
		ior->IOSer.io_Command	= CMD_READ;
		ior->IOSer.io_Data 		= &buffer[ gotlen ];
		ior->IOSer.io_Length 	= len;
		DoIO( ior );
		size-= len; /*ior->IOSer.io_Actual;*/
		gotlen += len; /*ior->IOSer.io_Actual;*/
	}

	if( size <= 0 || !timeout || gotlen )
	{
		return( gotlen );
	}

	flag |= 1L<<tport->mp_SigBit;
	SetSignal( 0, 1L<<tport->mp_SigBit );
	qtimer( timeout );

    ior->IOSer.io_Command = CMD_READ;
    ior->IOSer.io_Data = &buffer[ gotlen ];
    ior->IOSer.io_Length = 1;
    SendIO( ior );

	for(;;)
	{
        nflag = Wait( flag | tvsig );

		if( nflag & tvsig )
			tv_proc();

        if( nflag & ( 1L<<tw->UserPort->mp_SigBit ) )
		{
			struct IntuiMessage *m;
			int ex = FALSE;

			while( ( m = GetIMsg( tw->UserPort ) ) )
			{
				if( m->Class == IDCMP_CLOSEWINDOW )
					ex = TRUE;			
				ReplyMsg( m );
			}
			if( ex )
			{
				AbortIO( &treq );
				AbortIO( ior );
				WaitIO( &treq );
				WaitIO( ior );
		        inabortion = 1;
				return( 0 );
			}
        }

        if( CheckIO( &treq ) )
		{
			AbortIO(ior);
			WaitIO(&treq);
			WaitIO(ior);
			/* Timeout */
			return( gotlen );
        }

		if( !CheckIO( ior ) )
			continue;

		AbortIO( &treq );
        WaitIO( &treq );
        WaitIO( ior );

		gotlen++;
		size--;

        while( size > 0 )
		{
        	ior->IOSer.io_Command = SDCMD_QUERY;
			DoIO( ior );
			if( ( len = ior->IOSer.io_Actual ) ) 
			{
				if( len > size )
					len = size;
				ior->IOSer.io_Length = len;
				ior->IOSer.io_Command = CMD_READ;
				ior->IOSer.io_Data = &buffer[ gotlen ];
				DoIO( ior );
				gotlen += len;
				size -= len;
			}
			else break;
        }

		return( gotlen );
	}
    return( 0 ); // shouldn't happen
}

long xpr_chkabort( void )
{
	struct IntuiMessage *m;
	ULONG class;
	if(inabortion) return(-1);
	if(tw)
	{
		if(m=ogreIM(ogw))
		{
			class = m->Class;
			ogreIMReply( ogw, m );
			if( class == IDCMP_CLOSEWINDOW )
			{
				inabortion=1;
				return(-1);
			}
		}
	}
	if(docheckcd)
	{
		if(!testcarrier())
		{
			inabortion=1;
			return(-1);
		}
	}
	return(0);
}

static void closewindow(void)
{
	if(tw)
	{
		/*CloseFont(tw->RPort->Font);
		CloseWindow(tw);*/
		freeinfofg();
		ogreExitWindow( ogw );
	}
}

static void print(int y,char *txt)
{

	ogreSetStringValue( ogw, y, txt );

}
static void printn(int y,long n)
{
	char tmp[32];
	sprintf(tmp,"%lD",n);

	ogreSetStringValue( ogw, y, tmp );
}

static void drawperc(int x1,int x2)
{
/*	char tmp[16];
	ULONG pos=(499*x1)/x2;
	ULONG perc=(100*x1)/x2;
	sabd(lrp,3,0,JAM1);
	RectFill(lrp, 5,111, 5+pos,111+11);
	SetAPen(lrp,0);
	RectFill(lrp,5+pos,111,499+5,111+11);
	sprintf(tmp,"%ld%%",perc);
	SetAPen(lrp,1);
	Move(lrp,5+238,111+8);
	Text(lrp,tmp,strlen(tmp));
	sabd(lrp,1,0,JAM2);*/
	ogreSetMaxVal( ogw, 13, x2 );
	ogreSetValue( ogw, 13, x1 );
}


static long filesize;
extern struct Screen *scr;
static void openwindow(char *title)
{
	filesize=0;

	ogw = ogreInitWindow( scr,
		WFLG_CLOSEGADGET | WFLG_ACTIVATE,
		IDCMP_CLOSEWINDOW,
		title
	);

	ogreAddGroup( ogw, 0, OGFRAME_OUTLINE, NULL );
	ogreAddText( ogw, 0, "     Dateiname:", 1, "", 42, 1 );
	ogreAddText( ogw, 1, "    Dateigröße:", 2, "", 42, 1 );

	ogreAddGroup( ogw, 1, OGFRAME_OUTLINE, NULL );
	ogreAddText( ogw, 0, "Letzte Meldung:", 5, "", 42, 1 );
	ogreAddText( ogw, 1, "Letzter Fehler:", 6, "", 42, 1 );
	ogreAddText( ogw, 2, " Anzahl Fehler:", 7, "", 42, 1 );

	ogreAddGroup( ogw, 2, OGFRAME_OUTLINE, NULL );
	ogreAddText( ogw, 0, "  Bytes gesendet:", 3, "", 15, 1 );
	ogreAddText( ogw, 0, "      Blöcke:", 4, "", 18, 1 );
	ogreAddText( ogw, 1, " Zeichen/Sekunde:", 10, "", 15, 1 );
	ogreAddText( ogw, 1, "   Protokoll:", 0, "", 18, 1 );

	ogreAddGroup( ogw, 3, OGFRAME_OUTLINE, NULL );
	ogreAddText( ogw, 0, "      Gesamtzeit:", 8, "", 15, 1 );
	ogreAddText( ogw, 0, " Zeit bisher:", 9, "", 18, 1 );

	ogreAddGroup( ogw, 4, OGFRAME_NONE, NULL );
	ogreAddText( ogw, 0, "       Bereits übertragen:", 16, "", 1, FALSE );
	ogreAddFuelGauge( ogw, 0, 13, 100 );
	ogreAddText( ogw, 1, "Belegter Festplattenplatz:", 14, "", 1, FALSE );
	ogreAddFuelGauge( ogw, 1, 15, 100 );

	setupinfofg( "", ogw, 15 );

	tw = ogreOpenWindow( ogw );

	doinfofg();

}
static char tempproto[64],tempblockcheck[32];
static long filesize;
void xpr_update(struct XPR_UPDATE *xu)
{
	long ud=xu->xpru_updatemask;
	char tmp[96];
	static ULONG errors, timeouts;
	static ULONG blockcount, blocksize;
	static int counter;
	

	if(!tw) return;
	if(ud&XPRU_PROTOCOL) strcpy(&tempproto[0],xu->xpru_protocol);
	if(ud&XPRU_BLOCKCHECK) strcpy(&tempblockcheck[0],xu->xpru_blockcheck);
	if((ud&XPRU_PROTOCOL) || (ud&XPRU_BLOCKCHECK)) {
		sprintf(tmp,"%s / %s",tempproto,tempblockcheck);
		print(0,tmp);
	}
	if(ud&XPRU_FILENAME) print(1,xu->xpru_filename);
	if(ud&XPRU_FILESIZE) printn(2,filesize=xu->xpru_filesize);
	if(ud&XPRU_BYTES)
	{
		if(filesize) drawperc(xu->xpru_bytes,filesize);
		printn(3,xu->xpru_bytes);

		if( ! ( counter++ & 15 ) )
			doinfofg();
	}
	if(ud&XPRU_BLOCKS)
		blockcount = xu->xpru_blocks;
	if(ud&XPRU_BLOCKSIZE)
		blocksize = xu->xpru_blocksize;

	if( ud & ( XPRU_BLOCKS | XPRU_BLOCKSIZE ) )
	{
		sprintf( tmp, "%lD (à %lD Bytes)", blockcount, blocksize );
		print( 4, tmp );
	}

	if(ud&XPRU_MSG) print(5,xu->xpru_msg);
	if(ud&XPRU_ERRORMSG) print(6,xu->xpru_errormsg);
	if(ud&XPRU_ERRORS)
		errors = xu->xpru_errors;
	if(ud&XPRU_TIMEOUTS)
		timeouts = xu->xpru_timeouts;

	if( ud & ( XPRU_TIMEOUTS | XPRU_ERRORS ) )
	{
		sprintf( tmp, "%lD / %lD", errors, timeouts );
		print( 7, tmp );
	}

	if(ud&XPRU_EXPECTTIME) print(8,xu->xpru_expecttime);
	if(ud&XPRU_ELAPSEDTIME) print(9,xu->xpru_elapsedtime);
	if(ud&XPRU_DATARATE) printn(10,xu->xpru_datarate);
}

static void initio(void)
{
	memset(&xprio,0,sizeof(struct XPR_IO));
	strcpy(&tempproto[0],"--");
	strcpy(&tempblockcheck[0],"--");
}

long xpr_send(struct IOExtSer *sr,struct IOExtSer *sw,
	long checkcd,
	char **files)
{
	long retcode=0;

	ior=sr; iow=sw;
	filearray=files; fac=0;
	inabortion=0; docheckcd=checkcd;

	openwindow("Sende..."); 
	opentimer();
	initio();

	xprio.xpr_filename=files[0];
	retcode=XProtocolSend(&xprio);
	if(inabortion) retcode=0;
	XProtocolCleanup(&xprio);
bibi:
	closetimer();
	closewindow();
	return(retcode);
}

long xpr_receive(struct IOExtSer *sr,struct IOExtSer *sw,
	long checkcd)
{
	long retcode=0;

	ior=sr; iow=sw;
	filearray=NULL; fac=0;
	inabortion=0; docheckcd=checkcd;

	openwindow("Empfange...");
	opentimer();
	initio();

	xprio.xpr_filename="Unknown";
	retcode=XProtocolReceive(&xprio);
	if(inabortion) retcode=0;	
	XProtocolCleanup(&xprio);
bibi:
	closetimer();
	closewindow();
	return(retcode);
}

int zmodemmode;

void setzmodemmode( int mode )
{
	zmodemmode = mode;
}
