/*
 *  IRA : IRA Calculator
 *
 *    Version 2
 *
 *    by Joel Swank 9-26-89
 *
 */

/********* INCLUDES ************************ */


#include <exec/types.h>
#include <exec/io.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <intuition/intuition.h>
#include <stdio.h>
#include <ctype.h>
#include "fio.h"
#include "limits.h"


/* Data in helpwin.h  */
extern struct IntuiText prfailtxt ;
extern struct IntuiText badfiletxt ;
extern struct IntuiText fiofailtxt ;
extern struct IntuiText winfailtxt ;
extern struct IntuiText messagetxt ;
extern struct IntuiText infailtxt ;
extern struct IntuiText infailtxt2 ;
extern struct IntuiText oktxt ;
extern struct IntuiText cantxt ;
extern struct IntuiText retrytxt ;
extern struct NewWindow	NewWindowStructureHelp;
extern struct NewWindow	NewWindowStructure3;
extern char message_buff[];

/* Data in doargs.c   */
extern char filename[];

/* Defines for setting/clearing GADGDISABLED flag */
#define OffGad(gad) (gad).Flags = gad.Flags | GADGDISABLED
#define OnGad(gad) (gad).Flags = gad.Flags & ~(GADGDISABLED)
#define OffMenu(item) (item).Flags = item.Flags & ~(CHECKED)
#define OnMenu(item) (item).Flags = item.Flags | CHECKED



extern struct IntuitionBase *IntuitionBase ;
extern struct GfxBase *GfxBase ;
extern struct DosLibrary *DosBase ;

struct ViewPort vP;
struct Window *wG = NULL;
struct Window *wF = NULL;
struct RastPort *rpG;
struct IntuiMessage *message;	/* the message from the IDCMP */

struct Window *OpenWindow();
void *OpenLibrary();
struct IntuiMessage *GetMsg();
struct MenuItem *ItemAddress();

struct FileIOSupport *FIOSupp = NULL;      /* fileio support stuff */
struct FileIOSupport *GetFileIOSupport();
struct FileLock *Lock();
char save_title[] = "Select File to SAVE";
char load_title[] = "Select File to LOAD";

/* get the PowerWindows 2.0 code */
#include "ira.h"

/* internal data areas */
char balancemsg[] = "Invalid Balance";
char interestmsg[] = "Invalid Interest";
char depositmsg[] = "Invalid Deposit";
char yearsmsg[] = "Invalid Years";
char header[] = "IRA Calculator";

/*    The input data    */
double apr = 0.0;        /* Anual percentage rate  (-a) */
double bb = 0.0;         /* Beginning balance      (-b) */
double ad = 0.0;         /* Annual Deposit         (-d) */
long  yrs = 0;           /* Years till retirement  (-y) */

/*    The Answer        */
double ne = 0.0;         /* final total */

char *name;
int batch = 0;           /* flag for a batch (CLI) execution */

double atof();
long atol();



main(argc,argv)
int argc;
char *argv[];
{
	UWORD code;
	ULONG class;
	APTR object;
	FILE *fp;
 

	/* Open the libraries */

	IntuitionBase = (struct IntuitionBase *)
		OpenLibrary("intuition.library", 0L);
	if (IntuitionBase == NULL)
		{
		done(11);
		}
	GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0L);
	if (GfxBase == NULL)
		{
		done(10);
		}

	DosBase = (struct DosLibrary *)OpenLibrary("dos.library", 0);
	if (DosBase == NULL)
		{
		done(16);
		}

	/*   Get the arguments */

	filename[0] = '\0';

	if (argc == 0) getWBargs();
	else getCLIargs(argc,argv);
	if (batch)
		{
		calc_it();
		done(0);
		}

	wG = OpenWindow(&NewWindowStructure1);	/* open main window */
	if ( wG == NULL )
		{
		done(12);
		}

	rpG = wG->RPort;	/* get a rastport pointer for the window */

	PrintIText(rpG,&IntuiTextList1,0L,0L); /* write window text */

	SetMenuStrip(wG,&MenuList1);	/* attach my Menu */

	if (filename[0] != '\0')
		{
		while ((fp = fopen(filename,"r")) == NULL)
			{
			infailtxt2.IText = (UBYTE *) filename;
			if (AutoRequest(wG,&infailtxt,&retrytxt,&cantxt,
				0L,0L,reqlen(filename),75L)) continue;
			}
		if (fp != NULL) {
			read_file(fp);
			fclose(fp);
			}
		}

	/* Wait for some User interaction */
	while(1)
	{
		WaitPort(wG->UserPort);
			while( (message = (struct IntuiMessage *)
				GetMsg(wG->UserPort) ) != NULL)
			{
				code = message->Code;  /* MENUNUM */
				object = message->IAddress;  /* Gadget */
				class = message->Class;  /* IDCMP Flags */
				ReplyMsg(message);  /* Free the sender */
				switch (class)
					{
					case CLOSEWINDOW :
						done(0);   /* close gadget clicked */
					case GADGETUP:
						if (object == (APTR) &CalcGad)
							{
							calc_it();
							break;
							}
						/* add more gadget checks here */
						break;
					case MENUPICK:    /* menu selection made */
						/* I get a NULL message whenever the user brings
						   up the menu but doesn't select anything    */
						if (code != MENUNULL) do_pick((USHORT)code);
						break;
					}
			}
	} 
}

