#import "myApp.h"
#import <streams/streams.h>
#import <utmp.h>

int find();
void enter();
void clear_marks();
void remove_unmarked();

@implementation myApp

void who(DPSTimedEntry teNumber, double now, char *userData)

/* Call this function via the DPS Timed Entry */

{
struct utmp temp;			/* Utmp structure. See utmp.h */

	clear_marks();					/* Clear marked */
	utmpFile = NXMapFile("/etc/utmp", NX_READONLY);	/* Map utmp file into memory */
	if (utmpFile == NULL)
	{
		exit(0);
	}
	while( NXRead(utmpFile, &temp, sizeof(struct utmp)) !=0 )	/* Read next entry */
	{
		if (temp.ut_name[0] != '\000')			/* Is is a real user? */
			enter(temp.ut_line, temp.ut_name);	/* Yes, enter or affirm in list */
	}
	remove_unmarked();					/* Remove all un-referenced entries in 
								   the list */

	NXClose(utmpFile);					/* Close utmp file */
}

-init
{

	nextX = nextY = 0;			/* Init Icon Position coordinates */
	last = users = NULL;			/* Initialize List pointers */

	DPSAddTimedEntry((double)5.0, who, NULL, NX_BASETHRESHOLD);

	c_self = self;				/* Fudge.  C calls seem to need this */
	return(self);
}

-newIconUser: (const char *)name tty: (const char *)ttystr xcoord: (float)x ycoord: (float)y
{
NXRect windowRect;

	iconWindow = [Window alloc];			/* Get a window instance */

	/* Calulate Screen Coordinates */
	windowRect.origin.x = 4.0 + 64.0 * x;
	windowRect.origin.y = 0.0 + 64.0 * y;
	windowRect.size.height = windowRect.size.width = 64.0; /* Icon size 64x64 */

	/*Init the window content */
	[iconWindow initContent: &windowRect style: NX_PLAINSTYLE
		 backing: NX_BUFFERED buttonMask:0  defer: YES];

	/* Get an IconView Instance */
	icon = [[IconView alloc] init];

	/* Set IconView as the window's contentView */
	[iconWindow setContentView: icon];

	[iconWindow setDelegate:icon];		/* Make view the window's delegate */
	[iconWindow makeFirstResponder:icon];	/* and first responder */
	
	/* Add to window list */
	[iconWindow makeKeyAndOrderFront:self];	
 
	[icon iconSetName: name];		/* Set icon variables */
	[icon iconSetTty: ttystr];

	return iconWindow;
}

void enter(tty,name)
char *tty, *name;
{
struct record *temp;


	if (find(tty, name)==0)		/* If new entry, malloc space and put in list */
	{
		temp = (struct record *) malloc(sizeof (struct record ));
		temp->next = NULL;

		/* New Icon */
		temp->windowPointer = [c_self newIconUser: name tty: tty 
					  xcoord: (float)nextX ycoord:(float) nextY];

		temp->x = (float)nextX;	/* Position Icon in "dock" */
		temp->y = (float)nextY;
		temp->marked = 1;	/* Mark icon as referenced */

		strcpy(temp->name, name);  /* User name */
		strcpy(temp->tty, tty);	   /* TTY name */

		if (last == NULL)	/* First entry in list (usually console) */
		{
			users = temp;
			last = temp;
		}
		else			/* Not furst entry in list */
		{
			last->next = temp;
			last = temp;
		}

		nextY++;		/* Update coordinate for next icon */
		if (nextY>=13)
		{
			nextY = 0;
			nextX++;
		}
	}
}

void clear_marks()		/* Simply traverse list and clear "marked" item in struct */
{
struct record *temp;

	temp = users;
	while (temp!=NULL)
	{
		temp->marked = 0;
		temp = temp->next;
	}
}

void remove_unmarked()		/* Remove all items from the list which have not been referenced */
{
struct record *temp,*prev;

	nextX = nextY = 0;
	temp = users;
	prev = temp;
	while (temp!=NULL)
	{
		if (temp->marked == 0) 			/* Standard linked list removal algorithm */
		{
			if (temp == users)		/* Remove head item */
			{
				users = temp->next;
				[temp->windowPointer free];
				free(temp);
				temp = users->next;
			}
			if (temp == last)		/* Remove last item */
			{
				last  = prev;
				prev -> next = NULL;
				[temp->windowPointer free];
				free(temp);
				temp = NULL;
			}
			else				/* Remove internal item */
			{
				prev->next = temp->next;
				[temp->windowPointer free];
				free(temp);
				temp = prev->next;
			}
		}
		else
		{
			temp->x = 4.0 + 64.0 * (float) nextX;	/* Calulate Screen Coordinates */
			temp->y = 0.0 + 64.0 * (float) nextY;

			/* Reposition icon to new location */
			[temp->windowPointer moveTo: temp->x : temp->y];
			[[temp->windowPointer contentView] display];

			nextY++;	/* Calculate next icon position */
			if (nextY>13) 
			{
				nextY = 0;
				nextX++;
			}
			prev = temp;
			temp = temp->next;
		}
	}
}

int find(tty,name)	/* Return a 1 if record with "name" and "tty" exists in the list */
			/* Mark record as referenced so that it is not removed from the list */
char *tty,*name;
{
struct record *temp;

	temp = users;		/* Head of list */
	while(temp!=NULL)
	{
		if ((strcmp(temp->tty, tty)==0)&&(strcmp(temp->name,name) ==0))
		{
			temp->marked = 1;
			return(1);
		}
		temp = temp->next;
	}
	return(0);
}


@end
