#include <CrashTickHatch.h>

#define VERSION      "1.01"
#define COPYRIGHT    "1997"

#define STACKSIZE 20000

#ifdef __SASC__
   const UBYTE ver[]="\0$VER: CrashTickHatch " VERSION " " AMIGADATE ;
#endif

#ifdef _DCC
   const UBYTE ver[]="\0$VER: CrashTickHatch "VERSION" ("__COMMODORE_DATE__")";
#endif

struct Screen *scr;
struct Menu *menus;

struct LayoutHandle *mainhandle;
struct Window *mainwin;

#ifdef _DCC
void _waitwbmsg(void);
routine_that_is_never_called() { _waitwbmsg(); }
#endif

extern struct WBStartup *_WBMsg;

extern struct ExecBase *SysBase;
extern struct Library *GadToolsBase;

struct Library *AmigaGuideBase;
struct Library *ReqToolsBase;
struct Library *GTLayoutBase;

struct MsgPort *WBAppPort;
struct AppWindow *appwindow;

struct Library *LocaleBase;
struct Catalog *catalog;

APTR mempool;

struct NewAmigaGuide nag;
AMIGAGUIDECONTEXT handle;
BOOL amigaguide,amigaguideerr;

UBYTE arg_Settings[100]="";
UBYTE arg_PubScreen[100]="";
UBYTE arg_Helpfile[100]="PROGDIR:CrashTick.guide";
UBYTE arg_CrashTick[100]="MAIL:CrashTick";
UBYTE arg_Window[100]="CON://///WAIT/AUTO";

struct List cfg_AreaList;
struct Area *hatcharea;

__asm void (*own_StackSwap)(register __A0 struct StackSwapStruct *newstack,register __A6 struct Library *library);
struct StackSwapStruct stackswapstruct;

/* All AmigaGuide junk */

UBYTE *Context[] = {
   "CRASHTICKHATCH"
   NULL };

void SetFile(UBYTE *file);
void mystrncpy(uchar *dest,uchar *src,ulong len);
BOOL OpenReq(UBYTE *file,ULONG varsize,UBYTE *title,struct Window *win);
short jbstrcpy(char *dest,char *src,long maxlen);
LONG AskList(struct List *list,UBYTE *title,struct Window *win);
void Hatch(void);

void ShowAmigaGuideHelp(ULONG num);
void HandleAmigaGuide(void);

void HandleAmigaGuide(void)
{
   struct AmigaGuideMsg *agm;

   if(AmigaGuideBase)
   {
      while(agm = (struct AmigaGuideMsg *) GetAmigaGuideMsg(handle))
      {
         switch(agm->agm_Type)
         {
            case ActiveToolID:
                  amigaguide=TRUE;
                  break;
            case ToolStatusID:
                  if(agm->agm_Pri_Ret)
                     amigaguideerr=TRUE;

                  break;
         }
         ReplyAmigaGuideMsg( agm );
      }
   }
}

void LoadAmigaGuide(UBYTE *filename)
{
   ULONG sig,retsig;
   static UBYTE filenamebuf[200];

   strcpy(filenamebuf,filename);

   amigaguide=FALSE;
   amigaguideerr=FALSE;

   nag.nag_Name=filenamebuf;
   nag.nag_BaseName="CrashMail";
   nag.nag_Context=Context;
   nag.nag_Screen=scr;

   if(AmigaGuideBase=(struct Library *)OpenLibrary("amigaguide.library",34))
   {
      sig=0;

      if(handle=(AMIGAGUIDECONTEXT)OpenAmigaGuideAsyncA(&nag,NULL))
         sig = AmigaGuideSignal(handle);

      if(sig)
      {
         HandleAmigaGuide();

         while(!amigaguide && !amigaguideerr)
         {
            retsig=Wait(sig);
            HandleAmigaGuide();
         }
      }
   }
}

void ShowAmigaGuideHelp(ULONG num)
{
   if(amigaguide==FALSE && amigaguideerr==FALSE)
   {
      if(AmigaGuideBase=(struct Library *)OpenLibrary("amigaguide.library",34))
      {
         if(arg_Helpfile[0]!=0)
         {
            LoadAmigaGuide(arg_Helpfile);
         }
         else
         {
            LoadAmigaGuide("PROGDIR:CrashTick.guide");
            if(!amigaguide) LoadAmigaGuide("HELP:english/CrashTick.guide");
         }
      }
   }

   if(amigaguide)
   {
      SetAmigaGuideContextA(handle,num,NULL);
      SendAmigaGuideContextA(handle,NULL);
   }
   else
   {
      DisplayBeep(NULL);
   }
}

