#include <CrashTickPrefs.h>

#include <newconfig.h>
#include <import.h>

#define STACKSIZE 20000

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

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

uchar *config_version="CrashTickPrefs "VERSION;

struct Config config;
struct Config config2;

struct Screen *scr;
struct Menu *menus;

struct LayoutHandle *mainhandle;
struct Window *mainwin;

struct LayoutHandle *parthandle;
struct Window *partwin;

#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 *KeymapBase; */
struct Library *AmigaGuideBase;
struct Library *ReqToolsBase;
struct Library *GTLayoutBase;

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]="";

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

/* All AmigaGuide junk */

UBYTE *Context[] = {
   "CTP_MAIN",
   "CTP_GENERAL",
   "CTP_COMMANDS",
   "CTP_PATHS",
   "CTP_OPTIONS",
   "CTP_GROUPS",
   "CTP_AKAS",
   "CTP_NODES",
   "CTP_AREAS",
   "CTP_ANNOUNCE",
   "CTP_CHANGEAREAS",
   NULL };

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_MAIN};

/* 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)

__asm __saveds ULONG StrEditHookEntry (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; */
            }
         }
      }

      return (TRUE);
   }
   return (FALSE);
}

struct Hook StrEditHook = { { NULL }, StrEditHookEntry, NULL, NULL };

#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(PREFS_REQ_ERROR_TITLE),
            RTEZ_Flags,       EZREQF_CENTERTEXT,
            TAG_END);
   }
   else
   {
      VFPrintf(Output(),fmt,args);
      FPrintf(Output(),"\n");
   }

   va_end(args);
}

void AskQuit(struct Window *lockwin)
{
   ULONG res;
   uchar errorbuf[100];

   if(config.configchanged)
   {
      res=rtEZRequestTags(getString(PREFS_TXT_CHANGED_QUIT),getString(PREFS_TXT_CHANGED_QUIT_OPT),NULL,NULL,
            RT_Underscore,    '_',
            RT_Window,        lockwin,
            RT_WaitPointer,   TRUE,
            RT_LockWindow,    TRUE,
            RTEZ_Flags,       EZREQF_CENTERTEXT,
            TAG_END);

      if(res==0)
         return;

      if(res==1)
      {
         LT_LockWindow(lockwin);

         if(!WriteConfig(&config,errorbuf))
         {
            LT_UnlockWindow(lockwin);

            rtEZRequestTags(errorbuf,getString(PREFS_TXT_OK),NULL,NULL, 
                  RT_Underscore,    '_',
                  RT_Window,        lockwin,
                  RT_WaitPointer,   TRUE,
                  RT_LockWindow,    TRUE,
                  RTEZ_Flags,       EZREQF_CENTERTEXT,
                  TAG_END);

            return;
         }

         LT_UnlockWindow(lockwin);
      }
   }

   CleanUp(0);
}

void CheckUnconfirmed(void)
{
   struct Area *a;

   for(a=(struct Area *)config.AreaList.First;a;a=a->Next)
      if(a->Flags & AREA_UNCONFIRMED) break;

   if(a)
   {
      rtEZRequestTags(getString(PREFS_TXT_UNCONFIRMED_AREAS),
                           getString(PREFS_TXT_PROCEED),NULL,NULL,
                           RT_Underscore,'_',
                           RT_Window,mainwin,
                           RT_WaitPointer,TRUE,
                           RT_LockWindow, TRUE,
                           RTEZ_Flags, EZREQF_CENTERTEXT,
                           TAG_END);
   }
}

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

void PartGeneral(void);
void PartCommands(void);
void PartPaths(void);
void PartOptions(void);
void PartAnnounce(void);
void PartAka(void);
void PartGroups(void);
void PartAreas(void);
void PartNodes(void);

void (*mainfuncs[])(void)={   PartGeneral, PartCommands, PartPaths,
                              PartOptions, PartGroups,   PartAka,
                              PartNodes,   PartAreas,    PartAnnounce  };

#define SETTINGS  0
#define PUBSCREEN 1
#define HELPFILE  2

short initconfig;

