#include <exec/types.h>
#include <stdio.h>
#include <intuition/intuition.h>

/* set up the structure with forward and backward pointers */
struct addr {
	char name[31];
	char street[41];
	char city[21];
	char state[3]; 
	char zip[10];
        char phone[11];
	struct addr *next; 
	struct addr *prior; 
} name_card; 

struct addr *start; /* pointer to first entry in list */
struct addr *last;  /* pointer to last entry in list */

/* Define an Intuition Structure    */
struct IntuitionBase *IntuitionBase;

/* Define a Graphics Structure      */
struct GfxBase *GfxBase; 

/* Define a structure to get messages from Intuition through the IDCMP */
struct IntuiMessage *message;

/* Intuition and Graphics revision of 0 means that any version of the
   operating system (1.0, 1.1, or 1.2) are acceptable                  */
#define INTUITION_REV 0
#define GRAPHICS_REV  0

#include "Header2.c"

char Enter_Text[] = "Enter Information To Add";
char Search_Text[] = "Enter Name To Find";
char Delete_Text[] = "Enter Name To Delete";
char Variable_Text[41];

static struct IntuiText DisplayText = {
 2,0,JAM2,
 0,0,
 NULL,
 Variable_Text,
 NULL
};

void Op_Main(), Cl_Main(), delall(), display_list();
void clear_strings(), search(), delete();
int Load(), Save(), Alt_Window(), enter(), list();
struct addr *find_it(); 

struct Window *MainWindow, *SubWindow, *ListWindow;
struct Menu *MainMenu = &W1Menu1;

void main() {
	ULONG  MIClass;
	USHORT MIGadID,MICode,WhichItem,Quit_Flag = 0,Menu_Selected=0;
	int return_code = 0, Window_Function = 0;
	struct Gadget *MIGad;

	IntuitionBase=(struct IntuitionBase *) 
		OpenLibrary("intuition.library",INTUITION_REV);

	if (IntuitionBase == NULL) exit(FALSE);
        
	GfxBase=(struct GfxBase *)
		OpenLibrary("graphics.library",GRAPHICS_REV);

	if (GfxBase == NULL) exit(FALSE);

	/* Open the Main Window and attach menustrip */
	Op_Main();

	/* initialize the start of the list */ 
	start=0;

	/* The Main Processing Loop */
	do { /* Wait until the IDCMP says that the user did something */ 
		Wait(1<<MainWindow->UserPort->mp_SigBit);
  
		while(message = (struct IntuiMessage *)
				GetMsg(MainWindow->UserPort)) {
			/* Decipher the message received from the IDCMP */
			MIClass = message->Class;
			MICode  = message->Code;
			MIGad   = (struct Gadget *)message->IAddress;
			MIGadID = MIGad->GadgetID;
			ReplyMsg(message);

			if(MIClass == MENUPICK) {
				if(MICode != MENUNULL) {
					WhichItem = ITEMNUM(MICode);
					Menu_Selected = 1;
				}
			}

			switch (MIClass) {
				case GADGETDOWN:
					break;
				case GADGETUP:
					switch (MIGadID) {
						case 1: /* Enter */
						 Window_Function = 1;
			                         return_code = 
						   Alt_Window(Window_Function);
						 break;
						case 2: /* Search */
						 Window_Function = 2;
						 return_code = 
						   Alt_Window(Window_Function);
						 break;
						case 3: /* List */
						 return_code = list();
						 break;
						case 4: /* Delete  */
						 Window_Function = 4;
						 return_code = 
						   Alt_Window(Window_Function);
						 break;
						default:
						 break;
					} /* Gadget Switch */
					break;
				case MENUPICK:
					if (Menu_Selected == 0) break;
					switch(WhichItem) {
					case 0: /* Load the namelist */
						return_code = Load();
						break;
					case 1: /* Save the namelist */
					/* disabled for Jumpdisk */
					DisplayBeep(NULL);
					/*****	Save(); ******/
						break;
					case 2: /* Quit the program */
						Quit_Flag = 1;
						break;
					default: /* Unknown menu selection */
						break;
					} /* Menu Switch */
					Menu_Selected = 0;
					break;
				default:
					break;
			} /* IDCMP selection switch */
		} /* end GetMsg loop */
	} while (Quit_Flag == 0);
	Cl_Main();
	CloseLibrary(GfxBase);
	CloseLibrary(IntuitionBase);
	delall();
	exit(TRUE);
}  /* End of main procedure */