void FreeAmigaGuide(void)
{
   struct AmigaGuideMsg *agm;

   if(AmigaGuideBase)
   {
      if(handle)
      {
         if(amigaguide || amigaguideerr)
         {
            while(agm = (struct AmigaGuideMsg *)GetAmigaGuideMsg(handle))
            {
                ReplyAmigaGuideMsg( agm );
            }
         }
         else
         {
            /* if AG is not ready wait until we get the ActiveToolID before
            ** we exit
            */
            while(!amigaguide)
            {
               HandleAmigaGuide();        /* clear amigaguide messages */
               Delay(5);                  /* 100 ms */
            }
         }
         CloseAmigaGuide(handle);
      }
      CloseLibrary(AmigaGuideBase);
   }
}

/* Help hook */

__asm __saveds ULONG HelpHookEntry(register __a0 struct Hook *hook,register __a2 struct HelpMsg *helpmsg,register __a1 struct IBox *ibox)
{
   ShowAmigaGuideHelp((LONG)hook->h_Data);
   return(0);
}

struct Hook MainHelpHook = { {NULL}, HelpHookEntry,NULL,HELP_CRASHTICKHATCH};

/* Locale hook */

__asm __saveds ULONG LocaleHookEntry(register __a0 struct Hook *hook,register __a2 struct LayoutHandle *handle,register __a1 LONG ID)
{
   return (ULONG)getString(ID);
}

struct Hook LocaleHook = { {NULL}, LocaleHookEntry,NULL,NULL};

/* EditHook */

#define IEQUALIFIER_SHIFT     (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)

/* EditHook that also takes you to the next string gadget when return is pressed */

__asm __saveds ULONG StrEditHookEntryNext (register __a0 struct Hook *hook,register __a2 struct SGWork *sgw,register __a1 ULONG *msg)
{
   int qual,rawcode;

   if (msg[0] == SGH_KEY)
   {
      rawcode = sgw->IEvent->ie_Code;
      qual = sgw->IEvent->ie_Qualifier;
      if (sgw->EditOp == EO_INSERTCHAR   || sgw->EditOp == EO_REPLACECHAR  || sgw->EditOp == EO_BADFORMAT    ||
         (sgw->EditOp == EO_NOOP && sgw->Actions == (SGA_USE|SGA_BEEP) && sgw->NumChars == (sgw->StringInfo->MaxChars - 1)))
      {
         if ((qual & IEQUALIFIER_RCOMMAND) || sgw->Code == 27)
         {
            sgw->Actions &= ~(SGA_USE|SGA_BEEP|SGA_REDISPLAY);
            sgw->IEvent->ie_Qualifier &= ~IEQUALIFIER_RCOMMAND;

            if (!(qual & IEQUALIFIER_REPEAT))
            {
               sgw->Actions |= SGA_REUSE|SGA_END;
               /* sgw->Code = KEYB_SHORTCUT; */
            }
         }
      }
      if(sgw->EditOp == EO_ENTER)
      {
         sgw->Actions=SGA_END;

         if(sgw->IEvent->ie_Qualifier & IEQUALIFIER_SHIFT)
            sgw->Actions |= SGA_PREVACTIVE;

         else
            sgw->Actions |= SGA_NEXTACTIVE;
      }
      return(TRUE);
   }
   return (FALSE);
}

struct Hook StrEditHookNext = { { NULL }, StrEditHookEntryNext, NULL, NULL };

void myputs(UBYTE *str)
{
   Write(Output(),str,strlen(str));
}

uchar wintitle[100];
uchar aboutbuf[2000];

void ShowError(char *fmt,...)
{
   va_list args;

   va_start(args,fmt);

   if(_WBMsg)
   {
      rtEZRequestTags(fmt,getString(PREFS_TXT_OK),NULL,args,
            RT_Underscore,    '_',
            RTEZ_ReqTitle,    getString(HATCHGUI_REQ_ERROR_TITLE),
            RTEZ_Flags,       EZREQF_CENTERTEXT,
            RT_Window,        mainwin,
            TAG_END);
   }
   else
   {
      VFPrintf(Output(),fmt,args);
      FPrintf(Output(),"\n");
   }

   va_end(args);
}

