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

#include <exec/memory.h>

#include <dos/dos.h>

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

#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <clib/dos_protos.h>

#include <string.h>

#include "/defs.h"
#include "main.h"

LONG PortRemoved = FALSE, Blanking = FALSE, *ServerBlanking, GotPing;
ULONG  Seconds, Micros, LastTime;
struct IntuitionBase *IntuitionBase = 0L;
struct GfxBase *GfxBase = 0L;
struct Library *GarshnelibBase = 0L;
struct MsgPort *ClientPort;
VOID *CurPrefs;

extern __far LONG RangeSeed;

#define PREFSIZE 512

BYTE PrefsPath[128];

STRPTR NameSansParens( STRPTR Name )
{
	BYTE Buf[64], *Ptr;
	LONG Len = strlen( Name );

	strcpy( Buf, Name );

	if( Buf[Len - 1] == ')' )
	{
		for( Ptr = Buf; *Ptr != '('; Ptr++ );
		strcpy( Ptr, Ptr + 1 );
		Buf[Len - 2] = '\0';
	}

	return Buf;
}

VOID SavePrefs( VOID *Prefs )
{
	BPTR PrefFile;
	
	if( PrefFile = Open( PrefsPath, MODE_NEWFILE ))
	{
		Write( PrefFile, Prefs, PREFSIZE );
		Close( PrefFile );
	}
}

VOID *LoadPrefs( BYTE *PrefsName )
{
	BPTR PrefFile;
	VOID *Prefs;
	
	strcpy( PrefsPath, PrefsName );
	strcat( PrefsPath, ".prefs" );
	
	if( Prefs = AllocVec( PREFSIZE, MEMF_CLEAR ))
	{
		if( PrefFile = Open( PrefsPath, MODE_OLDFILE ))
		{
			if( Read( PrefFile, Prefs, PREFSIZE ) != PREFSIZE )
				FillDefaults( Prefs );
			Close( PrefFile );
		}
		else
			FillDefaults( Prefs );
	}
	
	return Prefs;
}

LONG MessageServer( LONG Type )
{
	struct MsgPort *ServerPort;
	BlankMsg *ClientMsg;
	
	if( ServerPort = FindPort( "GarshneServer" ))
	{
		if( ClientMsg = AllocVec( sizeof( BlankMsg ), MEMF_PUBLIC|MEMF_CLEAR ))
		{
			ClientMsg->bm_Mess.mn_ReplyPort = ClientPort;
			ClientMsg->bm_Mess.mn_Length = sizeof( BlankMsg );
			ClientMsg->bm_Type = Type;
			PutMsg( ServerPort, ( struct Message * )ClientMsg );
			
			return OK;
		}
	}
	
	return QUIT;
}

LONG HandleSignal( LONG Signal )
{
	BlankMsg *CurMsg;
	
	if( Signal & SIG_WIN )
		DoPrefs( IDCMP, CurPrefs );
	
	if( Signal & SIG_PORT )
	{
		while( CurMsg = ( BlankMsg * )GetMsg( ClientPort ))
		{
			LONG Type = CurMsg->bm_Type;
			LONG Flags = CurMsg->bm_Flags;
			
			if( Type == BM_DELAYEDQUIT )
			{
				RemPort( ClientPort );
				PortRemoved = TRUE;
				Delay( 60 );
			}
			
			ServerBlanking = ( LONG * )CurMsg->bm_Mess.mn_Node.ln_Name;
			
			if( Flags & BF_REPLY )
				FreeVec( CurMsg );
			else
			{
				CurMsg->bm_Flags |= BF_REPLY;
				ReplyMsg(( struct Message * )CurMsg );
			}
			
			switch( Type )
			{
			case BM_DOBLANK:
				if( !Blanking )
				{
					Blanking = TRUE;
					LastTime = 0L;
					switch( Blank( CurPrefs ))
					{
					case FAILED:
						MessageServer( BM_FAILED );
					case QUIT:
						return QUIT;
					default:
						Blanking = FALSE;
					}
				}
				return OK;
			case BM_DOPREFS:
				if( !SIG_WIN )
					DoPrefs( STARTUP, CurPrefs );
				break;
			case BM_UNBLANK:
				return UNBLANK;
			case BM_DELAYEDQUIT:
			case BM_DOQUIT:
				return QUIT;
			case BM_PING:
				GotPing = TRUE;
			default:
				break;
			}
		}
	}
	
	if( Signal & SIGBREAKF_CTRL_C )
	{
		MessageServer( BM_FAILED );
		return QUIT;
	}
	
	return OK;
}

LONG ContinueBlanking( VOID )
{
	LONG Sigs = SetSignal( 0L, SIG_PORT | SIGBREAKF_CTRL_C ), RetVal = OK;

	if( Sigs )
		RetVal = HandleSignal( Sigs );
	
	if( RetVal == OK && !*ServerBlanking )
		RetVal = UNBLANK;
	
	return RetVal;
}

int main( int argc, char *argv[] )
{
	BlankMsg *FreeMsg;
	static BYTE PortName[] = "GarshneClient";
	ULONG Seconds, Micros;
	LONG RetVal = 0;
	
	if( FindPort( PortName ))
		return 1;
	
	IntuitionBase =
		( struct IntuitionBase * )OpenLibrary( "intuition.library", 37L );
	GfxBase = ( struct GfxBase * )OpenLibrary( GRAPHICSNAME, 37L );
	GarshnelibBase = OpenLibrary( "Garshnelib.library", 37L );
	
	if( IntuitionBase && GfxBase && GarshnelibBase )
	{
		ClientPort = CreateMsgPort();
		
		if( ClientPort )
		{
			ClientPort->mp_Node.ln_Name = PortName;
			ClientPort->mp_Node.ln_Pri = 0L;
			AddPort( ClientPort );
			CurPrefs = LoadPrefs( NameSansParens( argv[0] ));
			
			CurrentTime( &Seconds, &Micros );
			RangeSeed = Seconds + Micros;
			
			if( MessageServer( BM_INITMSG ) == OK )
				while( HandleSignal( Wait( SIG_PORT | SIG_WIN |
										  SIGBREAKF_CTRL_C )) == OK );
			
			if( SIG_WIN )
				DoPrefs( KILL, CurPrefs );
			
			while( FreeMsg = ( BlankMsg * )GetMsg( ClientPort ))
			{
				if( FreeMsg->bm_Type & BF_REPLY )
					FreeVec( FreeMsg );
				else
				{
					FreeMsg->bm_Type |= BF_REPLY;
					ReplyMsg(( struct Message * )FreeMsg );
				}
			}
			
			if( CurPrefs )
				FreeVec( CurPrefs );
			
			if( !PortRemoved )
				RemPort( ClientPort );
			DeleteMsgPort( ClientPort );
		}
		else
			RetVal = 2;
	}
	else
		RetVal = 1;
	
	if( GarshnelibBase )
		CloseLibrary( GarshnelibBase );
	
	if( GfxBase )
		CloseLibrary(( struct Library * )GfxBase );
	
	if( IntuitionBase )
		CloseLibrary(( struct Library * )IntuitionBase );
	
	return RetVal;
}