/* Close Main Window and clear the menu strip */
void Cl_Main()
{
	while(message = (struct IntuiMessage *) GetMsg(MainWindow->UserPort)) {
		ReplyMsg(message);
	}
	ClearMenuStrip(MainWindow); 
	CloseWindow(MainWindow);
}

/* Open Main Window and attach menu strip */
void Op_Main()
{
	if ((MainWindow=(struct Window *)
	OpenWindow(&W1NewWindowStructure1)) == NULL) {
		exit(FALSE);
	}
	SetMenuStrip(MainWindow, MainMenu);
}

int Load()
{
	register int t, size; 
	struct addr *info, *temp; 
	char *p, *malloc(); 
	FILE *fp; 
 
	temp=0;

	if((fp=fopen("namelist","r"))==0) return(99); 
 
	delall(); /* Get rid of any previously allocated lists */ 
	size=sizeof(name_card); 
	start=(struct addr *)malloc(size); 
	if(!start) return(98);

	info=start; 
	p=(char *)info; /* convert to char pointer */ 
 
	while((*p++=getc(fp))!=EOF) { /* keep reading until EOF */ 
		for(t=0;t<size-1;++t)  /* scan a character at a time */
			*p++=getc(fp); 
		info->next=(struct addr *)malloc(size); 
		if(!info->next) return(97);
 
		info->prior=temp; 
		temp=info; 
		info=info->next; 
		p=(char *)info; 
	}
	free(temp->next); /* we do a free here since we've allocated 1 too many */
	temp->next=0; 
	last=temp; 
	start->prior=0; 
	fclose(fp); 
	return(0);
}

void delall() 
{ 
	struct addr *info; 
 
	info=start;  /* point to the start of the list                    */ 
	while(info) { /* keep going until we get to the end of the list   */ 
		start=info->next; /* save the pointer to the next entry   */ 
		free(info); /* free the memory of the entry               */ 
		info=start; /* make info point to the same place as start */ 
        }
	start=0; /* initialize the start of the list */ 
}

int Save()
{
	register int t, size; 
	struct addr *info; 
	char *p; 
	FILE *fp; 

	if((fp=fopen("namelist","w"))==0) return(99); 

	size=sizeof(name_card); 
	info=start; 

	while(info) { 
		p=(char *)info; 
		for(t=0;t<size;++t) 
			putc(*p++,fp); 
		info=info->next; 
	} 
	putc(EOF,fp); /* write an explicit EOF marker */ 
	fclose(fp); 
	return(0);
}