BOOL ReadConfig(void)
{
   BPTR fh;
   UBYTE line[500],keyword[50],buf[200];
   struct Area *area;

   if(arg_Settings[0] == 0)
   {
      if(!(fh=Open("PROGDIR:CrashTick.prefs",MODE_OLDFILE)))
      {
         if(!(fh=Open("MAIL:CrashTick.prefs",MODE_OLDFILE)))
         {
            sprintf(buf,getString(HATCHGUI_FAILED_CONFIG));

            rtEZRequestTags(buf,getString(HATCHGUI_TXT_OK),NULL,NULL,
                  RT_Underscore,    '_',
                  RTEZ_ReqTitle,    getString(HATCHGUI_REQ_ERROR_TITLE),
                  RTEZ_Flags,       EZREQF_CENTERTEXT,
                  RT_Window,        mainwin,
                  TAG_END);

            return(FALSE);
         }
      }
   }
   else
   {
      if(!(fh=Open(arg_Settings,MODE_OLDFILE)))
      {
         sprintf(buf,getString(HATCHGUI_FAILED_CONFIG_NAME),arg_Settings);

         rtEZRequestTags(buf,getString(HATCHGUI_TXT_OK),NULL,NULL,
               RT_Underscore,    '_',
               RTEZ_ReqTitle,    getString(HATCHGUI_REQ_ERROR_TITLE),
               RTEZ_Flags,       EZREQF_CENTERTEXT,
               RT_Window,        mainwin,
               TAG_END);

         return(FALSE);
      }
   }

   while(FGets(fh,line,490))
   {
      jbcpos=0;

      if(jbstrcpy(keyword,line,40))
      {
         if(stricmp(keyword,"AREA")==0)
         {
            if(jbstrcpy(buf,line,80))
            {
               if(!(area=(struct Area *)LibAllocPooled(mempool,sizeof(struct Area))))
               {
                  DisplayBeep(NULL);
                  Close(fh);
                  return(FALSE);
               }
            }

            area->Node.ln_Type=0;
            area->Node.ln_Pri=0;
            area->Node.ln_Name=area->Name;

            strcpy(area->Name,buf);
            AddTail(&cfg_AreaList,(struct Node *)area);
         }

         if(stricmp(keyword,"UNCONFIRMED")==0)
         {
            /* Remove last node if there is one */

            if(cfg_AreaList.lh_Head->ln_Succ)
            {
               area=RemTail(&cfg_AreaList);
               LibFreePooled(mempool,area,sizeof(struct Area));
            }
         }
      }
   }

   Close(fh);
   return(TRUE);
}

struct NewMenu newmenus[] = { {NM_TITLE,"","",0,0,NULL},                     /* >Project    */
                              {NM_ITEM, "","?",0,0,NULL},                    /* About...    */
                              {NM_ITEM, (STRPTR)NM_BARLABEL,NULL,0,0,NULL},
                              {NM_ITEM, "","",0,0,NULL},                     /* Quit        */
                              {NM_END,  "","",0,0,NULL}};

#define SETTINGS  0
#define PUBSCREEN 1
#define HELPFILE  2
#define CRASHTICK 3
#define WINDOW    4

void realmain(void);

void _main(void)
{
   struct Process *myproc;

   if(SysBase->LibNode.lib_Version<37)
   {
      myputs("Sorry! This program requires Kickstart 2.04 or higher\n");
      _exit(0);
   }

   myproc=FindTask(NULL);

   if(myproc->pr_Task.tc_SPUpper-myproc->pr_Task.tc_SPLower < STACKSIZE)
   {
      /* Only allocate stack if original stack smaller */

      if(!(stackswapstruct.stk_Lower = AllocMem(STACKSIZE,MEMF_PUBLIC)))
      {
         Printf("Failed to allocate memory for new stack\n");
         exit(10);
      }

      stackswapstruct.stk_Upper   = (ULONG)stackswapstruct.stk_Lower + STACKSIZE;
      stackswapstruct.stk_Pointer = (APTR)stackswapstruct.stk_Upper;

      /* This trick is needed, otherwise DICE will use stack when swapping... */


      own_StackSwap=(void *)((ULONG)SysBase-(ULONG)732);
      (*own_StackSwap)(&stackswapstruct,(struct Library *)SysBase);
   }

   realmain();
}

