/*
 *      Copyright (c) 1993-4 Michael D. Bayne.
 *      All rights reserved.
 *
 *      Please see the documentation accompanying the distribution for distribution and disclaimer
 *      information.
 */

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/ports.h>

#include <dos/dos.h>
#include <dos/dostags.h>

#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>

#include <libraries/reqtools.h>
#include <devices/timer.h>

#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/intuition_protos.h>
#include <clib/graphics_protos.h>
#include <clib/utility_protos.h>
#include <clib/reqtools_protos.h>
#include <clib/alib_protos.h>

#include <pragmas/exec_pragmas.h>
#include <pragmas/dos_pragmas.h>
#include <pragmas/intuition_pragmas.h>
#include <pragmas/graphics_pragmas.h>
#include <pragmas/utility_pragmas.h>
#include <pragmas/reqtools_pragmas.h>

#include <stdlib.h>

#include "Blanker.h"
#include "Garshneblanker_rev.h"
#include "defs.h"

STATIC const UBYTE VersTag[] = VERSTAG;

#include "protos/main.h"
#include "protos/cxhand.h"
#include "protos/prefs.h"
#include "protos/winhand.h"
#include "protos/module.h"

#define OPENLIB( lb, lbn, v ) if(!( lb = OpenLibrary( lbn, v ))) exitb( 1L )
#define OPENLIBCAST( lb, lbn, v ) if(!( lb = ( struct lb * )OpenLibrary( lbn, v ))) exitb( 1L )

__far extern LONG RangeSeed;

LONG Blanking = FALSE, BlankAfterInit = FALSE;
LONG tags[] = { RT_Window, 0L, RT_LockWindow, TRUE, TAG_END, 0L, TAG_END };

struct IntuitionBase *IntuitionBase = 0L;
struct GfxBase *GfxBase = 0L;
struct ReqToolsBase *ReqToolsBase = 0L;
struct Library *CxBase = 0L, *GadToolsBase = 0L, *UtilityBase = 0L, *IconBase = 0L;
struct MsgPort *ServerPort = 0L, *TimerPort = 0L;
struct Task *ServerTask;
struct List *BlankerEntries, *ActiveEntries;
BlankerPrefs *Prefs;
struct rtHandlerInfo *ReqHandler = 0L;
struct timerequest *TimeOutIO;

LONG HandleServerMsg( VOID )
{
	ULONG PubScreenModes;
	BlankMsg *CurMsg;
	
	while( CurMsg = ( BlankMsg * )GetMsg( ServerPort ))
	{
		LONG Type = CurMsg->bm_Type;
		LONG Flags = CurMsg->bm_Flags;

		if( Flags & BF_REPLY )
		{
			if(!( Flags & BF_INTERNAL ))
				FreeVec( CurMsg );
		}
		else
		{
			CurMsg->bm_Flags |= BF_REPLY;
			ReplyMsg(( struct Message * )CurMsg );
		}
		
		switch( Type )
		{
		case BM_DOBLANK:
			if( Flags & BF_REPLY )
			{
				if( !CheckIO(( struct IORequest * )TimeOutIO ))
				{
					AbortIO(( struct IORequest * )TimeOutIO );
					WaitIO(( struct IORequest * )TimeOutIO );
					SetSignal( 0L, SIG_TIMER );
				}
				Blanking = TRUE;
			}
			break;
		case BM_INITMSG:
			Prefs->bp_Flags |= BF_VALIDMOD;
			if( BlankAfterInit )
			{
				BlankAfterInit = FALSE;
				MessageModule( BM_DOBLANK );
				Blanking = TRUE;
			}
			break;
		case BM_FAILED:
			Prefs->bp_Flags &= ~BF_VALIDMOD;
			Blanking = FALSE;
			Delay( 60 );
			MessageModule( BM_DOBLANK );
			break;
		case BM_SENDBLANK:
			if( Flags & BF_REPLY )
				break;
			PubScreenModes = SetPubScreenModes( 0L );
			if( Stricmp( Prefs->bp_Blanker, "Random" ))
			{
				if( !Blanking )
					MessageModule( BM_DOBLANK );
			}
			else
			{
				if( !Blanking || Prefs->bp_Flags & BF_REPLACE )
				{
					MessageModule( BM_DELAYEDQUIT );
					BlankAfterInit = TRUE;
					LoadModule( Prefs->bp_Dir, Prefs->bp_Blanker );
				}
			}
			SetPubScreenModes( PubScreenModes );
			break;
		case BM_SENDUNBLANK:
			if( Flags & BF_REPLY )
				break;
			if( Prefs->bp_Flags & BF_VALIDMOD )
				MessageModule( BM_UNBLANK );
			if( ServerScr )
			{
				UnblankMousePointer();
				CloseScreen( ServerScr );
				ServerScr = 0L;
			}
			Blanking = FALSE;
			break;
		default:
			break;
		}
	}

	return OK;
}

