/************************************************************************
*
*  Program:  Grocery.c
*
*  Author: Brian Gragg
*
*  Date:   11/29/92     version 0.1
*           5/15/93     version 1.4 - added create meal menu option
*          10/17/93     version 1.5 - added list scroll option & sort at print
*           9/19/94     version 1.6 - fixed bug in meal generation option
*			3/18/95     version 1.7 - moved about requester to grocery screen
*
*************************************************************************/

#define  DATAFILE    "Grocery.data"
#define  BACKFILE    "Grocery.data.bak"
#define  TEMPFILE    "t:groctmp"
#define  MODEID      HIRESLACE_KEY
#define  SWIDTH      640
#define  SHEIGHT     400
#define  SDEPTH      2

#define ASLLEFTEDGE 163
#define ASLTOPEDGE  24
#define ASLWIDTH    320
#define ASLHEIGHT   200

#define MYGAD_ITEM     (0)
#define MYGAD_AMOUNT   (1)
#define MYGAD_SIZE     (2)
#define MYGAD_GLIST    (3)
#define MYGAD_ILIST    (4)
#define MYGAD_MEALS    (5)
#define MYGAD_EDIT     (6)
#define MYGAD_DELETE   (7)
#define MYGAD_SORT     (8)
#define MYGAD_SORTNAME (9)
#define MYGAD_AISLE   (10)
#define MYGAD_ADD     (11)
#define MAXGADGET     (12)  /* this should be 1 greater than last gadget id */

#define NOITEM         65535
#define OPEN           1
#define SAVE           2

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <ctype.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/lists.h>
#include <exec/nodes.h>
#include <dos/dos.h>
#include <libraries/asl.h>
#include <intuition/intuition.h>
#include <intuition/screens.h>
#include <intuition/gadgetclass.h>
#include <libraries/gadtools.h>
#include <intuition/intuitionbase.h>
#include <graphics/gfx.h>
#include <graphics/gfxbase.h>
#include <libraries/dos.h>

#include <clib/utility_protos.h>
#include <clib/alib_protos.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/intuition_protos.h>
#include <clib/graphics_protos.h>
#include <clib/gadtools_protos.h>
#include <clib/asl_protos.h>

/* Use SAS/C 6.0 ability to open libraries for you !! */
extern struct Library         *DOSBase;
extern struct Library         *GadToolsBase;
extern struct Library         *AslBase;
extern struct IntuitionBase   *IntuitionBase;
extern struct GfxBase         *GfxBase;
extern struct Library         *SysBase;
extern struct Library         *UtilityBase;

struct EasyStruct myES = {
    sizeof(struct EasyStruct), 0, "GroceryList",
    "%s",
    "OK",
};


struct Screen *myscreen      = NULL;
struct Window *window        = NULL;
struct Menu   *menuStrip     = NULL;
struct APTR   *my_VisualInfo = NULL;
struct Gadget *glist         = NULL;
struct List   *ItemList      = NULL;
struct List   *GrocList      = NULL;
struct List   *MealList      = NULL;
struct List   *AislList      = NULL;
struct Gadget *mygad[MAXGADGET];
struct NewGadget ng;

#define NAMENODE_ID    100     /* The type of "NameNode" */
#define MEALNODE_ID    101     /* The type of "MealNode" */

struct NameNode {
   struct  Node nn_Node;       /* System Node structure            */
   UBYTE   nn_Item[30];        /* The item (equals the node name)  */
   UBYTE   nn_Size[10];        /* standard size (ie lbs, oz, etc)  */
   UBYTE   nn_Amount[10];      /* usual amount                     */
   WORD    nn_Aisle;           /* the aisle number where it's found*/
   UBYTE   nn_LongName[80];    /* the long name associated with the item */
   WORD    nn_ListPos;         /* ordinal position in a list       */
};

struct MealNode {
   struct  Node nn_Node;       /* System Node structure            */
   UBYTE   nn_Meal[30];        /* The meal (equals node name)      */
   struct  List *nn_MealItem;  /* a sublist of items               */
};
   
struct TextAttr Topaz80 = { "topaz.font", 8, 0, 0, };

struct NewMenu mynewmenu[] =
{
    { NM_TITLE, "Project",  0 , 0, 0, 0,},
    { NM_ITEM,  "New",       "N", 0, 0, 0,},
    { NM_ITEM,  "Open...",   "O", 0, 0, 0,},
    { NM_ITEM,  NM_BARLABEL,  0 , 0, 0, 0,},
    { NM_ITEM,  "Save",      "S", 0, 0, 0,},
    { NM_ITEM,  "Save As...","A", 0, 0, 0,},
    { NM_ITEM,  NM_BARLABEL,  0 , 0, 0, 0,},
    { NM_ITEM,  "Print",     "P", 0, 0, 0,},
    { NM_ITEM,  NM_BARLABEL,  0 , 0, 0, 0,},
    { NM_ITEM,  "About",      0 , 0, 0, 0,},
    { NM_ITEM,  NM_BARLABEL,  0 , 0, 0, 0,},
    { NM_ITEM,  "Quit",      "Q", 0, 0, 0,},
    { NM_TITLE, "Meals",      0 , 0, 0, 0,},
    { NM_ITEM,  "Create Meal","M", 0, 0, 0,},
 };    

char savefilename[256];
char aislename[30][22];
char aisleId[30]; 
WORD pens[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ~0};
UWORD currentAisle = NOITEM;
UWORD currentGroc  = NOITEM;
far char buffer[256], buf[256];
 
#ifdef LATTICE
int __chkabort(void) { return(0); } /* Disable Lattice CTRL/C handling */
#endif

/* VERSION STRING */
UBYTE vers[] = "\0$VER: Grocery 1.7";
char screenname[80];
char title[120];

/************ my protos *************/
VOID cleanExit(char *);            /* clean up and close           */
int doMenus(VOID);                 /* create menus                 */
VOID handle_window_events(VOID);   /* deal with the IDCMP events   */
VOID getWBPens(VOID);              /* get the workbench pens       */
VOID setupGadgets(VOID);           /* setup the required gadgets   */
VOID AddName(struct List *, UBYTE *, UBYTE *, UBYTE *, WORD);
VOID AddItem(struct List *, UBYTE *, UBYTE *, UBYTE *, WORD);
VOID AddAisle(struct List *, UBYTE *, WORD);
struct List *AddMeal(struct List *, UBYTE *);
VOID FreeMealNodes(struct List *);
VOID FreeNameNodes(struct List *);
VOID readData(VOID);               /* reads data from DATAFILE     */
VOID newMeal(VOID);                /* saves the list as a meal in the database */


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