/*
 * Cleanup and exit
 */

done(how)
int how;
{
	if (FIOSupp) ReleaseFileIO(FIOSupp);
	if (wG) ClearMenuStrip(wG);
	if (wG) CloseWindow(wG);
	if (DosBase) CloseLibrary(DosBase);
	if (GfxBase != NULL) CloseLibrary(GfxBase);
	if (IntuitionBase != NULL) CloseLibrary(IntuitionBase);
	exit(how);

 /* exit codes 
  * 0  User requested
  * 10 graphics lib open fail
  * 11 intuition lib open fail
  * 12 main window open fail
  * 13 _abort() called
  * 14 Bad CLI args
  * 16 Dos lib open fail
  */
}


/*
 * do_pick : handle chain of menu selections
 */

do_pick(menunum)
USHORT menunum;
{
struct MenuItem *item, *ItemAddress();
	while (menunum != MENUNULL)
		{
		switch(MENUNUM(menunum))
			{
			case 0:     /* Project Menu */
			switch(ITEMNUM(menunum))
				{
				case 0: /* Load */
					do_load();
					break;
				case 1: /* Save */
					do_save();
					break;
				case 2: /* Print */
					do_print();
					break;
				case 4: /* About */
					about();
					break;
				case 3: /* Help */
					help();
					break;
				case 5: /* Quit */
					done(0);
				}
			break;
			default:	/* What's this garbage ? */
				menunum = MENUNULL;
			}       /* end switch MENUNUM  */

		/* Get chain to next selection. NextSelect contains another item
		   when the user makes multiple menu selections             */
		item = ItemAddress(&MenuList1,(long) menunum);
		menunum = item->NextSelect;
		}
}


/*
 *  Validate input and calculate new balance
 */

calc_it()
/*
 *  Adapted from:
 *
 *     ira.c :  Calculate Nest-Egg at retirement from the
 *              following input:
 *
 *     Beginning Balance
 *     Anual percentage rate
 *     Annual deposit
 *     Years till retirement
 *
 *   By Joel Swank 8/18/89
 */

{
	long i;
	double xapr;

	if (!batch)  if (!get_values()) return;

	xapr = 1.0 + apr/100.0;
	ne = bb;
	for (i=0; i<yrs; i++)
	   {
	   ne += ad;
	   ne *= xapr;
	   }

	if (batch) {
		printf("For Beginning balance = $%-12.2f\n",bb);
		printf("Annual percentage Rate = %2.2f%%\n",apr);
		printf("Annual deposit = $%-12.2f\n",ad);
		printf("Nest-Egg after %ld years is $%-12.2f\n",yrs,ne);
	} else {
		bb = ne;
		put_values();
		}

}

/*
 *  Get input data from string requesters
 */

get_values()
{
	int i;

	i = get_float(BalanceGadSIBuff,&bb) ;
	if ( !i || bb < MINBB)
		{
		messagetxt.IText = (UBYTE *) balancemsg;
		AutoRequest(wG,&messagetxt,0L,&oktxt,0L,0L,300L,75L);
		return FALSE;
		}

	i = get_float(InterestGadSIBuff,&apr);
	if ( !i || apr < MINAPR || apr > MAXAPR)
		{
		messagetxt.IText = (UBYTE *) interestmsg;
		AutoRequest(wG,&messagetxt,0L,&oktxt,0L,0L,300L,75L);
		return FALSE;
		}

	i = get_float(DepositGadSIBuff,&ad);
	if ( !i || ad < MINAD )
		{
		messagetxt.IText = (UBYTE *) depositmsg;
		AutoRequest(wG,&messagetxt,0L,&oktxt,0L,0L,300L,75L);
		return FALSE;
		}

	yrs = YearsGadSInfo.LongInt;
	if (yrs < MINYRS)
		{
		messagetxt.IText = (UBYTE *) yearsmsg;
		AutoRequest(wG,&messagetxt,0L,&oktxt,0L,0L,300L,75L);
		return FALSE;
		}

	return TRUE;
}

/*
 *  Get a floating point number from an ASCII string.
 *    Return TRUE for good number, FALSE for bad.
 */

get_float(string,val)
char *string;
double *val;
{
	int i;

	i = sscanf(string,"%E",val);
	if (i == 1) return TRUE;
	else return FALSE;
}

/*
 *  Put values back into their string requesters
 */

put_values()
{
	YearsGadSInfo.LongInt = yrs;
	sprintf(YearsGadSIBuff,"%d",YearsGadSInfo.LongInt);
	if (bb >= 1000000.0) sprintf(BalanceGadSIBuff,"%.6e",bb);
	else sprintf(BalanceGadSIBuff,"%.2f",bb);
	sprintf(InterestGadSIBuff,"%.3f",apr);
	sprintf(DepositGadSIBuff,"%.2f",ad);
	if (wG) redraw_scr();
}