void realmain(void)
{
   short gid;
   ULONG class,code;
   APTR lock;
   ULONG num,sigs,c;
   struct IntuiMessage *IntuiMessage;
   APTR iaddress;
   struct MenuItem *menuitem;
   LONG res;
   UBYTE buf[200];

   NewList(&cfg_AreaList);

   if(LocaleBase=OpenLibrary("locale.library",37))
   {
      catalog=OpenCatalog(NULL,"crashtick.catalog",OC_BuiltInLanguage, "english",
                                                                       OC_Version,  2L,
                                                                       TAG_DONE );
   }

   if(!(mempool=LibCreatePool(MEMF_ANY,10000,1000)))
   {
      ShowError("%s",getString(HATCHGUI_ERR_NO_MEMORYPOOL));
      CleanUp(10);
   }

   if(!(ReqToolsBase=OpenLibrary(REQTOOLSNAME,REQTOOLSVERSION)))
   {
      ShowError(getString(HATCHGUI_ERR_LIB_VER_NEEDED),REQTOOLSNAME,REQTOOLSVERSION);
      CleanUp(10);
   }

   if(!(GTLayoutBase=OpenLibrary("gtlayout.library",24)))
   {
      ShowError(getString(HATCHGUI_ERR_LIB_VER_NEEDED),"gtlayout.library",24);
      CleanUp(10);
   }

   if(!(WBAppPort = CreateMsgPort()))
   {
      ShowError(getString(HATCHGUI_ERR_NO_MSGPORT),"gtlayout.library",24);
      CleanUp(10);
   }

   if(_WBMsg)
   {
      struct DiskObject *dobj;
      UBYTE *what;
      BPTR olddir;

      olddir=CurrentDir(_WBMsg->sm_ArgList->wa_Lock);

      if(!(dobj=GetDiskObject(_WBMsg->sm_ArgList->wa_Name)))
      {
         CurrentDir(olddir);
         CleanUp(10);
      }

      if(what=FindToolType(dobj->do_ToolTypes,"SETTINGS"))
      {
         strncpy(arg_Settings,what,98);
         arg_Settings[99]=0;
      }

      if(what=FindToolType(dobj->do_ToolTypes,"PUBSCREEN"))
      {
         strncpy(arg_PubScreen,what,98);
         arg_PubScreen[99]=0;
      }

      if(what=FindToolType(dobj->do_ToolTypes,"HELPFILE"))
      {
         strncpy(arg_Helpfile,what,98);
         arg_Helpfile[99]=0;
      }

      if(what=FindToolType(dobj->do_ToolTypes,"CRASHTICK"))
      {
         strncpy(arg_CrashTick,what,98);
         arg_CrashTick[99]=0;
      }

      if(what=FindToolType(dobj->do_ToolTypes,"WINDOW"))
      {
         strncpy(arg_Window,what,98);
         arg_Window[99]=0;
      }

      FreeDiskObject(dobj);
      CurrentDir(olddir);
   }
   else
   {
      struct RDArgs *rdargs;
      UBYTE *argstr="SETTINGS,PUBSCREEN=PS/K,HELPFILE/K,CRASHTICK/K,WINDOW/K";
      LONG argarray[]={NULL,NULL,NULL,NULL,NULL};

      if(!(rdargs=ReadArgs(argstr,argarray,NULL)))
      {
         PrintFault(IoErr(),"");
         CleanUp(10);
      }

      if(argarray[SETTINGS]) strcpy(arg_Settings,(UBYTE *)argarray[SETTINGS]);
      if(argarray[PUBSCREEN]) strcpy(arg_PubScreen,(UBYTE *)argarray[PUBSCREEN]);
      if(argarray[HELPFILE]) strcpy(arg_Helpfile,(UBYTE *)argarray[HELPFILE]);
      if(argarray[CRASHTICK]) strcpy(arg_CrashTick,(UBYTE *)argarray[CRASHTICK]);
      if(argarray[WINDOW]) strcpy(arg_Window,(UBYTE *)argarray[WINDOW]);

      FreeArgs(rdargs);
   }

   if(!(scr=LockPubScreen(arg_PubScreen)))
   {
      if(!(scr=LockPubScreen(NULL)))
      {
         ShowError(getString(HATCHGUI_ERR_NO_PUBLIC_SCREEN),arg_PubScreen);
         CleanUp(10);
      }
   }

   mainhandle = LT_CreateHandleTags(scr,
      LH_AutoActivate,  FALSE,
      LH_LocaleHook,  &LocaleHook,
      TAG_DONE);

   if(!mainhandle)
   {
      DisplayBeep(NULL);
      CleanUp(10);
   }

   newmenus[0].nm_Label    = getString(HATCHGUI_MENU_PROJECT);

   newmenus[1].nm_Label    = getString(HATCHGUI_MENU_ABOUT)+2;
   newmenus[1].nm_CommKey  = getString(HATCHGUI_MENU_ABOUT);

   newmenus[3].nm_Label    = getString(HATCHGUI_MENU_QUIT)+2;
   newmenus[3].nm_CommKey  = getString(HATCHGUI_MENU_QUIT);

   menus=LT_LayoutMenus(mainhandle,newmenus,GTMN_FrontPen,        0L,
                                            GTMN_TextAttr,        scr->Font,
                                            GTMN_NewLookMenus,    TRUE,
                                            LH_MenuGlyphs,        TRUE,
                                            TAG_DONE);

	if(!menus)
   {
      DisplayBeep(NULL);
      CleanUp(0);
   }

   LT_New(mainhandle,
      LA_Type,      VERTICAL_KIND,
      TAG_DONE);

       LT_New(mainhandle,
         LA_Type,      VERTICAL_KIND,
         LA_LabelID,   HATCHGUI_GROUP_FILE_TO_HATCH,
         LA_Chars,     40,
         TAG_DONE);

          LT_New(mainhandle,
            LA_Type,      STRING_KIND,
            LA_LabelID,   HATCHGUI_GADGET_FILENAME,
            LA_Chars,     40,
            LA_ID,        1,
            LAST_Picker,  TRUE,
            TAG_DONE);

          LT_New(mainhandle,
            LA_Type,      TEXT_KIND,
            LA_LabelID,   HATCHGUI_GADGET_AREA,
            LA_Chars,     40,
            LATX_Picker,  TRUE,
            GTTX_Border,  TRUE,
            LA_ID,        2,
            TAG_DONE);

          LT_New(mainhandle,
            LA_Type,      STRING_KIND,
            LA_LabelID,   HATCHGUI_GADGET_DESCRIPTION,
            LA_Chars,     40,
            LA_ID,        3,
            TAG_DONE);

          LT_New(mainhandle,
            LA_Type,      STRING_KIND,
            LA_LabelID,   HATCHGUI_GADGET_REPLACES,
            LA_Chars,     40,
            LA_ID,        4,
            TAG_DONE);

          LT_New(mainhandle,
            LA_Type,      STRING_KIND,
            LA_LabelID,   HATCHGUI_GADGET_MAGIC,
            LA_Chars,     40,
            LA_ID,        5,
            GTST_MaxChars,8,
            TAG_DONE);

      LT_EndGroup(mainhandle);

      LT_New(mainhandle,
         LA_Type,      VERTICAL_KIND,
         LA_Chars,     40,
         TAG_DONE);

      LT_New(mainhandle,
         LA_Type,      BUTTON_KIND,
         LA_LabelID,   HATCHGUI_BUTTON_HATCH,
         LA_ID,        7,
         TAG_DONE);

      LT_EndGroup(mainhandle);

   LT_EndGroup(mainhandle);

   sprintf(wintitle,getString(HATCHGUI_MAINWIN_TITLE),VERSION,COPYRIGHT);

   mainwin=LT_Build(mainhandle,LAWN_IDCMP,    IDCMP_CLOSEWINDOW,
                               LAWN_Menu,     menus,
                               LAWN_HelpHook, &MainHelpHook,
                               LAWN_Title,    wintitle,
                               WA_Flags,      WFLG_ACTIVATE|WFLG_CLOSEGADGET|WFLG_DEPTHGADGET|WFLG_DRAGBAR|WFLG_NEWLOOKMENUS,
                               TAG_END);

   if(!mainwin)
   {
      DisplayBeep(NULL);
      CleanUp(0);
   }

   appwindow=(struct AppWindow *)AddAppWindow(0,NULL,mainwin,WBAppPort,TAG_END);

   lock=rtLockWindow(mainwin);

   if(!ReadConfig())
   {
      rtUnlockWindow(mainwin,lock);
      CleanUp(10);
   }

   rtUnlockWindow(mainwin,lock);

   for(;;)
   {
      sigs = Wait(1<<mainwin->UserPort->mp_SigBit | 1<<WBAppPort->mp_SigBit);

      if(sigs & 1<<mainwin->UserPort->mp_SigBit)
      {
         while(IntuiMessage=(struct IntuiMessage *)LT_GetIMsg(mainhandle))
         {
            class=IntuiMessage->Class;
            iaddress=IntuiMessage->IAddress;
            code=IntuiMessage->Code;

            LT_ReplyIMsg(IntuiMessage);

            switch(class)
            {
               case IDCMP_CLOSEWINDOW:   CleanUp(0);
                                         break;

               case IDCMP_IDCMPUPDATE:   gid=((struct Gadget *)iaddress)->GadgetID;

                                         switch(gid)
                                         {
                                            case 1:
                                               mystrncpy(buf,(uchar *)LT_GetAttributes(mainhandle,1,TAG_DONE),200);

                                               if(OpenReq(buf,200,getString(HATCHGUI_SELECT_FILE),mainwin))
                                                  SetFile(buf);

                                               break;

                                            case 2:
                                               res=AskList(&cfg_AreaList,getString(HATCHGUI_SELECT_AREA),mainwin);
                                               
                                               if(res!=-1)
                                               {
                                                  hatcharea=(struct Area *)cfg_AreaList.lh_Head;

                                                  for(c=0;c<res;c++)
                                                     hatcharea=(struct Area *)hatcharea->Node.ln_Succ;

                                                  LT_SetAttributes(mainhandle,2,GTTX_Text,hatcharea->Name,TAG_DONE);
                                               }
                                               break;
                                         }
                                         break;

               case IDCMP_GADGETUP:      gid=((struct Gadget *)iaddress)->GadgetID;

                                         if(gid == 7)
                                            Hatch();

                                         break;

               case IDCMP_MENUPICK:      num=code;
                                         while(num!=MENUNULL)
                                         {
                                            if(MENUNUM(num)==0)
                                            {
                                               switch(ITEMNUM(num))
                                               {
                                                  case 0: sprintf(aboutbuf,getString(HATCHGUI_ABOUT),VERSION,COPYRIGHT);

                                                          rtEZRequestTags(aboutbuf,getString(HATCHGUI_TXT_OK),NULL,NULL,
                                                                                                   RT_Underscore,'_',
                                                                                                   RT_Window,mainwin,
                                                                                                   RT_WaitPointer,TRUE,
                                                                                                   RT_LockWindow, TRUE,
                                                                                                   RTEZ_Flags, EZREQF_CENTERTEXT,
                                                                                                   TAG_END);
                                                          break;

                                                  case 2: CleanUp(0);
                                                          break;
                                               }
                                            }

                                            menuitem=ItemAddress(menus,num);
                                            num=menuitem->NextSelect;
                                         }
                                         break;
            }
         }
      }

      if(sigs & 1<<WBAppPort->mp_SigBit)
      {
         BPTR olddir,l;
         struct AppMessage *appmsg;
         UBYTE name[200];
         ULONG c;
         struct WBArg *arglist;

         while(appmsg = (struct AppMessage *)GetMsg(WBAppPort))
         {
            if(appmsg->am_Type = AMTYPE_APPWINDOW)
            {
               arglist=appmsg->am_ArgList;

               for(c=0;c<appmsg->am_NumArgs;c++)
               {
                  olddir=CurrentDir(arglist->wa_Lock);

                  if(l=Lock(arglist->wa_Name,SHARED_LOCK))
                  {
                     NameFromLock(l,name,199);
                     UnLock(l);
                     SetFile(name);
                  }

                  CurrentDir(olddir);
               }
            }
            ReplyMsg((struct Message *)appmsg);
         }
      }
   }
}