void
main(int argc, char *argv[])
{
   LONG screenTopBorder;
   
   /* Rely on SAS/C 6.0 to open the libraries for me */

   getWBPens();
   
   strcpy(title,&vers[7]);
   strcat(title,"  - Brian Gragg March 1995");
   strcpy(screenname,title);
   
   if (NULL == (myscreen = OpenScreenTags(NULL,
             SA_Width,     SWIDTH,
             SA_Height,    SHEIGHT,
             SA_DisplayID, MODEID,
             SA_Depth,     SDEPTH,
             SA_Title,     screenname,
             SA_Pens,      pens,
             SA_ShowTitle, TRUE,
             TAG_END))) 
       cleanExit("Couldn't open screen.");
   
   readData();
   setupGadgets();

   screenTopBorder = myscreen->WBorTop + myscreen->Font->ta_YSize +1;
   if (NULL == (window = OpenWindowTags(NULL,
             WA_Top,          screenTopBorder,
             WA_Left,         0,
             WA_Height,       myscreen->Height - screenTopBorder,
             WA_Width,        myscreen->Width,
             WA_CustomScreen, myscreen,
             WA_NoCareRefresh,TRUE,
             WA_IDCMP,        IDCMP_MENUPICK | IDCMP_MOUSEBUTTONS | 
                               LISTVIEWIDCMP | IDCMP_REFRESHWINDOW,
             WA_Gadgets,      glist,
             WA_Activate,     TRUE,
             WA_DetailPen,    3,
             TAG_END)))
       cleanExit("Couldn't open window.");
   
   
   GT_RefreshWindow(window, NULL);
   
   ActivateGadget(mygad[MYGAD_ITEM],window,NULL);

   if (doMenus()) 
       cleanExit("Couldn't create menu strip.");

   handle_window_events();
   
   cleanExit("");
}


/*********************************************************************
*   cleanExit("message")
*
*      clean up and exit.  Print message before quiting.
**********************************************************************/

VOID
cleanExit(char *message)
{
   if (strlen(message) > 1)
       EasyRequest(NULL, &myES, NULL, message);
       
   if (ItemList != NULL) {     FreeNameNodes(ItemList);
                               FreeMem(ItemList, sizeof(struct List)); }
   if (GrocList != NULL) {     FreeNameNodes(GrocList);
                               FreeMem(GrocList, sizeof(struct List)); }
   if (MealList != NULL) {     FreeMealNodes(MealList);
                               FreeMem(MealList, sizeof(struct List)); }
   if (AislList != NULL) {     FreeNameNodes(AislList);
                               FreeMem(AislList, sizeof(struct List)); }
   
   if (menuStrip != NULL)      FreeMenus(menuStrip);
   if (glist != NULL)          FreeGadgets(glist);
   if (my_VisualInfo != NULL)  FreeVisualInfo(my_VisualInfo);


   if (window != NULL)         CloseWindow(window);
   if (myscreen != NULL)       CloseScreen(myscreen);

   /* Rely on SAS/C 6.0 to close libraries for me */ 
   
   exit(0);  
}


/*********************************************************************
*   getWBPens()
*
*      get the colors from the workbench drawinfo structure
**********************************************************************/

VOID
getWBPens(VOID)
{
   UBYTE *pubScreenName = "Workbench";
   int   i;
   
   struct Screen *pub_screen = NULL;
   struct DrawInfo *screen_drawinfo = NULL;

   /* Get a lock on the Workbench screen */
   pub_screen = LockPubScreen(pubScreenName);
   if ( pub_screen == NULL )
   {
       EasyRequest(NULL, &myES, NULL, "Couldn't get a lock on workbench.");
       for (i=0; i<4; i++)
           pens[i] = i;
       return;
   }
       
   screen_drawinfo = GetScreenDrawInfo(pub_screen);
   if ( screen_drawinfo == NULL)
   {
       UnlockPubScreen(pubScreenName,pub_screen);
       EasyRequest(NULL, &myES, NULL, "Couldn't get workbench's drawinfo structure.");
       for (i=0; i<4; i++)
           pens[i] = i;
       return;
   }

   for (i=0; pens[i] != ~0; i++)
      pens[i] = screen_drawinfo->dri_Pens[i];
   
   FreeScreenDrawInfo(pub_screen,screen_drawinfo);
   UnlockPubScreen(pubScreenName,pub_screen);
}

/*********************************************************************
*   doMenus()
*   return 0=ok  1=failed
**********************************************************************/

int
doMenus(VOID)
{
   if (NULL != (menuStrip = CreateMenus(mynewmenu, TAG_END)))
   {
       if (LayoutMenus(menuStrip, my_VisualInfo, TAG_END))
       {
           if (SetMenuStrip(window, menuStrip))
           {
               return(0);
           }
       }
       FreeMenus(menuStrip);
   }
   return(1);
}


/*********************************************************************
*   readData()
*
**********************************************************************/

VOID
readData(VOID)
{
   FILE   *fileptr = NULL;      /* a pointer to a file handle */
   char   *item, *amount, *size, meal[30];
   long   place;
   struct List *list;
   char   *pointer;
   int    i, j;
      
   GrocList = AllocMem(sizeof(struct List),MEMF_CLEAR);
   ItemList = AllocMem(sizeof(struct List),MEMF_CLEAR);
   MealList = AllocMem(sizeof(struct List),MEMF_CLEAR);
   AislList = AllocMem(sizeof(struct List),MEMF_CLEAR);

   if ((GrocList == NULL) || (ItemList == NULL) || (MealList == NULL) || (AislList == NULL))
       cleanExit("Out of memory allocating Lists.");
       
   NewList(GrocList);
   NewList(ItemList);
   NewList(MealList);
   NewList(AislList);
   
   fileptr = fopen(DATAFILE,"r");
   if ( fileptr == NULL )
       cleanExit("Couldn't open data file.");
   
   while ((fgets(buffer,255,fileptr) != NULL) && (strlen(buffer) > 1))
   {
       if (buffer[0] != ';')
       {
           buffer[strlen(buffer)-1] = '\0';
           i = atoi(&buffer[3]);  /* order id */
           j = atoi(buffer);      /* aisle id */
           aisleId[j] = i ;
           strncpy(aislename[i],&buffer[6],13);
           AddAisle(AislList,&buffer[6], (WORD)i); 
       }
   }

   while ((fgets(meal,29,fileptr) != NULL) && (strncmp(meal,"EXIT!",5)))
   {
       meal[strlen(meal)-1] = '\0';
       list = AddMeal(MealList,meal);
       
       while ((fgets(buffer,255,fileptr) != NULL) && (strlen(buffer)>5) && 
                   (strrchr(buffer,'`') != NULL))
       {
           pointer   =strrchr(buffer,'`');
           pointer[0]='\0';
           place     = atol(&pointer[1]);
           pointer   =strrchr(buffer,'`');
           pointer[0]='\0';
           size      = &pointer[1];
           pointer   =strrchr(buffer,'`');
           pointer[0]='\0';
           amount    = &pointer[1];
           item      = buffer;

           AddName(list,item,amount,size,aisleId[place]);
       }
   }

   fgets(buffer,255,fileptr); /* read in blank line */
   
   
   while ((fgets(buffer,255,fileptr) != NULL) && (strlen(buffer)>1))
   {
       pointer   =strrchr(buffer,'`');
       pointer[0]='\0';
       place     = atol(&pointer[1]);
       pointer   =strrchr(buffer,'`');
       pointer[0]='\0';
       size      = &pointer[1];
       pointer   =strrchr(buffer,'`');
       pointer[0]='\0';
       amount    = &pointer[1];
       item      = buffer;
       
       AddName(ItemList,item,amount,size,aisleId[place]);
   }

   fclose(fileptr);
}