void OpenSettings(uchar *filename)
{
   short seconderr,res;
   ulong cfgline;
   uchar buf[200],errorbuf[200];
   APTR lock;

   InitConfig(&config2);

   lock=rtLockWindow(mainwin);
   res=ReadConfig(filename,&config2,&seconderr,&cfgline,errorbuf);
   rtUnlockWindow(mainwin,lock);

   if(res)
   {
      FreeConfig(&config);
      CopyMem(&config2,&config,sizeof(struct Config));
      return;
   }

   FreeConfig(&config2);

   switch(seconderr)
   {
      case READCONFIG_INVALID:
         sprintf(buf,getString(CFG_ERR_CONFIG_ERR_IN_LINE),cfgline);
         strcat(buf,": ");
         strcat(buf,errorbuf);
         break;

      case READCONFIG_NO_MEM:
         strcpy(buf,getString(PREFS_ERR_OUT_OF_MEMORY));
         break;

      default:
         sprintf(buf,getString(CFG_ERR_NO_CONFIG_NAME),filename);
   }

   rtEZRequestTags(buf,getString(PREFS_TXT_OK),NULL,NULL,
            RT_Underscore,    '_',
            RT_Window,        mainwin,
            RT_WaitPointer,   TRUE,
            RT_LockWindow,    TRUE,
            RTEZ_Flags,       EZREQF_CENTERTEXT,
            TAG_END);
}

void SaveSettings(void)
{
   short res;
   APTR lock;
   uchar errorbuf[200];
   
   lock=rtLockWindow(mainwin);
   res=WriteConfig(&config,errorbuf);
   rtUnlockWindow(mainwin,lock);

   if(res)
   {
      config.configchanged=FALSE;
      return;
   }

   rtEZRequestTags(errorbuf,getString(PREFS_TXT_OK),NULL,NULL,
            RT_Underscore,    '_',
            RT_Window,        mainwin,
            RT_WaitPointer,   TRUE,
            RT_LockWindow,    TRUE,
            RTEZ_Flags,       EZREQF_CENTERTEXT,
            TAG_END);
}

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 hasconfig,gid;
   ULONG class,code;
   APTR lock;
   ULONG num;
   struct IntuiMessage *IntuiMessage;
   APTR iaddress;
   struct MenuItem *menuitem;
   ULONG res;
   UBYTE errorbuf[200],buf[200];

   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(PREFS_ERR_NO_MEMORYPOOL));
      CleanUp(10);
   }