VOID exitb( LONG exitValue )
{
	if( exitValue != 3L )
	{
		MessageModule( BM_DOQUIT );

		if( ReqHandler )
			rtReqHandler( ReqHandler, 0L, RTRH_EndRequest, REQ_OK, TAG_END );

		CloseBlankerWindow();
		CloseDownScreen();
		
		FreeBlankerEntries( BlankerEntries );
		
		if( Prefs )
			FreeVec( Prefs );
		
		if( TimeOutIO )
		{
			if( TimeOutIO->tr_node.io_Device )
				CloseDevice(( struct IORequest * )TimeOutIO );
			DeleteExtIO(( struct IORequest * )TimeOutIO );
		}

		if( TimerPort )
			DeletePort( TimerPort );
		
		if( ServerPort )
			DeletePort( ServerPort );
		
		ShutdownCX();
	}

	if( UtilityBase )
		CloseLibrary( UtilityBase );
	if( ReqToolsBase )
		CloseLibrary(( struct Library * )ReqToolsBase );
	if( CxBase )
		CloseLibrary( CxBase );
	if( IconBase )
		CloseLibrary( IconBase );
	if( GfxBase )
		CloseLibrary(( struct Library * )GfxBase );
	if( GadToolsBase )
		CloseLibrary( GadToolsBase );
	if( IntuitionBase )
		CloseLibrary(( struct Library * )IntuitionBase );

	exit( exitValue );
}

VOID main( int argc, char *argv[] )
{
	LONG sigs;
	LONG retval;
	
	OPENLIBCAST( IntuitionBase, "intuition.library", 37L );
	OPENLIBCAST( GfxBase, "graphics.library", 37L );
	OPENLIB( IconBase, "icon.library", 37L );
	OPENLIB( GadToolsBase, "gadtools.library", 37L );
	OPENLIB( CxBase, "commodities.library", 37L );
	OPENLIBCAST( ReqToolsBase, REQTOOLSNAME, REQTOOLSVERSION );
	OPENLIB( UtilityBase, "utility.library", 37L );
	
	RangeSeed = ( LONG )( ServerTask = FindTask( 0L ));
	
	if( CheckCX() == QUIT )
		exitb( 3L );
	
	ServerPort = CreatePort( "GarshneServer", 0 );
	if( !ServerPort )
		exitb( 4L );

	TimerPort = CreatePort( 0L, 0 );
	if( !TimerPort )
		exitb( 4L );

	TimeOutIO = ( struct timerequest * )CreateExtIO( TimerPort, sizeof( struct timerequest ));
	if( !TimeOutIO )
		exitb( 5L );
	
	if( OpenDevice( "timer.device", UNIT_VBLANK, ( struct IORequest * )TimeOutIO, 0L ))
		exitb( 5L );
	
	Prefs = LoadDefaultPrefs();
	BlankerEntries = LoadBlankerEntries( Prefs->bp_Dir );
	if( !( Prefs->bp_Flags & BF_REPLACE ) || Stricmp( Prefs->bp_Blanker, "Random" ))
		LoadModule( Prefs->bp_Dir, Prefs->bp_Blanker );
	
	if( SetupCX() == QUIT )
		exitb( 6L );

	if( Prefs->bp_PopUp )
		retval = openMainWindow();
	
	do
	{
		sigs = Wait( SIG_CX | SIG_SERVWIN | SIGBREAKF_CTRL_C | SIG_SERVPORT | SIG_REQHANDLER | SIG_TIMER );
		
		if( sigs & SIG_SERVPORT )
			retval = HandleServerMsg();

		if( sigs & SIG_CX )
			retval = HandleCxMess();

		if( sigs & SIG_SERVWIN )
			retval = HandleBlankerIDCMP();

		if( sigs & SIGBREAKF_CTRL_C )
			retval = 0L;

		if( sigs & SIG_REQHANDLER )
		{
			if( rtReqHandler( ReqHandler, sigs, TAG_END ) != CALL_HANDLER )
			{
				FreeVec( InfoStr );
				InfoStr = 0L;
				ReqHandler = 0L;
			}
			retval = OK;
		}

		if( sigs & SIG_TIMER )
		{
			WaitIO(( struct IORequest * )TimeOutIO );
			MessageModule( BM_UNBLANK );
			InternalBlank();
		}

		if( retval == CLOSEWIN )
		{
			Prefs->bp_Left = BlankerWnd->LeftEdge;
			Prefs->bp_Top = BlankerWnd->TopEdge;
			CloseBlankerWindow();
			CloseDownScreen();
		}
	}
	while( retval );

	exitb( 0L );
}