/*********************************************************************
*   setupGadgets()
*
**********************************************************************/

VOID
setupGadgets(VOID)
{
   struct Gadget *gad;
   
   if (NULL == (my_VisualInfo = GetVisualInfo(myscreen, TAG_END)))
       cleanExit("Couldn't GetVisualInfo.");

   gad = CreateContext(&glist);
   
   /** ITEM GADGET **/
   ng.ng_LeftEdge   = 17;
   ng.ng_TopEdge    = 348;
   ng.ng_Width      = 215;
   ng.ng_Height     = 21;
   ng.ng_GadgetText = "Item";
   ng.ng_VisualInfo = my_VisualInfo;
   ng.ng_GadgetID   = MYGAD_ITEM;
   ng.ng_TextAttr   = &Topaz80;
   ng.ng_Flags      = PLACETEXT_BELOW;

   mygad[MYGAD_ITEM] = gad = CreateGadget(STRING_KIND, gad, &ng, 
                   GA_TabCycle,      TRUE,
                   GA_Immediate,     TRUE,
                   STRINGA_ExitHelp, TRUE,
                   TAG_END);

   /** AMOUNT GADGET **/
   ng.ng_LeftEdge   = 236;
   ng.ng_Width      = 84;
   ng.ng_GadgetText = "Amount";
   ng.ng_GadgetID   = MYGAD_AMOUNT;

   mygad[MYGAD_AMOUNT] = gad = CreateGadget(STRING_KIND, gad, &ng, 
                   GA_TabCycle,    TRUE,
                   GA_Immediate,   TRUE,
                   TAG_END);   ng.ng_LeftEdge   = 17;

   /** UNITS GADGET **/
   ng.ng_LeftEdge   = 324;
   ng.ng_GadgetText = "Units";
   ng.ng_GadgetID   = MYGAD_SIZE,

   mygad[MYGAD_SIZE] = gad = CreateGadget(STRING_KIND, gad, &ng, 
                   GA_TabCycle,    TRUE,
                   GA_Immediate,   TRUE,
                   TAG_END);

   /** AISLE GADGET **/
   ng.ng_LeftEdge   = 423;
   ng.ng_TopEdge    = 316;
   ng.ng_Width      = 185;
   ng.ng_Height     = 60;
   ng.ng_GadgetText = "Asile";
   ng.ng_GadgetID   = MYGAD_AISLE;
   
   mygad[MYGAD_AISLE] = gad = CreateGadget(LISTVIEW_KIND, gad, &ng, 
                   GTLV_Labels,        AislList,
                   GTLV_ScrollWidth,   18,
                   GTLV_Top,           1,
                   LAYOUTA_Spacing,    1,
                   GTLV_ShowSelected,  NULL,
                   TAG_END);

   /** MEALS GADGET **/
   ng.ng_LeftEdge   = 423;
   ng.ng_TopEdge    = 223;
   ng.ng_Width      = 185;
   ng.ng_Height     = 80;
   ng.ng_GadgetText = "Meals";
   ng.ng_GadgetID   = MYGAD_MEALS;
   
   mygad[MYGAD_MEALS] = gad = CreateGadget(LISTVIEW_KIND, gad, &ng, 
                   GTLV_Labels,        MealList,
                   GTLV_ScrollWidth,   18,
                   GTLV_Top,           0,
                   LAYOUTA_Spacing,    1,
                   TAG_END);

   /** ILIST GADGET **/
   ng.ng_TopEdge    = 15;
   ng.ng_Height     = 208;
   ng.ng_GadgetText = "Items List";
   ng.ng_GadgetID   = MYGAD_ILIST;
   ng.ng_Flags      = PLACETEXT_ABOVE;
   
   mygad[MYGAD_ILIST] = gad = CreateGadget(LISTVIEW_KIND, gad, &ng, 
                   GTLV_Labels,        ItemList,
                   GTLV_ScrollWidth,   18,
                   GTLV_Top,           0,
                   LAYOUTA_Spacing,    1,
                   TAG_END);


   /** GLIST GADGET **/
   ng.ng_LeftEdge   = 17;
   ng.ng_Width      = 390;
   ng.ng_Height     = 292;
   ng.ng_GadgetText = "Grocery List";
   ng.ng_GadgetID   = MYGAD_GLIST;
   
   mygad[MYGAD_GLIST] = gad = CreateGadget(LISTVIEW_KIND, gad, &ng, 
                   GTLV_Labels,        GrocList,
                   GTLV_ScrollWidth,   18,
                   GTLV_Top,           0,
                   LAYOUTA_Spacing,    1,
                   GTLV_ShowSelected,  NULL,
                   TAG_END);

   /** EDIT GADGET **/
   ng.ng_LeftEdge   = 17;
   ng.ng_TopEdge    = 310;
   ng.ng_Width      = 56;
   ng.ng_Height     = 20;
   ng.ng_GadgetText = "EDIT";
   ng.ng_GadgetID   = MYGAD_EDIT;
   ng.ng_Flags      = PLACETEXT_IN;

   mygad[MYGAD_EDIT] = gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END);


   /** DELETE GADGET **/
   ng.ng_LeftEdge   = 80;
   ng.ng_GadgetText = "DELETE";
   ng.ng_GadgetID   = MYGAD_DELETE;

   mygad[MYGAD_DELETE] = gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END);


   /** SORT BY AISLE GADGET **/
   ng.ng_LeftEdge   = 143;
   ng.ng_Width      = 94;
   ng.ng_GadgetText = "AISLE SORT";
   ng.ng_GadgetID   = MYGAD_SORT;


   mygad[MYGAD_SORT] = gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END);

   /** SORT BY NAME GADGET **/
   ng.ng_LeftEdge   = 244;
   ng.ng_GadgetText = "NAME SORT";
   ng.ng_GadgetID   = MYGAD_SORTNAME;

   mygad[MYGAD_SORTNAME] = gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END);


   /** ADD GADGET **/
   ng.ng_LeftEdge   = 345;
   ng.ng_Width      = 62;
   ng.ng_GadgetText = "ADDITEM";
   ng.ng_GadgetID   = MYGAD_ADD;

   mygad[MYGAD_ADD] = gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END);

   

}