/* Open alternate window and listen for events */
int Alt_Window(Window_Function)
int Window_Function;
{
	ULONG  MIClass;
	USHORT MIGadID,Quit_Flag = 0;
	struct Gadget *MIGad;
	int return_code = 0;

	if(Window_Function<1 || Window_Function>4) return(99);

	Cl_Main();

	if((SubWindow=(struct Window *)
		OpenWindow(&W2NewWindowStructure2)) == NULL) {
		Op_Main();
		return(98);
	}
	clear_strings();

	/* Put the appropriate Title above the window */
	switch(Window_Function) {
		case 1:
		 SetWindowTitles(SubWindow,Enter_Text,-1);
		 break;
		case 2:
		 SetWindowTitles(SubWindow,Search_Text,-1);
		 break;
		case 4:
		 SetWindowTitles(SubWindow,Delete_Text,-1);
		 break;
		default:
		 break;
	}

	/* Print all text items in the subwindow */
	PrintIText(SubWindow->RPort,&W2IText10,0,0);

	/* Activate the first gadget */
	ActivateGadget(&W2Name,SubWindow,NULL);

	do { /* Wait until the IDCMP says that the user did something */ 
		Wait(1<<SubWindow->UserPort->mp_SigBit);

		while(message = (struct IntuiMessage *)
				GetMsg(SubWindow->UserPort)) {
		  MIClass = message->Class;
		  MIGad   = (struct Gadget *)message->IAddress;
		  MIGadID = MIGad->GadgetID;
		  ReplyMsg(message);

		  switch (MIClass) {
 		  case GADGETDOWN:
			break;
		  case GADGETUP:
			switch (MIGadID) {
			case 11:
				switch (Window_Function) {
                           	case 1:
				 ActivateGadget(&W2Address,SubWindow,NULL);
				 break;
				case 2:
				 search(W2W2NameSIBuff);
				 break;
				case 3:
				 delete(W2W2NameSIBuff);
				 break;
			        } /* Window_Function */
				break;
			case 12:
				ActivateGadget(&W2City,SubWindow,NULL);
				break;
			case 13:
				ActivateGadget(&W2St,SubWindow,NULL);
				break;
			case 14:
				ActivateGadget(&W2Zip,SubWindow,NULL);
				break;
			case 15:
				ActivateGadget(&W2Phone,SubWindow,NULL);
				break;
			case 16: /* Last gadget. Process When
					 user presses enter */
				if(Window_Function == 1)
					return_code = enter();
				if (!return_code) Quit_Flag = 1;
					clear_strings();
				ActivateGadget(&W2Name,SubWindow,NULL);
				break;
			case 17: /* OK - process the screen */
				switch(Window_Function) {
				case 1: /* the user wishes to enter */
					return_code = enter();
					if (!return_code) Quit_Flag = 1;
					clear_strings();
				   	ActivateGadget(&W2Name,SubWindow,NULL);
					break;
				case 2: /* the user wishes to search */
					search(W2W2NameSIBuff);
					break;
				case 4: /* the user wishes to delete */
					delete(W2W2NameSIBuff);
					break;
					default: /* should never get here */
				break;
				} /* case 17 switch */
				break; 
			case 18: /* Cancel */
				Quit_Flag = 1;
				break;
			default:   /* Should never get in here */
                        	break;
			} /* Gadget Switch */
		  		break;
		  default:
			break;
		  } /* IDCMP selection switch */
		} /* end GetMsg loop */
	} while (Quit_Flag == 0);

	CloseWindow(SubWindow);
	Op_Main();
}

/* clear all of the strings and reset screen */
void clear_strings()
{
	char *stpcpy();
	char *p;
	LONG gad_pos, real_pos;
	int i;

	gad_pos = RemoveGList(SubWindow,&W2Name,1L);
	p = W2W2NameSIBuff;
	for(i=1;i<30;i++) p = stpcpy(p,NULL);
	real_pos = AddGList(SubWindow,&W2Name,gad_pos,1L,(LONG)NULL);
	RefreshGList(&W2Name,SubWindow,(LONG)NULL,1L);

	gad_pos = RemoveGList(SubWindow,&W2Address,1L);
	p = W2W2AddressSIBuff;
	for(i=1;i<40;i++) p = stpcpy(p,NULL);
	real_pos = AddGList(SubWindow,&W2Address,gad_pos,1L,(LONG)NULL);
	RefreshGList(&W2Address,SubWindow,(LONG)NULL,1L);

	gad_pos = RemoveGList(SubWindow,&W2City,1L);
	p = W2W2CitySIBuff;
	for(i=1;i<20;i++) p = stpcpy(p,NULL);
	real_pos = AddGList(SubWindow,&W2City,gad_pos,1L,(LONG)NULL);
	RefreshGList(&W2City,SubWindow,(LONG)NULL,1L);

	gad_pos = RemoveGList(SubWindow,&W2St,1L);
	p = W2W2StSIBuff;
	for(i=1;i<2;i++) p = stpcpy(p,NULL);
	real_pos = AddGList(SubWindow,&W2St,gad_pos,1L,(LONG)NULL);
	RefreshGList(&W2St,SubWindow,(LONG)NULL,1L);

	gad_pos = RemoveGList(SubWindow,&W2Zip,1L);
	p = W2W2ZipSIBuff;
	for(i=1;i<9;i++) p = stpcpy(p,NULL);
	real_pos = AddGList(SubWindow,&W2Zip,gad_pos,1L,(LONG)NULL);
	RefreshGList(&W2Zip,SubWindow,(LONG)NULL,1L);

	gad_pos = RemoveGList(SubWindow,&W2Phone,1L);
	p = W2W2PhoneSIBuff;
	for(i=1;i<10;i++) p = stpcpy(p,NULL);
	real_pos = AddGList(SubWindow,&W2Phone,gad_pos,1L,(LONG)NULL);
	RefreshGList(&W2Phone,SubWindow,(LONG)NULL,1L);
}