/*   if(!(KeymapBase=OpenLibrary("keymap.library",37)))
      CleanUp(10); */

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

   if(!(GTLayoutBase=OpenLibrary("gtlayout.library",24)))
   {
      ShowError(getString(PREFS_ERR_LIB_VER_NEEDED),"gtlayout.library",32);
      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;
      }

      FreeDiskObject(dobj);
      CurrentDir(olddir);
   }
   else
   {
      struct RDArgs *rdargs;
      UBYTE *argstr="SETTINGS,PUBSCREEN=PS/K,HELPFILE/K";
      LONG argarray[]={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]);

      FreeArgs(rdargs);
   }

   if(!(scr=LockPubScreen(arg_PubScreen)))
   {
      if(!(scr=LockPubScreen(NULL)))
      {
         ShowError(getString(PREFS_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(PREFS_MENU_PROJECT);

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

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

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

   newmenus[5].nm_Label    = getString(PREFS_MENU_ABOUT)+2;
   newmenus[5].nm_CommKey  = getString(PREFS_MENU_ABOUT);

   newmenus[7].nm_Label    = getString(PREFS_MENU_QUIT)+2;
   newmenus[7].nm_CommKey  = getString(PREFS_MENU_QUIT);

   newmenus[8].nm_Label    = getString(PREFS_MENU_IMPORT);

   newmenus[9].nm_Label    = getString(PREFS_MENU_IMPORTTICK)+2;
   newmenus[9].nm_CommKey  = getString(PREFS_MENU_IMPORTTICK);

   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,
      LA_LabelID,   PREFS_MAIN_SECTIONS,
      TAG_DONE);

      LT_New(mainhandle,
         LA_Type,      HORIZONTAL_KIND,
         TAG_DONE);

         LT_New(mainhandle,
            LA_Type,      BUTTON_KIND,
            LA_LabelID,   PREFS_BUTTON_GENERAL,
            LA_Chars,     20,
            LA_ID,        1,
         TAG_DONE);

         LT_New(mainhandle,
            LA_Type,      BUTTON_KIND,
            LA_LabelID,   PREFS_BUTTON_COMMANDS,
            LA_Chars,     20,
            LA_ID,        2,
         TAG_DONE);

         LT_New(mainhandle,
            LA_Type,      BUTTON_KIND,
            LA_LabelID,   PREFS_BUTTON_PATHS,
            LA_Chars,     20,
            LA_ID,        3,
         TAG_DONE);

      LT_EndGroup(mainhandle);

      LT_New(mainhandle,
         LA_Type,      HORIZONTAL_KIND,
         TAG_DONE);

         LT_New(mainhandle,
            LA_Type,      BUTTON_KIND,
            LA_LabelID,   PREFS_BUTTON_OPTIONS,
            LA_Chars,     20,
            LA_ID,        4,
         TAG_DONE);

         LT_New(mainhandle,
            LA_Type,      BUTTON_KIND,
            LA_LabelID,   PREFS_BUTTON_GROUPS,
            LA_Chars,     20,
            LA_ID,        5,
         TAG_DONE);

         LT_New(mainhandle,
            LA_Type,      BUTTON_KIND,
            LA_LabelID,   PREFS_BUTTON_AKAS,
            LA_Chars,     20,
            LA_ID,        6,
         TAG_DONE);

      LT_EndGroup(mainhandle);

      LT_New(mainhandle,
         LA_Type,      HORIZONTAL_KIND,
         TAG_DONE);

         LT_New(mainhandle,
            LA_Type,      BUTTON_KIND,
            LA_LabelID,   PREFS_BUTTON_NODES,
            LA_Chars,     20,
            LA_ID,        7,
         TAG_DONE);

         LT_New(mainhandle,
            LA_Type,      BUTTON_KIND,
            LA_LabelID,   PREFS_BUTTON_AREAS,
            LA_Chars,     20,
            LA_ID,        8,
            TAG_DONE);

         LT_New(mainhandle,
            LA_Type,      BUTTON_KIND,
            LA_LabelID,   PREFS_BUTTON_ANNOUNCE,
            LA_Chars,     20,
            LA_ID,        9,
         TAG_DONE);

      LT_EndGroup(mainhandle);

   LT_EndGroup(mainhandle);

   sprintf(wintitle,getString(PREFS_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);
   }

   InitConfig(&config);
   initconfig=TRUE;

   hasconfig=FALSE;

   if(arg_Settings[0] == 0)
   {
      ulong cfgline;
      short res,seconderr;

      lock=rtLockWindow(mainwin);

      if(!(res=ReadConfig("PROGDIR:CrashTick.prefs",&config,&seconderr,&cfgline,errorbuf)))
      {
         if(seconderr == READCONFIG_NOT_FOUND)
            res=ReadConfig("MAIL:CrashTick.prefs",&config,&seconderr,&cfgline,errorbuf);
      }

      rtUnlockWindow(mainwin,lock);

      if(res)
      {
         hasconfig=TRUE;
      }
      else
      {
         strcpy(config.filename,"PROGDIR:CrashTick.prefs");

         switch(seconderr)
         {
            case READCONFIG_INVALID:
               sprintf(buf,getString(CFG_ERR_CONFIG_ERR_IN_LINE),cfgline);
               strcat(buf,": ");
               strcat(buf,errorbuf);
               break;
               
            case READCONFIG_NO_MEM:
               strcpy(buf,getString(PREFS_ERR_OUT_OF_MEMORY));
               break;

            default:
               strcpy(buf,getString(CFG_ERR_NO_CONFIG));
        }
      }
   }
   else
   {
      short seconderr;
      ulong cfgline;

      lock=rtLockWindow(mainwin);

      if(ReadConfig(arg_Settings,&config,&seconderr,&cfgline,errorbuf))
      {
         hasconfig=TRUE;
      }
      else
      {
         strcpy(config.filename,arg_Settings);

         switch(seconderr)
         {
            case READCONFIG_INVALID:
               sprintf(buf,getString(CFG_ERR_CONFIG_ERR_IN_LINE),cfgline);
               strcat(buf,": ");
               strcat(buf,errorbuf);
               break;

            case READCONFIG_NO_MEM:
               strcpy(buf,getString(PREFS_ERR_OUT_OF_MEMORY));
               break;

            default:
               sprintf(buf,getString(CFG_ERR_NO_CONFIG_NAME),arg_Settings);
         }
      }
      rtUnlockWindow(mainwin,lock);
   }

   while(!hasconfig)
   {
      res=rtEZRequestTags(buf,getString(PREFS_NO_CONFIG_REQ),NULL,NULL,
             RT_Underscore,'_',
             RT_Window,mainwin,
             RT_WaitPointer,TRUE,
             RT_LockWindow, TRUE,
             TAG_END);

      if(!res)
         CleanUp(0);

      if(res==1)
      {
         if(OpenReq(config.filename,200,getString(PREFS_REQ_OPEN_TITLE),mainwin,FALSE))
         {
            short seconderr;
            ulong cfgline;

            lock=rtLockWindow(mainwin);

            if(ReadConfig(config.filename,&config,&seconderr,&cfgline,errorbuf))
            {
               hasconfig=TRUE;
            }
            else
            {
               switch(seconderr)
               {
                  case READCONFIG_INVALID:
                     sprintf(buf,getString(CFG_ERR_CONFIG_ERR_IN_LINE),cfgline);
                     strcat(buf,": ");
                     strcat(buf,errorbuf);
                     break;

                  case READCONFIG_NO_MEM:
                     strcpy(buf,getString(PREFS_ERR_OUT_OF_MEMORY));
                     break;

                  default:
                     sprintf(buf,getString(CFG_ERR_NO_CONFIG_NAME),config.filename);
               }
            }

            rtUnlockWindow(mainwin,lock);
         }
      }

      if(res==2)
      {
         if(NewConfig(mainwin))
            hasconfig=TRUE;
      }
   }

   CheckUnconfirmed();

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

         LT_ReplyIMsg(IntuiMessage);

         switch(class)
         {
            case IDCMP_CLOSEWINDOW:   AskQuit(mainwin);
                                      break;

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

                                      if(gid > 0 && gid<=9)
                                      {
                                         LT_LockWindow(mainwin);
                                         (*mainfuncs[gid-1])();
                                         LT_UnlockWindow(mainwin);
                                      }

                                      break;

            case IDCMP_MENUPICK:      num=code;
                                      while(num!=MENUNULL)
                                      {
                                         if(MENUNUM(num)==0)
                                         {
                                            switch(ITEMNUM(num))
                                            {
                                               case 0: strcpy(buf,config.filename);

                                                       if(OpenReq(buf,300,getString(PREFS_REQ_OPEN_TITLE),mainwin,FALSE))
                                                          OpenSettings(buf);

                                                       break;

                                               case 1: SaveSettings();
                                                       break;

                                               case 2: if(OpenReq(config.filename,200,getString(PREFS_REQ_SAVE_AS_TITLE),mainwin,TRUE))
                                                          SaveSettings();

                                                       break;

                                               case 4: sprintf(aboutbuf,getString(PREFS_ABOUT),VERSION,COPYRIGHT);
                                               
                                                       rtEZRequestTags(aboutbuf,getString(PREFS_TXT_OK),NULL,NULL,
                                                                                                RT_Underscore,'_',
                                                                                                RT_Window,mainwin,
                                                                                                RT_WaitPointer,TRUE,
                                                                                                RT_LockWindow, TRUE,
                                                                                                RTEZ_Flags, EZREQF_CENTERTEXT,
                                                                                                TAG_END);
                                                       break;

                                               case 6: AskQuit(mainwin);
                                                       break;
                                            }
                                         }
                                         if(MENUNUM(num)==1)
                                         {
                                            switch(ITEMNUM(num))
                                            {
                                               case 0: ImportOldTick(mainwin);
                                                       break;
                                            }
                                         }
                                         menuitem=ItemAddress(menus,num);
                                         num=menuitem->NextSelect;
                                      }
                                      break;
         }
      }
      WaitPort(mainwin->UserPort);
   }
}

void CleanUp(int err)
{
   if(initconfig)
      FreeConfig(&config);

   FreeAmigaGuide();

   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(KeymapBase)   CloseLibrary(KeymapBase); */
   if(ReqToolsBase) CloseLibrary(ReqToolsBase);
   if(GTLayoutBase) CloseLibrary(GTLayoutBase);

   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);
}