/*********************************************************************
*      NODE FUNCTIONS
*
*   AddName()  &  FreeNameNodes()  &  FindNode()  & alphaEnqueue
*
*      used to build and clear nodes from a list
**********************************************************************/

VOID
alphaEnqueue(struct List *list, struct Node *node)
{                              /* inserts a node queued by pri then name */
    struct Node *worknode;
    BOOL   found = FALSE;

    worknode = list->lh_Head; /* First node */
    while (worknode != NULL)
    {
        if ((worknode->ln_Pri < node->ln_Pri) ||
            ((worknode->ln_Pri == node->ln_Pri) &&
             (strcmp(worknode->ln_Name,node->ln_Name) > 0)))
        {
           Insert(list, node, worknode->ln_Pred);
           found = TRUE;
           break;
        }
        worknode = worknode->ln_Succ;
    }
    if ( found == FALSE )
       AddTail(list,node);
}



/* Allocate a NameNode structure, copy the given name into the structure,
 * then add it the specified list. 
*/

VOID 
AddName(struct List *list, UBYTE *item, UBYTE *amount, UBYTE *size, WORD aisle)
{
    struct NameNode *namenode;

    if (!( namenode = AllocMem(sizeof(struct NameNode),MEMF_CLEAR) ))
        cleanExit("Out of memory adding a node.");

    strcpy(namenode->nn_Item,item);
    strcpy(namenode->nn_Size,size);
    strcpy(namenode->nn_Amount,amount);
    namenode->nn_Aisle = aisle;
    namenode->nn_Node.ln_Name = namenode->nn_Item;
    namenode->nn_Node.ln_Type = NAMENODE_ID;
    namenode->nn_Node.ln_Pri  = 0;
    alphaEnqueue((struct List *)list,(struct Node *)namenode);
}

VOID
AddItem(struct List *list, UBYTE *item, UBYTE *amount, UBYTE *size, WORD aisle)
{
    struct NameNode *namenode;

    if (!( namenode = AllocMem(sizeof(struct NameNode),MEMF_CLEAR) ))
        cleanExit("Out of memory adding a node.");

    strcpy(namenode->nn_Item,item);
    strcpy(namenode->nn_Size,size);
    strcpy(namenode->nn_Amount,amount);
    namenode->nn_Aisle = aisle;
    namenode->nn_Node.ln_Type = NAMENODE_ID;
    namenode->nn_Node.ln_Pri  = 0;
    sprintf(buffer,"%-18.18s %8.8s %-7.7s %-14.14s\0",namenode->nn_Item, namenode->nn_Amount,
           namenode->nn_Size, aislename[namenode->nn_Aisle]);
    strcat(namenode->nn_LongName,buffer);
    namenode->nn_Node.ln_Name = namenode->nn_LongName;
    AddTail((struct List *)list,(struct Node *)namenode);
}

VOID 
AddAisle(struct List *list, UBYTE *name, WORD aisle)
{
    struct NameNode *namenode;

    if (!( namenode = AllocMem(sizeof(struct NameNode),MEMF_CLEAR) ))
        cleanExit("Out of memory adding a node.");

    strcpy(namenode->nn_Item,name);
    namenode->nn_Aisle = aisle;
    namenode->nn_Node.ln_Name = namenode->nn_Item;
    namenode->nn_Node.ln_Type = NAMENODE_ID;
    namenode->nn_Node.ln_Pri  = 40-aisle;
    Enqueue((struct List *)list,(struct Node *)namenode);
}


struct List *
AddMeal(struct List *list, UBYTE *meal)
{
    struct MealNode *mealnode;

    if (!( mealnode = AllocMem(sizeof(struct MealNode),MEMF_CLEAR) ))
        cleanExit("Out of memory adding a meal.");

    strcpy(mealnode->nn_Meal,meal);
    mealnode->nn_Node.ln_Name = mealnode->nn_Meal;
    mealnode->nn_Node.ln_Type = MEALNODE_ID;
    mealnode->nn_Node.ln_Pri  = 0;
    if (!(mealnode->nn_MealItem = AllocMem(sizeof(struct List),MEMF_CLEAR)))
       cleanExit("No memory for meal list.");
    NewList(mealnode->nn_MealItem);
    alphaEnqueue((struct List *)list,(struct Node *)mealnode);
    return(mealnode->nn_MealItem);
}


/*
 * Free the entire list, including the header.  The header is not updated
 * as the list is freed.  This function demonstrates how to avoid
 * referencing freed memory when deallocating nodes.
 */
VOID FreeNameNodes(struct List *list)
{
    struct NameNode *worknode;
    struct NameNode *nextnode;

    worknode = (struct NameNode *)(list->lh_Head); /* First node */
    while (nextnode = (struct NameNode *)(worknode->nn_Node.ln_Succ)) {
        FreeMem(worknode,sizeof(struct NameNode));
        worknode = nextnode;
    }
}

VOID FreeMealNodes(struct List *list)
{
    struct MealNode *worknode;
    struct MealNode *nextnode;

    worknode = (struct MealNode *)(list->lh_Head); /* First node */
    while (nextnode = (struct MealNode *)(worknode->nn_Node.ln_Succ)) 
    {
        FreeNameNodes(worknode->nn_MealItem);
        FreeMem(worknode->nn_MealItem, sizeof(struct List));
        FreeMem(worknode,sizeof(struct MealNode));
        worknode = nextnode;
    }

}


struct Node *
FindNode(struct List *list, int number)
{
   struct Node *node;
   int    i;

   if (list->lh_TailPred == (struct Node *)list)
       return(NULL);
   else {
       for (node = list->lh_Head, i=0; i<number ; node = node->ln_Succ, i++)
           ;
   return(node);
   }
}


