/*
 *  MicroDot XPK-Support
 */

#include "microdot.h"
#include "ogre.h"
#include "ogre_protos.h"
#include <libraries/xpk.h>

#define GID_ULV 1
#define GID_UCANCEL 2
#define GID_UOK 3
#define GID_UINFO 4

extern struct Library *XpkBase;

struct packsel {
	char id[ 6 ];
	UWORD mode;
};

static void doxpkinfo( struct ogrevn *vn )
{
	struct packsel *ps;
	XPINFO xppi;
	XMINFO xmi;
	char typ[ 80 ];

	if( !vn )
		return;
	ps = vn->userdata;

	XpkQueryTags( XPK_PackMethod, ps->id, XPK_PackerQuery, &xppi, TAG_DONE );
	XpkQueryTags( XPK_PackMethod, ps->id, XPK_PackMode, ps->mode, XPK_ModeQuery, &xmi, TAG_DONE );

	typ[ 0 ] = 0;
	if( xppi.Flags & XPKIF_ENCRYPTION )
	{
		strcpy( typ, "\nVerschlüsselungsalgorithmus" );
		if( xppi.Flags & XPKIF_NEEDPASSWD )
			strcat( typ, ", benötigt Passwort!" );
		strcat( typ, "\n" );
	}

	askreq("\
Name..................: %s\n\
%s\n\
%s\n\
Modus.................: %s\n\
RAM-Bedarf/Packen.....: %lD KBytes\n\
RAM-Bedarf/Entpacken..: %lD KBytes\n\
Packgeschwindigkeit...: %lD KByte/sec\n\
Entpackgeschwindigkeit: %lD KByte/sec\n\
Ungefähre Packratio...: %ld.%ld%%", "Ok",
		xppi.LongName, xppi.Description,
		typ,
		xmi.Description, xmi.PackMemory, xmi.UnpackMemory,
		xmi.PackSpeed, xmi.UnpackSpeed, xmi.Ratio / 10, xmi.Ratio % 10
	);

}

void xpknotinstalled( void )
{
	if( !XpkBase )
	{
		askreq( "Die \"xpkmaster.library\" konnte nicht geöffnet werden.\nUm die XPK-Kompression nutzen zu können, müssen Sie zuerst\ndas XPK-Paket auf Ihrem Rechner installieren.", "Abbruch" );
	}
}

char *xpkinfostring( void )
{
	static char buffer[ 80 ];
	char xpkid[ 8 ];
	char xpkerror[ 70 ];
	XPINFO xppi;
	XMINFO xmi;

	if( !XpkBase )
	{
		xpknotinstalled();
		return( "XPK nicht installiert!" );
	}

	if( !prefs.xpkid )
	{
		return( "Noch kein Packer ausgewählt!" );
	}

	xpkid[ 4 ] = 0;
	memcpy( xpkid, &prefs.xpkid, 4 );

	if( XpkQueryTags(
		XPK_GetError, xpkerror,
		XPK_PackerQuery, &xppi,
		XPK_PackMethod, xpkid,
		TAG_DONE ) )
	{
		/* Error */
		sprintf( buffer, "FEHLER: %s.%ld, %s",
			xpkid, prefs.xpkmode,
			xpkerror
		);
		return( buffer );
	}

	XpkQueryTags(
		XPK_ModeQuery, &xmi,
		XPK_PackMethod, xpkid,
		XPK_PackMode, prefs.xpkmode,
		TAG_DONE
	);

	sprintf( buffer, "%s, %s",
		xppi.Name,
		xmi.Description
	);

	return( buffer );
}