/* allocate and store one name occurance */
int enter() 
{ 
	struct addr *info; 
	char *malloc(), *strcpy();
	char *p;

	/* allocate memory for one more addition to list */
	info=(struct addr *)malloc(sizeof(name_card)); 
	if(info==0) return(99); 

	/* move the information from the screen buffers to the structure */
	p = strcpy(info->name,W2W2NameSIBuff);
	p = strcpy(info->street,W2W2AddressSIBuff);
	p = strcpy(info->city,W2W2CitySIBuff);
	p = strcpy(info->state,W2W2StSIBuff);
	p = strcpy(info->zip,W2W2ZipSIBuff);
	p = strcpy(info->phone,W2W2PhoneSIBuff);

	if(start!=0) { /* not the first entry in the list */ 
	  last->next=info;  /* update the forward pointer */
	  info->prior=last; /* update the backward pointer */
	  last=info;        /* set the last pointer */
	  last->next=0;     /* mark the end of the list */
	} 
	else {  /* this is the first entry in the list */ 
	  start=info;      /* set a new head of list */
	  start->next=0;   /* set the end of the list */
	  last=start;      /* mark the end of the list */
	  start->prior=0;  /* mark the beginning of the list */
	} 
}

/* list all of the element in their own window */
int list() 
{ 
	ULONG  MIClass;
	int name_counter = 0, filled_up = 0, Quit_Flag = 0, x_pos = 4, y_pos = 11;
	struct addr *info;
 
	if ((ListWindow=(struct Window *)
			OpenWindow(&W3NewWindowStructure3)) == NULL) {
		return(98);
	}

	info=start; /* set up the head of the list */

	while(info && !filled_up) { 
		name_counter++;
		/* the function will handle printing */
		display_list(info,x_pos,y_pos);

		/* Reposition our "text cursor" to print 2 columns of 4 names */
		if(name_counter != 4) y_pos = y_pos + 40;
		else {
			x_pos = 320;
			y_pos = 11;
		}

		/* Setting filled_up to a non-zero will drop us out of the loop */
		if (name_counter >= 8) filled_up = 1;

		info=info->next; /* after printing, point to the next one */
	}
	/* If there are no more items in the list, tell the user, otherwise
	print a message tell them to click the moue buttons to continue */
	if(!info) PrintIText(ListWindow->RPort,&W3IText17,0,0);
	else      PrintIText(ListWindow->RPort,&W3IText16,0,0);


	do { /* Wait until the IDCMP says that the user did something */ 
		Wait(1<<ListWindow->UserPort->mp_SigBit);
  
		while(message = (struct IntuiMessage *)
				GetMsg(ListWindow->UserPort)) {
			MIClass = message->Class;
			ReplyMsg(message);

			switch (MIClass) {
			case CLOSEWINDOW:
				Quit_Flag = 1;
				break;
			case MOUSEBUTTONS:
			/* if there is nothing more to display, just loop around */
				if (!info) break;

				/* Clear our text screen */
                                Move(ListWindow->RPort,0,0);
				ClearScreen(ListWindow->RPort);

				/* Set up our variables necessary for display */
				x_pos = 4;
				y_pos = 11;
				name_counter = 0; 
				filled_up = 0;

				while(info && !filled_up) { 
				 name_counter++;
				 display_list(info,x_pos,y_pos);
				 if(name_counter != 4) y_pos = y_pos + 40;
				 else {
					x_pos = 324;
					y_pos = 11;
				 }
				 if (name_counter >= 8) filled_up = 1;
				 info=info->next;
				} 

		    		if(!info)
				 PrintIText(ListWindow->RPort,&W3IText17,0,0);
		     		else
				 PrintIText(ListWindow->RPort,&W3IText16,0,0);
                   
				/* This loop clears out any intuition messages
				that may have accumlated while we were away
				printing. We'll assume the user did anything
				by accident at this point and just throw
				the messages away. */
				while(message = (struct IntuiMessage *)
						GetMsg(ListWindow->UserPort)) {
					ReplyMsg(message);
				}
				break;
			default:
				break;
			} /* IDCMP selection switch */
		} /* end GetMsg loop */
	} while (Quit_Flag == 0);

	CloseWindow(ListWindow);
} /* end list function */
 