/*********************************************************************
*   getFile(Prompt)
*   
*      gets a file using the ASL file requester & the prompt
**********************************************************************/


BPTR
getFile(char *prompt,int type)
{
    struct FileRequester *fr;
    static BYTE savefile[100] = "";
    static BYTE savedir[255]  = "";
    char doit[10];
    ULONG fileflag;
    long  mode;
    BPTR  fh = -1L;

    if (type == OPEN)
    { 
       strcpy(doit,"OPEN");
       fileflag = 0L;
    }
    else
    {
       strcpy(doit,"SAVE");
       fileflag = FILF_SAVE;
    }
    
    if (fr = (struct FileRequester *)
         AllocAslRequestTags(ASL_FileRequest,
             ASL_Hail,       (ULONG)prompt,
             ASL_Height,     200,
             ASL_Width,      320,
             ASL_LeftEdge,   163,
             ASL_TopEdge,    50,
             ASL_OKText,     (ULONG)doit,
             ASL_CancelText, (ULONG)"CANCEL",
             ASL_Window,     window,
             ASL_File,       savefile,
             ASL_Dir,        savedir,
             ASL_FuncFlags,  fileflag,
             TAG_DONE))
     {
         if (AslRequest(fr,NULL))  
         {
             strcpy(savedir, fr->rf_Dir);
             strcpy(savefile, fr->rf_File);

             /* setup filename and load it */             
             strcpy(buffer,fr->rf_Dir);
             if (AddPart(buffer,fr->rf_File,255))
             {
                if (type == OPEN)
                   mode = MODE_OLDFILE;
                else
                   mode = MODE_NEWFILE;
                fh = Open(buffer,mode);
                strcpy(savefilename,buffer);
                sprintf(screenname,"%s    [FILE: %s]",title,fr->rf_File);
                ShowTitle(myscreen,TRUE);
             }
         }
         else
           fh = 0L;    /* CANCEL */
         FreeAslRequest(fr);
    }
    return(fh);
}


/*********************************************************************
*   Menu selection (NEW)
*
**********************************************************************/

VOID
doNew(VOID)
{
   GT_SetGadgetAttrs(mygad[MYGAD_GLIST],window,NULL,
       GTLV_Labels, ~0, TAG_DONE);
   FreeNameNodes(GrocList);
   FreeMem(GrocList, sizeof(struct List));
   if (!(GrocList = AllocMem(sizeof(struct List),MEMF_CLEAR)))
       cleanExit("No memory for Grocery list.");
   NewList(GrocList);
   GT_SetGadgetAttrs(mygad[MYGAD_GLIST],window,NULL,
       GTLV_Labels, GrocList, TAG_DONE);
}


/*********************************************************************
*   Menu selection (OPEN)
*
**********************************************************************/

VOID
doOpen(VOID)
{
   BPTR   pfile;
   char   *pointer;
   char   *item, *amount, *size;
   long   place = 0L;
    
   if (-1 == (pfile = getFile("Select Save Open:",OPEN)))
   {
       sprintf(buf,"Couldn't open file '%s'.",buffer);
       EasyRequest(window, &myES, NULL, buf);
   }
   
   doNew();

   GT_SetGadgetAttrs(mygad[MYGAD_GLIST],window,NULL,
            GTLV_Labels, ~0, TAG_DONE);   

   while (FGets(pfile,buffer,255) != NULL)
   {
       pointer   =strrchr(buffer,'`');
       pointer[0]='\0';
       place     = atol(&pointer[1]);
       pointer   =strrchr(buffer,'`');
       pointer[0]='\0';
       size      = &pointer[1];
       pointer   =strrchr(buffer,'`');
       pointer[0]='\0';
       amount    = &pointer[1];
       item      = buffer;
       AddItem(GrocList,item,amount,size,aisleId[place]);
   }
   GT_SetGadgetAttrs(mygad[MYGAD_GLIST],window,NULL,
            GTLV_Labels, GrocList, TAG_DONE);
   
   Close(pfile);
}          

/*********************************************************************
*   Menu selection (SAVE & SAVE AS)
*
**********************************************************************/

VOID
doSave(VOID)
{
   BPTR   pfile;
   struct NameNode *node;
   int    i;
 
   if (GrocList->lh_TailPred == (struct Node *)GrocList)
       return;  /* empty list */
 
   if (savefilename[0] == '\0')
   {
       pfile = getFile("Select Save File:",SAVE);
       if (pfile == -1 )
       {
           sprintf(buf,"Couldn't open file '%s'\nIt may already exist.",buffer);
           EasyRequest(window, &myES, NULL, buf);
       }
           
       if (pfile == 0 )
           return;
   }
   else
   {
       DeleteFile(savefilename);
       if (-1 == (pfile = Open(savefilename,MODE_NEWFILE)))
       {
         sprintf(buffer,"Couldn't open file '%s'.",savefilename);
         EasyRequest(window, &myES, NULL, buffer);
       }
   }
   
   if (pfile == -1) return;
   
   for (node=(struct NameNode *)GrocList->lh_Head ; 
          node->nn_Node.ln_Succ ; 
          node = (struct NameNode *)node->nn_Node.ln_Succ)
   {   
       for (i = 0; i < 30; i++)
           if (aisleId[i] == node->nn_Aisle)
               break;
               
       sprintf(buffer, "%s`%s`%s`%d\n", node->nn_Item, node->nn_Amount,
            node->nn_Size, i);
            
       if (-1 == Write(pfile, buffer, strlen(buffer)))
       {
           EasyRequest(window, &myES, NULL, "Save File Failed.");
           break;
       }
   }
   strcpy(buf,screenname);
   sprintf(screenname,"Saved to file: %s",savefilename);
   ShowTitle(myscreen,TRUE);
   strcpy(screenname,buf);
       
   Close(pfile);
}


/*********************************************************************
*   Sort List 
*               doSort(ID)   ID= MYGAD_SORT  or MYGAD_SORTNAME
**********************************************************************/

VOID
doSort(int ID)
{
struct NameNode *node, *nextnode;
struct List *list;

      if (GrocList->lh_TailPred == (struct Node *)GrocList)
          return;  /* empty list */
      if (!(list = AllocMem(sizeof(struct List),MEMF_CLEAR)))
          cleanExit("No memory for list.");
      NewList(list);
      GT_SetGadgetAttrs(mygad[MYGAD_GLIST],window,NULL,
              GTLV_Labels, ~0, TAG_DONE);
      
      for (nextnode=node=(struct NameNode *)GrocList->lh_Head ; 
             nextnode->nn_Node.ln_Succ ; node = nextnode)
      {
          nextnode = (struct NameNode *)node->nn_Node.ln_Succ;
          Remove((struct Node *)node);
          if (ID == MYGAD_SORT)
              node->nn_Node.ln_Pri = 40-node->nn_Aisle;
          else
              node->nn_Node.ln_Pri = 0;
          alphaEnqueue(list,(struct Node *)node);
      }
      FreeMem(GrocList, sizeof(struct List));
      GrocList = list;
      GT_SetGadgetAttrs(mygad[MYGAD_GLIST],window,NULL,
              GTLV_Labels, GrocList, TAG_DONE);
      currentGroc = NOITEM;
      ActivateGadget(mygad[MYGAD_ITEM],window,NULL);
}


