#include "watch.h"
#include "watchthor_rev.h"

static UBYTE *version_string = VERSTAG;

/*  Prototypes for external functions  */

struct Node * FindiName(struct TaskData *td, struct List *list, STRPTR name);
BOOL SetupTime(struct TaskData *td, UBYTE **error);
void CloseTime(struct TaskData *td);
void TimeRequest(struct TaskData *td, ULONG mins);
LONG myEasyRequest(struct IntuitionBase *IntuitionBase, struct Window *w, struct EasyStruct *es, ULONG *ip, ULONG arg1, ...);
struct Window * GetFrontScreenWindow(struct IntuitionBase *IntuitionBase);

UBYTE *template = "SYSTEMNAME=SYSTEM,CHECKDELAY=PERIODIC/N,CONFERENCE=CONF/K,RUNCOMMAND=CMD/K,USAGE/S";

enum {
	TEM_BBSNAME,
	TEM_CHECKDELAY,
	TEM_CONFNAME,
	TEM_COMMAND,
	TEM_USAGE,
	TEM_NUMBEROF
};

LONG __saveds NoName(void)
{
	TEXT envbuf[256];
	struct TaskData TaskData, *td;
	struct RDArgs *rdargs = NULL;
	LONG array[TEM_NUMBEROF], retval = RETURN_FAIL, n;
	struct List *bbslist = NULL, *conflist = NULL;
	BOOL terminated = FALSE;
	ULONG signal, signalmask, checkdelay, oldlastmail;
	struct BBSListItem	*mybbs;
	struct ConfListItem	*myconf;
	UBYTE				*errmsg = NULL;
	struct IntuitionBase *IntuitionBase = NULL;

	/*
		This program is meant to be pure so we have all data that would
		normally be global in a separate taskdata structure, which we
		initialize here
	*/

	setmem(td = &TaskData, sizeof(struct TaskData), 0);
	
	SysBase = *(struct ExecBase **)4L;

	if(!(DOSBase = (struct DosLibrary *) OpenLibrary(DOSNAME, 0L)))
	{
		errmsg = "missing library";		/* Should never happen */
		retval = 10000L;
		goto quit;
	}
	if(DOSBase->dl_lib.lib_Version < 37)
	{
		errmsg = "Needs Kick V37+";
		goto quit;
	}

	if(!(UtilityBase = OpenLibrary("utility.library", 37L)))
	{
		errmsg = "Needs utility.library V37+";
		goto quit;
	}

	if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 37L)))
	{
		errmsg = "Needs intuition.library V37+";
		goto quit;
	}

	/* Open bbsread.library relative to the directory THOR resides in */

	if(GetVar(ENV_THORPATH, envbuf, 255, GVF_GLOBAL_ONLY) != -1)
	{
		if(AddPart(envbuf, "libs/" BBSREADNAME, 200))
		{
			BBSReadBase = OpenLibrary(envbuf, 3L);
		}
	}
	if(!BBSReadBase) 
	{
		if(!(BBSReadBase = OpenLibrary(BBSREADNAME, 3L)))
		{
			errmsg = "Needs bbsread.library V3+";
			goto quit;
		}
	}

	for(n = 0; n < TEM_NUMBEROF; array[n++] = 0L);

	if(!(rdargs = ReadArgs(template, array, NULL)))
	{
		errmsg = "Error in arguments.";
		goto quit;
	}

	if(array[TEM_USAGE] || !array[TEM_BBSNAME]) 
	{
		errmsg = "Usage: WatchTHOR [SYSTEMNAME] [CONFNAME] [CHECKDELAY] [RUNCOMMAND] [USAGE]\n       Copyright (C) 1995 Ultima Thule Software, All Rights Reserved.\n       Author: Petter Nilsen.";
		retval = RETURN_OK;
		goto quit;
	}

	/* Set up how often it should check for new mail */

	checkdelay = array[TEM_CHECKDELAY] ? *((ULONG *)array[TEM_CHECKDELAY]) : 5;

	if(checkdelay == 0)
		checkdelay = 1;

	/* Get a list of systems configured in THOR */

	if(!(bbslist = GetBBSList())) { errmsg = "Error getting bbslist."; goto quit; }

	/* Find our system to watch */

	if(!(mybbs = (struct BBSListItem *)FindiName(td, bbslist, (STRPTR) array[TEM_BBSNAME])))
	{
		errmsg = "Unknown system";
		goto quit;
	}

	/* Get a list of conferences on this system */

	if(!(conflist = GetConfList(mybbs))) { errmsg = "Error getting conflist."; goto quit; }

	/* Find our conference to watch */

	if(!(myconf = (struct ConfListItem *)FindiName(td, conflist, array[TEM_CONFNAME] ? (STRPTR)array[TEM_CONFNAME] : (STRPTR)"EMail")))
	{
		errmsg = "Unknown conference";
		goto quit;
	}

	/* Setup timer */

	if(!(SetupTime(td, &errmsg)))
		goto quit;


	/* 
		We only need to monitor the last message in that conference, 
		when it changes, new messages have arrived
	*/

	oldlastmail = myconf->cl_Internal->ci_LastMsg;

	/* Start the first timer request */

	TimeRequest(td, checkdelay);

	/* Set up the signal mask for Wait() */

	signalmask = (1 << timerport->mp_SigBit | SIGBREAKF_CTRL_C);

	while(!terminated)
	{
		signal = Wait(signalmask);

		if(signal & SIGBREAKF_CTRL_C)
		{
			terminated = TRUE;
        }
		if(signal & (1 << timerport->mp_SigBit))
		{
			/* 
				Update our conference pointer to notice any changes
				in the structure. It will not work otherwise!
			*/

			UpdateDataStructTags(UD_ConfItem, myconf, TAG_DONE);

			if(myconf->cl_Internal->ci_LastMsg != oldlastmail)
			{
				struct EasyStruct es;
				STRPTR text = "%ld new messages have arrived in \n"
							"conference '%s' on system '%s'";

				if(array[TEM_COMMAND])
				{
					System((STRPTR)array[TEM_COMMAND], TAG_DONE);		
				}
				else
				{
					es.es_StructSize = sizeof(struct EasyStruct);
					es.es_Flags = 0L;
					es.es_Title = "WatchTHOR Notification";
					es.es_TextFormat =  text; 
					es.es_GadgetFormat = "Ok";

					myEasyRequest(IntuitionBase, GetFrontScreenWindow(IntuitionBase), &es, NULL,
									myconf->cl_Internal->ci_LastMsg - oldlastmail,
									myconf->cl_Data->cd_Name,
									mybbs->bl_Data->bd_Name);

				}
				oldlastmail = myconf->cl_Internal->ci_LastMsg;
			
			}

			/* Done with this request, start a new one */

			TimeRequest(td, checkdelay);
        }
	}