/*
 * Redraw Window
 */

redraw_scr()
{
	RemoveGList(wG,&GadgetList1,-1L); /* remove all gadgets */
	SetAPen(rpG,0L); /* clear the window */
	RectFill(rpG,2L,11L,(long)(wG->Width-3),(long)(wG->Height-2));
	AddGList(wG,&GadgetList1,0L,-1L,NULL);  /* put back gadgets */
	RefreshGList(&GadgetList1,wG,NULL,-1L); /* redraw the gadgets */
	PrintIText(rpG,&IntuiTextList1,0L,0L); /* write window text */
	SetAPen(rpG,1L);  /* set draw color */
}



/*
 *    Print the data
 */

do_print()
{
	int i;
	FILE *fp;

	if (!get_values()) return;

	while ((fp = fopen("PRT:","w")) == NULL)
		{
		if (AutoRequest(wG,&prfailtxt,&retrytxt,&cantxt,
			0L,0L,300L,75L)) continue;
		return;
		}

	fprintf(fp,"%s\n",header);
	fprintf(fp,"Balance = $%-20.2f\n",bb);
	fprintf(fp,"Annual percentage Rate = %2.3f%%\n",apr);
	fprintf(fp,"Annual deposit = $%-20.2f\n",ad);
	fprintf(fp,"Years = $%d\n",yrs);

	fclose(fp);
}


/*
 *    Load data from an ASCII file
 */

do_load()
{
	FILE *fp;

	select_file(0);
	if (filename[0] == '\0') return;

	while ((fp = fopen(filename,"r")) == NULL)
		{
		infailtxt2.IText = (UBYTE *) filename;
		if (AutoRequest(wG,&infailtxt,&retrytxt,&cantxt,
			0L,0L,reqlen(filename),75L)) continue;
		return;
		}
	read_file(fp);
	fclose(fp);
}


/*
 *    Read in data from open file
 */

read_file(fp)
FILE *fp;
{
	int i;

	i = fscanf(fp," %20F, %7F, %20F, %d",&bb,&apr,&ad,&yrs);
	if (i != 4 || apr > MAXAPR || bb < MINBB || ad < MINAD)
		{
		infailtxt2.IText = (UBYTE *) filename;
		AutoRequest(wG,&badfiletxt,0L,&oktxt,0L,0L,reqlen(filename),75L);
		return(FALSE);
		}

	put_values();
}

/*
 *    Save the current data in an ASCII file
 */

do_save()
{
	FILE *fp;
	int i;

	if (!get_values()) return;

	select_file(1);
	if (filename[0] == '\0') return;

	while ((fp = fopen(filename,"w")) == NULL)
		{
		infailtxt2.IText = (UBYTE *) filename;
		if (AutoRequest(wG,&infailtxt,&retrytxt,&cantxt,
			0L,0L,reqlen(filename),75L)) continue;
		return;
		}
	AddFileIOName(FIOSupp,filename); /* tell FIO about new file */

	fprintf(fp,"%.2f,%.3f,%.2f,%d",bb,apr,ad,yrs);
	fprintf(fp,"\n");
	fclose(fp);

}


/*
 * Select a file
 */

select_file(io)
int io;
{
	struct Window *OpenWindow(), *wF = NULL;
	struct FileLock *lock = NULL;

	ClearMenuStrip(wG);

	if (NULL == FIOSupp)
		if (NULL == (FIOSupp = GetFileIOSupport()))
			{
			AutoRequest(wG,&fiofailtxt,0L,&cantxt,0L,0L,300L,75L) ;
			SetMenuStrip(wG,&MenuList1);	/* re-attach my Menu */
			return;
			}

	/* set up title for file requester */
	if (io == 0) FIOSupp->ReqTitle = (UBYTE *) load_title;
	else FIOSupp->ReqTitle = (UBYTE *) save_title;

	wF = OpenWindow(&NewWindowStructure3);	/* open the window */
	if ( wF == NULL )
		{
		AutoRequest(wG,&winfailtxt,0L,&oktxt,0L,0L,300L,75L);
		SetMenuStrip(wG,&MenuList1);	/* re-attach my Menu */
		return;
		}

	filename[0] = '\0';
	if (GetFileIOName(FIOSupp,wF))
		BuildFileIOPathname(FIOSupp,filename);

	if (wF) CloseWindow(wF);
	if (lock) UnLock(lock);
	SetMenuStrip(wG,&MenuList1);	/* attach my Menu */
}


/*
 *  Calculate size of requester needed for given filename
 */

reqlen(filename)
char *filename;
{
	int r;
	r = TextLength(rpG,filename,strlen(filename))+50;
	if (r < 300) r = 300;
	if (r > 640) r = 640;
	return (r) ;
}
 
#ifdef AZTEC_C
_abort()
{
	done(13);
}
#endif