void display_list(info,x_pos,y_pos) 
struct addr *info;
int x_pos,y_pos; 
{ 
	char *p;

	p = (char *)strcpy(Variable_Text,info->name);
	PrintIText(ListWindow->RPort,&DisplayText,x_pos,y_pos);

	p = (char *)strcpy(Variable_Text,info->street);
	PrintIText(ListWindow->RPort,&DisplayText,x_pos,y_pos+9);

	p = (char *)strcpy(Variable_Text,info->city);
	PrintIText(ListWindow->RPort,&DisplayText,x_pos,y_pos+18);

	p = (char *)strcpy(Variable_Text,info->state);
	PrintIText(ListWindow->RPort,&DisplayText,x_pos+160,y_pos+18);

	p = (char *)strcpy(Variable_Text,info->zip);
	PrintIText(ListWindow->RPort,&DisplayText,x_pos+186,y_pos+18);

	p = (char *)strcpy(Variable_Text,info->phone);
	PrintIText(ListWindow->RPort,&DisplayText,x_pos,y_pos+27);
}

void search(name) 
char *name;
{ 
	struct addr *info,*find_it();
	LONG gad_pos, real_pos;
	char *p, *strcpy();

	if(!(info=find_it(name)))  
		DisplayBeep(NULL);
	else { /* If its found, move everthing to the panel */
		gad_pos = RemoveGList(SubWindow,&W2Name,1L);
		p = strcpy(W2W2NameSIBuff,info->name);
		real_pos = AddGList(SubWindow,&W2Name,gad_pos,1L,(LONG)NULL);
		RefreshGList(&W2Name,SubWindow,(LONG)NULL,1L);

		gad_pos = RemoveGList(SubWindow,&W2Address,1L);
		p = strcpy(W2W2AddressSIBuff,info->street);
		real_pos = AddGList(SubWindow,&W2Address,gad_pos,1L,(LONG)NULL);
		RefreshGList(&W2Address,SubWindow,(LONG)NULL,1L);

		gad_pos = RemoveGList(SubWindow,&W2City,1L);
		p = strcpy(W2W2CitySIBuff,info->city);
		real_pos = AddGList(SubWindow,&W2City,gad_pos,1L,(LONG)NULL);
		RefreshGList(&W2City,SubWindow,(LONG)NULL,1L);

		gad_pos = RemoveGList(SubWindow,&W2St,1L);
		p = strcpy(W2W2StSIBuff,info->state);
		real_pos = AddGList(SubWindow,&W2St,gad_pos,1L,(LONG)NULL);
		RefreshGList(&W2St,SubWindow,(LONG)NULL,1L);

		gad_pos = RemoveGList(SubWindow,&W2Zip,1L);
		p = strcpy(W2W2ZipSIBuff,info->zip);
		real_pos = AddGList(SubWindow,&W2Zip,gad_pos,1L,(LONG)NULL);
		RefreshGList(&W2Zip,SubWindow,(LONG)NULL,1L);

		gad_pos = RemoveGList(SubWindow,&W2Phone,1L);
		p = strcpy(W2W2PhoneSIBuff,info->phone);
		real_pos = AddGList(SubWindow,&W2Phone,gad_pos,1L,(LONG)NULL);
		RefreshGList(&W2Phone,SubWindow,(LONG)NULL,1L);
	}
}

void delete(name) 
char *name;
{ 
	struct addr *info, *find_it(); 

	info=find_it(name); 
	if(info) { 
		if(start==info) { /* if we're deleting the first on the 
				 list, handle it differently */ 
			start=info->next;
			start->prior=0; 
		} 
                else { 
			info->prior->next=info->next; 
			if(info!=last) 
				info->next->prior=info->prior; 
			else
				last=info->prior; 
		}
		free(info); /* return the memory of the entry just deleted */ 
	}
	else DisplayBeep(NULL);
}

struct addr *find_it(name) 
char *name; 
{ 
	struct addr *info; 

	info=start;
	while(info) { /* keep going until we get to the end of the list */ 
		if(!strcmp(name,info->name)) return info; 
		info=info->next; 
	} 
	return(0); /* not found */
}
 /*** end of program ***/