/*********************************************************************
*   Menu selection (PRINT)
*
**********************************************************************/

VOID
doPrint(VOID)
{
   BPTR   pfile;
   struct NameNode *node;
   char   line[70];
 
   doSort(MYGAD_SORT);
   
   if (GrocList->lh_TailPred == (struct Node *)GrocList)
       return;  /* empty list */
   
   if (!(pfile = Open( "PRT:", MODE_NEWFILE)))
       EasyRequest(window, &myES, NULL, "Could not access printer.");
   
   Write(pfile, "[0z[4w", 8L);    
   for (node=(struct NameNode *)GrocList->lh_Head;
        node->nn_Node.ln_Succ ; 
        node = (struct NameNode *)node->nn_Node.ln_Succ)
   {
       if (node->nn_Aisle == ((struct NameNode *)node->nn_Node.ln_Succ)->nn_Aisle)
           strcpy(line,"[24m");
       else
           strcpy(line,"[4m");
       
       sprintf(buffer,
           "%s%10.10s %-30.30s %-10.10s %-21.21s\n",
           line,node->nn_Amount, node->nn_Item,
           node->nn_Size, aislename[node->nn_Aisle]);
       if (-1 == Write(pfile, buffer, strlen(buffer)))
       {
           EasyRequest(window, &myES, NULL, "Printing Failed.");
           break;
       }
   }
   Write(pfile,"[1z[3w[24m",8L);
   Close(pfile);
} 


/*********************************************************************
*   node = findBestFit(string)
*
*      finds the item whose name best fist the string.
**********************************************************************/

struct NameNode *
findBestFit(char *namestring)
{
   struct NameNode *node;
   int    i = 0;
   
   for (node=(struct NameNode *)ItemList->lh_Head ; 
           node->nn_Node.ln_Succ, Stricmp(node->nn_Item,namestring)<0; 
           node = (struct NameNode *)node->nn_Node.ln_Succ, i++);
   node->nn_ListPos = i;
   return(node);
}


/*********************************************************************
*   getItem(node)
*
*      gets the info from the item and loads item,amount,size,location 
*          requesters
**********************************************************************/

VOID
getItem(struct NameNode *node)
{
   GT_SetGadgetAttrs(mygad[MYGAD_ITEM],window,NULL,
           GTST_String, node->nn_Item, TAG_DONE);
   GT_SetGadgetAttrs(mygad[MYGAD_AMOUNT],window,NULL,
           GTST_String, node->nn_Amount, TAG_DONE);
   GT_SetGadgetAttrs(mygad[MYGAD_SIZE],window,NULL,
           GTST_String, node->nn_Size, TAG_DONE);
   GT_SetGadgetAttrs(mygad[MYGAD_AISLE],window,NULL,
           GTLV_Selected, node->nn_Aisle, TAG_DONE);
/* turning this on will cause the item list to move the
   clicked on selection to the top each time.           
   GT_SetGadgetAttrs(mygad[MYGAD_ILIST],window,NULL,
           GTLV_Top, node->nn_ListPos, TAG_DONE);      
*/
   ActivateGadget(mygad[MYGAD_AMOUNT],window,NULL);
   currentAisle = node->nn_Aisle;
}




/*********************************************************************
*   MEALS -> CREATE MEAL  menu option
*
**********************************************************************/


VOID 
newMeal(VOID)
{
   FILE   *fileptr = NULL;      /* a pointer to a file handle */
   FILE   *tempptr = NULL;
   struct List *list;
   struct NameNode *node;
   int i;
 
   struct EasyStruct yesno = {
       sizeof(struct EasyStruct), 0, "GroceryList",
       "%s",
       "OK|CANCEL",    
       };

   if (GrocList->lh_TailPred == (struct Node *)GrocList)
   {
       EasyRequest(window, &myES, NULL, "Grocery List empty.\nTo use this option, fill the grocery list with the\nitems in the meal and put the meal name\nin the ITEM box.  Then select CREATE MEAL");
       return;  /* empty list */
   }
 
   if (strlen(((struct StringInfo *)mygad[MYGAD_ITEM]->SpecialInfo)->Buffer) < 1)
   {
       EasyRequest(window, &myES, NULL, "Item Field empty.\nTo use this option, fill the grocery list with the\nitems in the meal and put the meal name\nin the ITEM box.  Then select CREATE MEAL");
       return;  /* empty list */
   }
 
   sprintf(buffer,"Copy current list to a meal item\ncalled %s?",
       ((struct StringInfo *)mygad[MYGAD_ITEM]->SpecialInfo)->Buffer);
   if (0L == EasyRequest(window, &yesno, NULL, buffer))
       return;

   /* OPEN FILES */
   fileptr = fopen(DATAFILE,"r");
   if ( fileptr == NULL )
       cleanExit("Couldn't open data file.");
   tempptr = fopen(TEMPFILE,"w");
   if ( tempptr == NULL )
   {
       fclose(fileptr);
       fileptr = 0L;
       remove(TEMPFILE);
       EasyRequest(window, &myES, NULL, "Couldn't open temporary file.");
       return;
   }
   
   /* COPY THE DATA FILE UP TO THE END OF THE MEALS SECTION */
   while ((fgets(buffer,255,fileptr) != NULL) && (strncmp(buffer,"EXIT!",5) != 0))
   {
       fputs(buffer,tempptr);
   }

   /* END OF MEALS SECTION NOT FOUND !!!!!  WE HAVE A PROBLEM */
   if (strncmp(buffer,"EXIT!",5) != 0)
   {
       fclose(fileptr);
       fclose(tempptr);
       fileptr = 0L;
       tempptr = 0L;
       remove(TEMPFILE);
       EasyRequest(window, &myES, NULL, 
           "Error reading data file.  EXIT! line not found");
       return;
   }
  
   /* OKAY, LETS ADD THE MEAL */
   /* ADD MEAL NAME */   
   fputs(((struct StringInfo *)mygad[MYGAD_ITEM]->SpecialInfo)->Buffer,tempptr);
   fputc('\n',tempptr);
   GT_SetGadgetAttrs(mygad[MYGAD_MEALS],window,NULL,
            GTLV_Labels, ~0, TAG_DONE);
 
   list = AddMeal(MealList,strcat(((struct StringInfo *)mygad[MYGAD_ITEM]->SpecialInfo)->Buffer,
       strnset(buffer,' ',29-strlen(((struct StringInfo *)mygad[MYGAD_ITEM]->SpecialInfo)->Buffer))));
   
   /* NOW ADD THE ITEMS */
   for (node=(struct NameNode *)GrocList->lh_Head;
        node->nn_Node.ln_Succ ; 
        node = (struct NameNode *)node->nn_Node.ln_Succ)
   {
       for (i=0;i<31;i++)
           if (aisleId[i] == node->nn_Aisle)
               break;
       if (1 > fprintf(tempptr,
           "%s`%s`%s`%d\n",
           node->nn_Item,node->nn_Amount,
           node->nn_Size, i))
       {
           fclose(tempptr);
           fclose(fileptr);
           tempptr = 0L;
           fileptr = 0L;
           remove(TEMPFILE);
           EasyRequest(window, &myES, NULL, "Couldn't write to temp file.");
           return;
       }
       AddName(list,node->nn_Item,node->nn_Amount,node->nn_Size,
       node->nn_Aisle);
   }
   
   /* NOW COPY THE REST OF THE DATA */
   GT_SetGadgetAttrs(mygad[MYGAD_MEALS],window,NULL,
            GTLV_Labels, MealList, TAG_DONE);
 
   fputc('\n',tempptr);
   fputs("EXIT!\n",tempptr);
    while (fgets(buffer,255,fileptr) != NULL)
   {
       fputs(buffer,tempptr);
   }

   /* CLEAN UP FILES */
   fclose(fileptr);
   fileptr=0L;
   fclose(tempptr);
   tempptr=0L;
   remove(BACKFILE);
   rename(DATAFILE, BACKFILE);
   sprintf(buffer,"copy %s %s \012delete >nil: %s",TEMPFILE, DATAFILE, TEMPFILE);
   Execute(buffer,0L,0L);
 
}