void CleanUp(int err)
{
   struct Area *area;

   while(area=(struct MyNode *)RemHead(&cfg_AreaList))
      LibFreePooled(mempool,area,sizeof(struct Area));

   FreeAmigaGuide();

   if(appwindow)
      RemoveAppWindow(appwindow);

   if(mainhandle)
   {
      ClearMenuStrip(mainhandle->Window);
      LT_DeleteHandle(mainhandle);
   }

   if(menus)
	   FreeMenus(menus);

   if(scr)
      UnlockPubScreen(NULL,scr);

   if(catalog)
      CloseCatalog(catalog);

   if(LocaleBase)
      CloseLibrary(LocaleBase);

   if(ReqToolsBase) CloseLibrary(ReqToolsBase);
   if(GTLayoutBase) CloseLibrary(GTLayoutBase);

   if(WBAppPort)
   {
      struct AppMessage *appmsg;

      while(appmsg=(struct AppMessage *)GetMsg(WBAppPort))
         ReplyMsg((struct Message *)appmsg);

      DeleteMsgPort(WBAppPort);
   }

   if(mempool)
      LibDeletePool(mempool);

   if(stackswapstruct.stk_Lower)
   {
      /* This trick is needed, otherwise DICE will use stack... */

      own_StackSwap=(void *)((ULONG)SysBase-(ULONG)732);
      (*own_StackSwap)(&stackswapstruct,(struct Library *)SysBase);

      FreeMem(stackswapstruct.stk_Lower,STACKSIZE);
   }

   _exit(err);
}