done:   /*  All stuff is done  */

	retval = RETURN_OK;

	Flush(Output());

quit:
	CloseTime(td);

	if(errmsg)
	{
		Printf("%s\n", errmsg);
	};

	Flush(Output());

	if(conflist) FreeBRObject(conflist);
	if(bbslist) FreeBRObject(bbslist);
	if(rdargs) FreeArgs(rdargs);
	CloseLibrary(BBSReadBase);
	CloseLibrary((struct Library *)IntuitionBase);
	CloseLibrary((struct Library *)UtilityBase);
	CloseLibrary((struct Library *)DOSBase);
	return(retval);
}

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

struct Node * FindiName(struct TaskData *td, struct List *list, STRPTR name)
{
	struct Node *node = (struct Node *) &list->lh_Head;

	while((node = node->ln_Succ)->ln_Succ)
	{
		if(!Stricmp(name, node->ln_Name)) return(node);
	}
	return(NULL);
}

LONG myEasyRequest(
	struct IntuitionBase *IntuitionBase,
	struct Window *w,
	struct EasyStruct *es,
	ULONG *ip,
	ULONG arg1, ...)
{
	return(EasyRequestArgs(w, es, ip, &arg1));
}

/**************************************************/
/******************* Timer stuff ******************/
/**************************************************/

BOOL SetupTime(struct TaskData *td, UBYTE **error)
{
	if(!(timerport = CreateMsgPort()))
	{
		*error = "Couldn't create message port.";
		return(FALSE);
	}
	timerio = (struct timerequest *)CreateIORequest(timerport, sizeof(struct timerequest));

	if(OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest *)timerio, 0))
	{
		*error = "Couldn't open timer device.";
		return(FALSE);
	}
	return(TRUE);
}

void CloseTime(struct TaskData *td)
{
	if(timerport)
	{
		if(timerio)
		{
			AbortIO((struct IORequest *)timerio);
			WaitIO((struct IORequest *)timerio);
			CloseDevice((struct IORequest *)timerio);
			DeleteIORequest((struct IORequest *)timerio);
			timerio = NULL;
		}
		DeleteMsgPort(timerport);
		timerport = NULL;
	}
}

void TimeRequest(struct TaskData *td, ULONG mins)
{
	timerio->tr_node.io_Command	= TR_ADDREQUEST;
	timerio->tr_time.tv_secs	= (60 * mins);
	timerio->tr_time.tv_micro	= 0;
	SendIO((struct IORequest *)timerio);
}

struct Window * GetFrontScreenWindow(struct IntuitionBase *IntuitionBase)
{
	struct Screen *actscr;
	ULONG iblock;

	iblock = LockIBase(0L);
	actscr = IntuitionBase->ActiveScreen;
	UnlockIBase(iblock);

	return(actscr->FirstWindow);
}