/*********************************************************************
*   handle_window_events()
*
**********************************************************************/


VOID 
handle_window_events(VOID)
{
struct IntuiMessage *msg;
SHORT done;
UWORD menuNumber;
UWORD menuNum;
UWORD itemNum;
UWORD subNum;
WORD   mousex, mousey;
ULONG  class;
USHORT code;
struct MenuItem *item;
char   buffer[60];
struct MealNode *mnode;
struct NameNode *node, *nextnode;
struct List *list;
struct Gadget *gad;
char   *items, *amounts, *sizes;
BPTR   pfile;
int    i;

done = FALSE;
while (FALSE == done)
    {
    /* we only have one signal bit, so we do not have to check which
    ** bit broke the Wait().
    */
    Wait(1L << window->UserPort->mp_SigBit);

    while ( (FALSE == done) &&
            (NULL != (msg = (struct IntuiMessage *)GT_GetIMsg(window->UserPort))))
    {
        class = msg->Class;
        code  = msg->Code;
        mousex= msg->MouseX;
        mousey= msg->MouseY;
        gad   = (struct Gadget *)msg->IAddress; /*not valid for non-gadget event*/
        
        GT_ReplyIMsg(msg);
        
        switch (class)
            {
            case IDCMP_MENUPICK:
                menuNumber = code;
                while (menuNumber != MENUNULL) 
                    {
                    item = ItemAddress(menuStrip, menuNumber);

                    /* process the item here! */
                    menuNum = MENUNUM(menuNumber);
                    itemNum = ITEMNUM(menuNumber);
                    subNum  = SUBNUM(menuNumber);

                    /* stop if quit is selected. */
                    switch ( menuNum )
                    {
                       case 0:         /*** PROJECT ***/
                          switch ( itemNum )
                          {
                             case 0:   /* NEW */
                                 doNew();
                                 break;
                                 
                             case 1:   /* OPEN... */
                                 doOpen();
                                 break;
                             
                             case 4:   /* SAVE AS ... */
                                 savefilename[0] = '\0';    
                             case 3:   /* SAVE */
                                 doSave();
                                 break;
                             
                             case 6:   /* PRINT */
                                 doPrint();
                                 break;
                             
                             case 8:   /* ABOUT */
                                 sprintf(buffer,"%s\nBrian Gragg  Oct 1993 ",&vers[7]);
                                 EasyRequest(window, &myES, NULL,buffer);
                                 break;
                                 
                             case 10:   /* QUIT */
                                 done = TRUE;
                                 break;
                          }
                          break;
                          
                       case 1:        /*** MEALS ***/
                         switch (itemNum )
                         {
                           case 0:    /* CREATE MEAL */
                               newMeal();
                               break;
                         }
                          
                       case 2:        /*** OPTIONS ***/
                         switch (itemNum )
                         {
                           case 0:    /* SCROLLING LIST */
                               break;
                         }
                    }           
                               
                    menuNumber = item->NextSelect;
                    }
                break;
            
            case IDCMP_GADGETUP:
               switch (gad->GadgetID)
               {
                   case MYGAD_MEALS:
                       GT_SetGadgetAttrs(mygad[MYGAD_GLIST],window,NULL,
                               GTLV_Labels, ~0, TAG_DONE);
                       if ((mnode = (struct MealNode *)FindNode(MealList,code))==NULL)
                           break;    /* not a valid mnode */
                       list = mnode->nn_MealItem;
                       if (list->lh_TailPred == (struct Node *)list)
                           break;  /* empty list */
                       for (node=(struct NameNode *)list->lh_Head ; 
                              node->nn_Node.ln_Succ ; 
                              node = (struct NameNode *)node->nn_Node.ln_Succ)
                           AddItem(GrocList,node->nn_Item,node->nn_Amount,
                                           node->nn_Size,node->nn_Aisle);
                       GT_SetGadgetAttrs(mygad[MYGAD_GLIST],window,NULL,
                               GTLV_Labels, GrocList, TAG_DONE);
                       currentGroc = NOITEM;
                       ActivateGadget(mygad[MYGAD_ITEM],window,NULL);
                       break;
                        
                   case MYGAD_ILIST:
                       if (NULL == 
                         (node = (struct NameNode *)FindNode(ItemList,code)))
                           break;    /* not a valid node */
                       node->nn_ListPos = code;
                       getItem(node);
                       break;
                       
                   case MYGAD_ITEM:
                       if (code == 0x5F)   /* HELP key */
                       {
                           node = findBestFit(((struct StringInfo *)mygad[MYGAD_ITEM]->SpecialInfo)->Buffer);
                           if (node != NULL) 
                           {
                               getItem(node);
                               GT_SetGadgetAttrs(mygad[MYGAD_ILIST],window,NULL,
                                          GTLV_Top, node->nn_ListPos, TAG_DONE);      
                           }
                           break;
                       }
                   case MYGAD_AMOUNT:
                   case MYGAD_SIZE:
                       if (code == 9) break;  /* ignore tab key */
                       items = ((struct StringInfo *)mygad[MYGAD_ITEM]->SpecialInfo)->Buffer;
                       amounts = ((struct StringInfo *)mygad[MYGAD_AMOUNT]->SpecialInfo)->Buffer;
                       sizes = ((struct StringInfo *)mygad[MYGAD_SIZE]->SpecialInfo)->Buffer;

                       if ((strlen(items) < 3) || (strlen(amounts) < 0) ||
                           (strlen(sizes) < 1) || (currentAisle == NOITEM))
                       {
                           DisplayBeep(myscreen);
                           break;
                       }
                           
                       GT_SetGadgetAttrs(mygad[MYGAD_GLIST],window,NULL,
                               GTLV_Labels, ~0, TAG_DONE);
                       AddItem(GrocList, items, amounts, sizes, currentAisle);
                          
                       GT_SetGadgetAttrs(mygad[MYGAD_GLIST],window,NULL,
                               GTLV_Labels, GrocList, TAG_DONE);
                       currentGroc = NOITEM;
                       /* now clear the string gadgets */
                       GT_SetGadgetAttrs(mygad[MYGAD_ITEM],window,NULL,
                               GTST_String, "", TAG_DONE);
                       GT_SetGadgetAttrs(mygad[MYGAD_AMOUNT],window,NULL,
                               GTST_String, "", TAG_DONE);
                       GT_SetGadgetAttrs(mygad[MYGAD_SIZE],window,NULL,
                               GTST_String, "", TAG_DONE);
                       GT_SetGadgetAttrs(mygad[MYGAD_AISLE],window,NULL,
                               GTLV_Selected, NOITEM, TAG_DONE);
                       ActivateGadget(mygad[MYGAD_ITEM],window,NULL);
                       currentAisle = NOITEM;
                       break;
                       
                   case MYGAD_AISLE:
                       currentAisle = code;
                       ActivateGadget(mygad[MYGAD_AMOUNT],window,NULL);
                       break;
                       
                   case MYGAD_EDIT:
                       if (NULL == 
                         (node = (struct NameNode *)FindNode(GrocList,currentGroc)))
                           break;    /* not a valid node */
                       GT_SetGadgetAttrs(mygad[MYGAD_ITEM],window,NULL,
                               GTST_String, node->nn_Item, TAG_DONE);
                       GT_SetGadgetAttrs(mygad[MYGAD_AMOUNT],window,NULL,
                               GTST_String, node->nn_Amount, TAG_DONE);
                       GT_SetGadgetAttrs(mygad[MYGAD_SIZE],window,NULL,
                               GTST_String, node->nn_Size, TAG_DONE);
                       GT_SetGadgetAttrs(mygad[MYGAD_AISLE],window,NULL,
                               GTLV_Selected, node->nn_Aisle, TAG_DONE);
                       ActivateGadget(mygad[MYGAD_AMOUNT],window,NULL);
                       currentAisle = node->nn_Aisle;
                   case MYGAD_DELETE:
                       if (NULL == 
                          (node = (struct NameNode *)FindNode(GrocList,currentGroc)))
                           break;    /* not a valid node */
                       GT_SetGadgetAttrs(mygad[MYGAD_GLIST],window,NULL,
                               GTLV_Labels, ~0, TAG_DONE);
                       Remove((struct Node *)node);
                       GT_SetGadgetAttrs(mygad[MYGAD_GLIST],window,NULL,
                               GTLV_Labels, GrocList, TAG_DONE);
                       FreeMem(node,sizeof(struct NameNode));
                       currentGroc = NOITEM;
                       ActivateGadget(mygad[MYGAD_ITEM],window,NULL);
                       break;
  
                   case MYGAD_GLIST:
                       currentGroc = code;
                       ActivateGadget(mygad[MYGAD_ITEM],window,NULL);
                       break;
                       
                   case MYGAD_SORT:
                   case MYGAD_SORTNAME:
                       doSort((int)gad->GadgetID);
                       break;
                   
                   case MYGAD_ADD:
                       items = ((struct StringInfo *)mygad[MYGAD_ITEM]->SpecialInfo)->Buffer;
                       amounts = ((struct StringInfo *)mygad[MYGAD_AMOUNT]->SpecialInfo)->Buffer;
                       sizes = ((struct StringInfo *)mygad[MYGAD_SIZE]->SpecialInfo)->Buffer;

                       if ((strlen(items) < 3) || (strlen(amounts) < 1) ||
                           (strlen(sizes) < 1) || (currentAisle == NOITEM))
                       {
                           DisplayBeep(myscreen);  /* bad data */
                           break;
                       }
                       
                       /* Save the new item to the DATAFILE */
                       
                       if (!(pfile = Open(DATAFILE,MODE_OLDFILE)))
                       {
                           EasyRequest(window, &myES, NULL, "Couldn't open data file");
                           break;
                       }
                       
                       Seek(pfile,0,OFFSET_END);
                       for (i = 0; i < 30; i++)
                           if (aisleId[i] == currentAisle)
                               break;
                       sprintf(buffer, "%s`%s`%s`%d\n", items, amounts,
                                   sizes, i);
                       Write(pfile, buffer, strlen(buffer));
                       Close(pfile);
                       
                       /* Update the Item List */
                       GT_SetGadgetAttrs(mygad[MYGAD_ILIST],window,NULL,
                               GTLV_Labels, ~0, TAG_DONE);
                       
                       AddName(ItemList, items, amounts, sizes, currentAisle);
                          
                       GT_SetGadgetAttrs(mygad[MYGAD_ILIST],window,NULL,
                               GTLV_Labels, ItemList, TAG_DONE);
                       ActivateGadget(mygad[MYGAD_AMOUNT],window,NULL);
                       break;
                       
                   default:
                       break;
               }
            case IDCMP_REFRESHWINDOW:
               GT_BeginRefresh(window);
               GT_EndRefresh(window, TRUE);
               break;
   
            default:
               break;
               
            }
        }
    }
}