void SetFile(UBYTE *file)
{
   struct FileInfoBlock *fib;
   BPTR l;
   UBYTE errbuf[200];

   LT_SetAttributes(mainhandle,1,GTST_String,file,TAG_END);

   if(!(fib=LibAllocPooled(mempool,sizeof(struct FileInfoBlock))))
   {
      DisplayBeep(NULL);
      return;
   }

   if(!(l=Lock(file,SHARED_LOCK)))
   {
      sprintf(errbuf,getString(HATCHGUI_FILE_NOT_FOUND),file);

      rtEZRequestTags(errbuf,getString(HATCHGUI_TXT_OK),NULL,NULL,
            RT_Underscore,    '_',
            RTEZ_ReqTitle,    getString(HATCHGUI_REQ_ERROR_TITLE),
            RTEZ_Flags,       EZREQF_CENTERTEXT,
            RT_Window,        mainwin,
            TAG_END);

      LibFreePooled(mempool,fib,sizeof(struct FileInfoBlock));
      return;
   }

   Examine(l,fib);

   if(fib->fib_DirEntryType > 0)
   {
      sprintf(errbuf,getString(HATCHGUI_FILE_IS_DIR),file);

      rtEZRequestTags(errbuf,getString(HATCHGUI_TXT_OK),NULL,NULL,
            RT_Underscore,    '_',
            RTEZ_ReqTitle,    getString(HATCHGUI_REQ_ERROR_TITLE),
            RTEZ_Flags,       EZREQF_CENTERTEXT,
            RT_Window,        mainwin,
            TAG_END);

      LibFreePooled(mempool,fib,sizeof(struct FileInfoBlock));
      UnLock(l);
      return;
   }

   LT_SetAttributes(mainhandle,3,GTST_String,fib->fib_Comment,TAG_END);

   UnLock(l);
   LibFreePooled(mempool,fib,sizeof(struct FileInfoBlock));
}

void mystrncpy(uchar *dest,uchar *src,ulong len)
{
   strncpy(dest,src,len-1);
   dest[len-1]=0;
}