void selectxpk( void )
{
	struct ogwin *ogw;
	struct Window *iw;
	struct IntuiMessage *im;
	int Done = FALSE;
	struct ogrevn *vn;
	ULONG lastsecs = 0, lastmics = 0, oldval = 0, val;
	XPLIST xplist;
	XPINFO xppi;
	XMINFO xmi;
	int c, d;
	char buffer[ 60 ];
	void *packselpool;
	struct packsel *ps;

	if( !XpkBase )
	{
		xpknotinstalled();
		return;
	}

	XpkQueryTags( XPK_PackersQuery, &xplist, TAG_DONE );

	packselpool = LibCreatePool( 0, sizeof( struct packsel ) * 64, sizeof( struct packsel ) * 2 );

	ogw = ogreInitWindow( scr, 0, 0, "Bitte XPK-Packer auswählen:" );
	ogreAddGroup( ogw, 0, OGFRAME_NONE, NULL );
	ogreAddList( ogw, 0, 0xff, NULL, GID_ULV, 60, 16, 0, NULL );
	ogreLVInit( ogw, GID_ULV );

	for( c = 0; c < xplist.NumPackers; c++ )
	{
		XpkQueryTags( XPK_PackMethod, xplist.Packer[ c ], XPK_PackerQuery, &xppi, TAG_DONE );

		for( d = 0; d < 100; d = xmi.Upto + 1 )
		{
			if( XpkQueryTags( XPK_ModeQuery, &xmi, XPK_PackMethod, xplist.Packer[ c ], XPK_PackMode, d, TAG_DONE ) )
				break;

			sprintf( buffer, "%-32.32s %lc %s",
				xppi.LongName,
				xppi.Flags & XPKIF_ENCRYPTION ? 'E' : ' ',
				xmi.Description
			);

			ps = LibAllocPooled( packselpool, sizeof( *ps ) );

			strcpy( ps->id, xplist.Packer[ c ] );
			ps->mode = d;

			if( !memcmp( ps->id, &prefs.xpkid, 4 ) && ( prefs.xpkmode == d ) )
				ogreLVAddEntry( ogw, GID_ULV, buffer, 3, ps );
			else
				ogreLVAddEntry( ogw, GID_ULV, buffer, 2, ps );
		}
	}

	ogreAddButton( ogw, 1 | OGB_ONENTER, '@', "OK", GID_UOK );
	ogreAddButton( ogw, 1, 'i', "_Info", GID_UINFO );
	ogreAddHelp( ogw, 1 );
	ogreAddButton( ogw, 1 | OGB_ONESC, '\x1b', "Abbruch", GID_UCANCEL );

	iw = ogreOpenWindow( ogw );
	if( !iw )
		return;

	while( !Done )
	{
		im = ogreWaitIM( ogw );

		if( im->Class == IDCMP_GADGETHELP )
			showguide( "externwin_gads_16" );
		else if( im->Class == IDCMP_GADGETUP )
		{
			switch( im->Code )
			{
				case GID_ULV:
					if( im->Qualifier == 1 )
						Done = 2;
					val = ogreValue( ogw, GID_ULV );
					if( DoubleClick( lastsecs, lastmics, im->Seconds, im->Micros ) && ( val == oldval ) )
						Done = 2;
					oldval = val;
					lastsecs = im->Seconds;
					lastmics = im->Micros;
					break;

				case GID_UOK:
					Done = 2;
					break;

				case GID_UCANCEL:
					Done = 1;
					break;

				case GID_UINFO:
					doxpkinfo( ogreLVGetEntry( ogw, GID_ULV, ogreValue( ogw, GID_ULV ) ) );
					break;
			}
		}
		ogreIMReply( ogw, im );
	}

	if( Done == 2 )
	{
		vn = ogreLVGetEntry( ogw, GID_ULV, ogreValue( ogw, GID_ULV ) );
		if( vn )
		{
			ps = vn->userdata;

			memcpy( &prefs.xpkid, ps->id, 4 );
			prefs.xpkmode = ps->mode;
		}
	}

	LibDeletePool( packselpool );

	ogreExitWindow( ogw );

}

static char xpkpwbuff[ 64 ];
static char xpkpwbuff_old[ 64 ];
void makexpkpw( void )
{
	sprintf( xpkpwbuff_old, "!%ldMD%ld", prefs.passwordcrc, registerinfo.serie );
	sprintf( xpkpwbuff, "!42MD%ld", registerinfo.serie );
}

#define MPW ( prefs.do_packmsg == PACKMODE_XPKPW )

int xpkpack( void *from, void *to, int size )
{
	int rc;
	char xpkerror[ 80 ];
	long outlen = 0;
	char xpkid[ 8 ];

	if( !XpkBase )
	{
		xpknotinstalled();
		return( -1 );
	}

	xpkid[ 4 ] = 0;
	memcpy( xpkid, &prefs.xpkid, 4 );

	rc = XpkPackTags( 
		XPK_InBuf, from,
		XPK_InLen, size,
		XPK_GetError, xpkerror,
		XPK_OutBuf, to,
		XPK_OutBufLen, MAILBFSIZE + 2048,
		XPK_GetOutLen, &outlen,
		XPK_PackMode, prefs.xpkmode,
		XPK_PackMethod, xpkid,
		MPW ? XPK_Password : XPK_Ignore, xpkpwbuff,
		TAG_DONE	
	);

	if( rc )
	{
		if( rc != XPKERR_EXPANSION )
			askreq( "XPK-Fehler\n%s", "Abbruch", xpkerror );
		return( 0 );
	}
	return( outlen );
}

int xpkunpack( void *from, void *to, int insize )
{
	int rc;
	char xpkerror[ 80 ];
	long outlen = 0;

	if( !XpkBase )
	{
		xpknotinstalled();
		return( -1 );
	}

	rc = XpkUnpackTags( 
		XPK_InBuf, from,
		XPK_InLen, insize,
		XPK_OutBuf, to,
		XPK_OutBufLen, MAILBFSIZE + 256,
		XPK_GetError, xpkerror,
		XPK_GetOutLen, &outlen,
		MPW ? XPK_Password : XPK_Ignore, xpkpwbuff,
		TAG_DONE	
	);

	if( rc && ( MPW ) )
	{
		rc = XpkUnpackTags( 
			XPK_InBuf, from,
			XPK_InLen, insize,
			XPK_OutBuf, to,
			XPK_OutBufLen, MAILBFSIZE + 256,
			XPK_GetError, xpkerror,
			XPK_GetOutLen, &outlen,
			MPW ? XPK_Password : XPK_Ignore, xpkpwbuff_old,
			TAG_DONE	
		);
	}

	if( rc )
	{
		askreq( "XPK-Fehler\n%s", "Abbruch", xpkerror );
		return( 0 );
	}
	return( outlen );
}