BOOL OpenReq(UBYTE *file,ULONG varsize,UBYTE *title,struct Window *win)
{
   APTR req;
   UBYTE buf[200],dir[200];
   APTR res;

   if(!(req=rtAllocRequest(RT_FILEREQ,TAG_END)))
   {
      DisplayBeep(NULL);
      return(FALSE);
   }

   strcpy(buf,FilePart(file));

   strcpy(dir,file);
   *(PathPart(dir))=0;

   rtChangeReqAttr(req,RTFI_Dir,dir,TAG_END);

   res = rtFileRequest((struct rtFileRequester *)req,buf,title,RT_Window,      win,
                                                               RT_WaitPointer, TRUE,
                                                               RT_LockWindow,  TRUE,
                                                               TAG_END);

   if(res)
   {
      strncpy(file,((struct rtFileRequester *)req)->Dir,varsize-1);
      file[varsize-1]=0;
      AddPart(file,buf,varsize-1);
   }

   rtFreeRequest(req);

   if(res) return(TRUE);
   return(FALSE);
}

long jbcpos;

short jbstrcpy(char *dest,char *src,long maxlen)
{
   long d=0;
   char stopchar1,stopchar2;

   while(src[jbcpos]==32 || src[jbcpos]==9) jbcpos++;

   if(src[jbcpos]=='"')
   {
      jbcpos++;
      stopchar1='"';
      stopchar2=0;
   }
   else
   {
   	stopchar1=' ';
   	stopchar2=9;
   }

   while(src[jbcpos]!=stopchar1 && src[jbcpos]!=stopchar2 && src[jbcpos]!=10 && src[jbcpos]!=0 && d<maxlen-1)
   {
      if(src[jbcpos]=='\\' && src[jbcpos+1]!=0 && src[jbcpos+1]!=10)
      {
         jbcpos++;
         dest[d++]=src[jbcpos++];
      }

      else
         dest[d++]=src[jbcpos++];
   }
   dest[d]=0;
   if(src[jbcpos]==9 || src[jbcpos]==' ' || src[jbcpos]=='"') jbcpos++;

   if(d!=0 || stopchar1=='"') return(TRUE);

   return(FALSE);
}

/* Asklist */

struct Window *askwin;
struct LayoutHandle *askhandle;
LONG asklistres;

LONG AskList(struct List *list,UBYTE *title,struct Window *win)
{
   struct Node *node;
   struct IntuiMessage *IntuiMessage;
   ULONG class,code,num;
   APTR iaddress;

   LT_LockWindow(win);

   askhandle = LT_CreateHandleTags(win->WScreen,
                  LH_LocaleHook, &LocaleHook,
                  TAG_DONE);

   if(!askhandle)
   {
      DisplayBeep(NULL);
      LT_UnlockWindow(win);
      return(-1);
   }


   LT_New(askhandle,
      LA_Type,      VERTICAL_KIND,
      TAG_DONE);

      LT_New(askhandle,
         LA_Type,       LISTVIEW_KIND,
         LALV_Lines,    15,
         LALV_CursorKey,TRUE,
         LALV_Link,     NIL_LINK,
         LALV_LockSize, TRUE,
         LA_Chars,      40,
         LA_ID,4711,
         TAG_DONE);

      LT_New(askhandle,
         LA_Type,      XBAR_KIND,
         TAG_END);

      LT_New(askhandle,
         LA_Type,      HORIZONTAL_KIND,
         LAGR_SameSize,TRUE,
         TAG_DONE);

         LT_New(askhandle,
            LA_Type,      BUTTON_KIND,
            LA_LabelID,   HATCHGUI_TXT_OK,
            LA_Chars,19,
            GA_Disabled,   TRUE,
            LABT_ReturnKey,TRUE,
            LA_ID,10,
            TAG_DONE);

         LT_New(askhandle,
            LA_Type,      BUTTON_KIND,
            LA_LabelID,   HATCHGUI_TXT_CANCEL,
            LA_Chars,19,
            LA_ID,11,
            TAG_DONE);

      LT_EndGroup(askhandle);

   LT_EndGroup(askhandle);

   askwin=LT_Build(askhandle,LAWN_IDCMP,    IDCMP_CLOSEWINDOW,
                             LAWN_Title,    title,
                             WA_Flags,      WFLG_ACTIVATE|WFLG_CLOSEGADGET|WFLG_DEPTHGADGET|WFLG_DRAGBAR|WFLG_NEWLOOKMENUS,
                             TAG_END);

   if(!askwin)
   {
      LT_DeleteHandle(askhandle);
      DisplayBeep(NULL);
      LT_UnlockWindow(win);
      return(-1);
   }

   LT_SetAttributes(askhandle,4711,GTLV_Labels,list,TAG_END);

   asklistres=-1;

   num=0;

   for(node=list->lh_Head;node->ln_Succ;node=node->ln_Succ)
      num++;

   if(num)
   {
      LT_SetAttributes(askhandle,10,GA_Disabled,FALSE,TAG_END);
      LT_SetAttributes(askhandle,4711,GTLV_Selected,0,TAG_END);
      asklistres=0;
   }

   for(;;)
   {
      while(IntuiMessage=(struct IntuiMessage *)LT_GetIMsg(askhandle))
      {
         class=IntuiMessage->Class;
         code=IntuiMessage->Code;
         iaddress=IntuiMessage->IAddress;

         LT_ReplyIMsg(IntuiMessage);

         switch(class)
         {
             case IDCMP_GADGETUP:      switch(((struct Gadget *)iaddress)->GadgetID)
                                       {
                                          case 10:
                                             LT_DeleteHandle(askhandle);
                                             LT_UnlockWindow(win);
                                             return(asklistres);
                                          case 11:
                                             LT_DeleteHandle(askhandle);
                                             LT_UnlockWindow(win);
                                             return(-1);
                                          case 4711:
                                             asklistres=code;
                                             LT_SetAttributes(askhandle,10,GA_Disabled,FALSE,TAG_END);
                                             break;
                                       }
                                       break;

            case IDCMP_IDCMPUPDATE:    switch(((struct Gadget *)iaddress)->GadgetID)
                                       {
                                          case 4711:
                                             LT_DeleteHandle(askhandle);
                                             LT_UnlockWindow(win);
                                             return(asklistres);
                                       }
                                       break;
            case IDCMP_CLOSEWINDOW:    LT_DeleteHandle(askhandle);
                                       LT_UnlockWindow(win);
                                       return(-1);
         }
      }
      WaitPort(askwin->UserPort);
   }
}

uchar name[200],desc[200],repl[200],magc[200];
uchar execname[1000];

void AddArgument(uchar *dest,ulong maxlen,uchar *name,uchar *arg)
{
   ulong c,d;
   ulong destlen;

   destlen=maxlen-1;

   d=strlen(dest);

   if(d<destlen) dest[d++]=' ';

   for(c=0;name[c];c++)
      if(d<destlen) dest[d++]=name[c];

   if(d<destlen) dest[d++]=' ';
   if(d<destlen) dest[d++]='"';

   for(c=0;arg[c];c++)
   {
      if(arg[c]=='"' || arg[c]=='*')
         if(d<destlen) dest[d++]='*';

      if(d<destlen) dest[d++]=arg[c];
   }

   if(d<destlen) dest[d++]='"';

   dest[d]=0;
}

void Hatch(void)
{
   BPTR confh;
   uchar buf[300];

   mystrncpy(name,(UBYTE *)LT_GetAttributes(mainhandle,1,TAG_END),200);
   mystrncpy(desc,(UBYTE *)LT_GetAttributes(mainhandle,3,TAG_END),200);
   mystrncpy(repl,(UBYTE *)LT_GetAttributes(mainhandle,4,TAG_END),200);
   mystrncpy(magc,(UBYTE *)LT_GetAttributes(mainhandle,5,TAG_END),200);

   if(name[0]==0)
   {
      rtEZRequestTags(getString(HATCHGUI_NO_NAME),getString(HATCHGUI_TXT_OK),NULL,NULL,
            RT_Underscore,    '_',
            RTEZ_ReqTitle,    getString(HATCHGUI_REQ_ERROR_TITLE),
            RTEZ_Flags,       EZREQF_CENTERTEXT,
            RT_Window,        mainwin,
            TAG_END);


      return;
   }

   if(!hatcharea)
   {
      rtEZRequestTags(getString(HATCHGUI_NO_AREA),getString(HATCHGUI_TXT_OK),NULL,NULL,
            RT_Underscore,    '_',
            RTEZ_ReqTitle,    getString(HATCHGUI_REQ_ERROR_TITLE),
            RTEZ_Flags,       EZREQF_CENTERTEXT,
            RT_Window,        mainwin,
            TAG_END);


      return;
   }

   strcpy(execname,arg_CrashTick);

   AddArgument(execname,1000,"HATCH",name);
   AddArgument(execname,1000,"AREA",hatcharea->Name);

   if(desc[0])
      AddArgument(execname,1000,"DESC",desc);

   if(repl[0])
      AddArgument(execname,1000,"REPLACE",repl);

   if(magc[0])
      AddArgument(execname,1000,"MAGIC",magc);

   if(!(confh=Open(arg_Window,MODE_NEWFILE)))
   {
      sprintf(buf,getString(HATCHGUI_FAILED_CONSOLE),arg_Window);

      rtEZRequestTags(buf,getString(HATCHGUI_TXT_OK),NULL,NULL,
            RT_Underscore,    '_',
            RTEZ_ReqTitle,    getString(HATCHGUI_REQ_ERROR_TITLE),
            RTEZ_Flags,       EZREQF_CENTERTEXT,
            RT_Window,        mainwin,
            TAG_END);

      return;
   }

   SystemTags(execname,SYS_Input,confh,
                      SYS_Output,NULL,
                      SYS_UserShell, TRUE,
                      TAG_END);

   Close(confh);
}
