#include <CrashPrefs.h>

struct List packerlist;
ULONG packersnum,currentpacker;

struct Hook PackerHelpHook = { {NULL}, HelpHookEntry,NULL,HELP_PACKERS};

void SetPacker(ULONG num)
{
   struct Packer *packer;
   ULONG c;

   if(currentpacker!=-1)
   {
      packer=PackerList.First;
      for(c=0;c<currentpacker;c++) packer=packer->Next;

      strcmpcpy(packer->Packer,(UBYTE *)LT_GetAttributes(parthandle,50,TAG_END));
      strcmpcpy(packer->Unpacker,(UBYTE *)LT_GetAttributes(parthandle,51,TAG_END));
      strcmpcpy(packer->Recog,(UBYTE *)LT_GetAttributes(parthandle,52,TAG_END));
   }

   if(packersnum == 0)
   {
      LT_SetAttributes(parthandle,4712,GA_Disabled,TRUE,TAG_END);
      LT_SetAttributes(parthandle,11,GA_Disabled,TRUE,TAG_END);
      LT_SetAttributes(parthandle,12,GA_Disabled,TRUE,TAG_END);
      LT_SetAttributes(parthandle,13,GA_Disabled,TRUE,TAG_END);
      LT_SetAttributes(parthandle,50,GA_Disabled,TRUE,TAG_END);
      LT_SetAttributes(parthandle,51,GA_Disabled,TRUE,TAG_END);
      LT_SetAttributes(parthandle,52,GA_Disabled,TRUE,TAG_END);
   }

   if(num!=-1)
   {
      if(packersnum)
      {
         LT_SetAttributes(parthandle,11,GA_Disabled,FALSE,TAG_END);
         LT_SetAttributes(parthandle,4712,GA_Disabled,FALSE,TAG_END);
      }
      else
      {
         LT_SetAttributes(parthandle,11,GA_Disabled,TRUE,TAG_END);
         LT_SetAttributes(parthandle,4712,GA_Disabled,TRUE,TAG_END);
      }

      packer=PackerList.First;
      for(c=0;c<num;c++) packer=packer->Next;

      if(num!=0)                 LT_SetAttributes(parthandle,12,GA_Disabled,FALSE,TAG_END);
      else                       LT_SetAttributes(parthandle,12,GA_Disabled,TRUE,TAG_END);

      if(num!=packersnum-1)      LT_SetAttributes(parthandle,13,GA_Disabled,FALSE,TAG_END);
      else                       LT_SetAttributes(parthandle,13,GA_Disabled,TRUE,TAG_END);

      LT_SetAttributes(parthandle,50,GA_Disabled,FALSE,GTST_String,packer->Packer,TAG_END);
      LT_SetAttributes(parthandle,51,GA_Disabled,FALSE,GTST_String,packer->Unpacker,TAG_END);
      LT_SetAttributes(parthandle,52,GA_Disabled,FALSE,GTST_String,packer->Recog,TAG_END);
   }
   currentpacker=num;
}

void RefreshPackerlist(void)
{
   struct TempNode *tempnode;
   struct Packer *packer;

   LT_SetAttributes(parthandle,4711,GTLV_Labels,~0,TAG_END);
   FreeTempNodes(&packerlist);

   packersnum=0;

   for(packer=PackerList.First;packer;packer=packer->Next)
   {
      if(!(tempnode=(struct TempNode *)AllocMem(sizeof(struct TempNode),MEMF_CLEAR)))
      {
         DisplayBeep(NULL);
         FreeTempNodes(&packerlist);
         return;
      }
      strcpy(tempnode->buf,packer->Name);
      tempnode->Node.ln_Name=tempnode->buf;
      AddTail(&packerlist,(struct Node *)tempnode);
      packersnum++;
   }

   LT_SetAttributes(parthandle,4711,GTLV_Labels,&packerlist,TAG_END);
}

BOOL CheckDupePacker(UBYTE *buf,ULONG num)
{
   struct Packer *packer;
   ULONG c;

   for(packer=PackerList.First,c=0;packer;packer=packer->Next,c++)
      if(stricmp(packer->Name,buf)==0 && num!=c) break;

   if(packer)
   {
      rtEZRequestTags("You already have a packer with that name","_Ok",NULL,NULL,RT_Underscore,'_',
                                                                                 RT_Window,partwin,
                                                                                 RT_WaitPointer,TRUE,
                                                                                 RT_LockWindow, TRUE,
                                                                                 TAG_END);

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

void AddPacker(void)
{
   struct Packer *packer;
   UBYTE buf[100];
   BOOL res;

   buf[0]=0;
   res=rtGetString(buf,10,"Add packer",NULL,RT_Window,partwin,
                                            RT_WaitPointer, TRUE,
                                            RT_LockWindow, TRUE,
                                            TAG_END);

   if(!res)
      return;


   if(!CheckDupePacker(buf,-1))
      return;

   if(packer=(struct Packer *)AllocMem(sizeof(struct Packer),MEMF_CLEAR))
   {
      jbAddNode(&PackerList,(struct jbNode *)packer);
      strcpy(packer->Name,buf);
      RefreshPackerlist();
      SetPacker(packersnum-1);
      LT_SetAttributes(parthandle,4711,GTLV_Selected,currentpacker,GTLV_MakeVisible,currentpacker,TAG_END);
      saveconfig=TRUE;
   }
   else
   {
      DisplayBeep(NULL);
   }
}

void RemPacker(void)
{
   ULONG c,num,tmp;
   struct Packer *packer,*replace;
   struct ConfigNode *cnode;
   UBYTE buf[100];
   BOOL res;

   packer=PackerList.First;
   for(c=0;c<currentpacker;c++) packer=packer->Next;

   num=0;

   for(cnode=CNodeList.First;cnode;cnode=cnode->Next)
      if(cnode->Packer == packer) num++;

   sprintf(buf,"Do you really want to remove the packer \"%s\"?\n\nIt is used by %lu nodes",packer->Name,num);

   res=rtEZRequestTags(buf,"_Remove|_Cancel",NULL,NULL,RT_Underscore,'_',
                                                       RT_Window,partwin,
                                                       RT_WaitPointer,TRUE,
                                                       RT_LockWindow, TRUE,
                                                       RTEZ_Flags, EZREQF_CENTERTEXT | EZREQF_NORETURNKEY,
                                                       TAG_END);

   if(!res)
      return;

   if(num)
   {
      res=rtEZRequestTags("What do you want to do with the nodes that use this packer?\n\n(You can keep the packer by pressing Cancel)",
                          "_Change packer|_Select no packer|_Cancel",NULL,NULL,RT_Underscore,'_',
                                                                                  RT_Window,partwin,
                                                                                  RT_WaitPointer,TRUE,
                                                                                  RT_LockWindow, TRUE,
                                                                                  RTEZ_Flags, EZREQF_CENTERTEXT,
                                                                                  TAG_END);
      if(!res)
         return;

      if(res==1)
      {
         num=AskList(&packerlist,"Select packer",partwin);

         if(num==-1)
            return;

         if(num == currentpacker)
         {
            res=rtEZRequestTags("That was the packer you wanted to remove!","Ok",NULL,NULL,RT_Underscore,'_',
                  RT_Window,partwin,
                  RT_WaitPointer,TRUE,
                  RT_LockWindow, TRUE,
                  RTEZ_Flags, EZREQF_CENTERTEXT,
                  TAG_END);

            return;
         }
         else
         {
            replace=PackerList.First;
            for(c=0;c<num;c++) replace=replace->Next;
         }
      }
      else
      {
         replace=NULL;
      }

      for(cnode=CNodeList.First;cnode;cnode=cnode->Next)
         if(cnode->Packer == packer) cnode->Packer=replace;
   }

   tmp=currentpacker;
   SetPacker(-1);
   jbFreeNode(&PackerList,(struct jbNode *)packer,sizeof(struct Packer));
   RefreshPackerlist();
   if(tmp == packersnum) tmp--;
   SetPacker(tmp);
   saveconfig=TRUE;
}

UBYTE recogbuf[300];

HexToDec(char *hex)
{
   char *hextab="0123456789abcdef";
   int c=0,c2=0;
   unsigned long result=0;

   while(hex[c])
   {
      hex[c]|=32;

      for(c2=0;c2<16;c2++)
      {
         if(hex[c] == hextab[c2])
         {
            result *= 16;
            result += c2;
         }
      }
      c++;
   }
   return(result);
}

Compare(UBYTE *str, UBYTE *recog)
{
   ULONG c,d;
   UBYTE comp;
   UBYTE buf[5];

   d=0;

   for(c=0;d<strlen(recog);c++)
   {
      if(recog[d]=='$')
      {
         strncpy(buf,&recog[d+1],2);
         buf[2]=0;
         comp=HexToDec(buf);
         if(str[c]!=comp) return(FALSE);
         d+=3;
      }
      else
      {
         if(str[c]!=recog[d] && recog[d]!='?') return(FALSE);
         d++;
      }
   }

   return(TRUE);
}

void TestRecog(void)
{
   BPTR fh;
   UBYTE buf[40];
   UBYTE *name;
   struct Packer *tmppacker;
   UBYTE **argarr[2];

   if(!OpenReq(recogbuf,300,"Please select file",partwin,FALSE))
      return;

   if(!(fh=Open(recogbuf,MODE_OLDFILE)))
   {
      argarr[0]=recogbuf;

      rtEZRequestTags("Unable to open \"%s\"","_Ok",NULL,argarr,RT_Underscore,'_',
                                                                RT_Window,partwin,
                                                                RT_WaitPointer, TRUE,
                                                                RT_LockWindow, TRUE,
                                                                TAG_END);
      return;
   }

   Read(fh,buf,40);
   Close(fh);

   name="Unknown packer";

   for(tmppacker=PackerList.First;tmppacker;tmppacker=tmppacker->Next)
      if(Compare(buf,tmppacker->Recog))
      {
         name=tmppacker->Name;
         break;
      }

   argarr[0]=recogbuf;
   argarr[1]=name;

   rtEZRequestTags("\"%s\" was packed with: \"%s\"","_Ok",NULL,argarr,RT_Underscore,'_',
                                                                      RT_Window,partwin,
                                                                      RT_WaitPointer, TRUE,
                                                                      RT_LockWindow, TRUE,
                                                                      TAG_END);
}

void PartPackers(void)
{
   ULONG class,code,tmp;
   struct IntuiMessage *IntuiMessage;
   struct TempNode *tempnode;
   APTR iaddress;
   ULONG c;
   struct Packer *packer;

   NewList(&packerlist);
   currentpacker=-1;

   parthandle = LT_CreateHandleTags(scr,LH_EditHook,&StrEditHook,
                                        LH_RawKeyFilter,FALSE,
                                        TAG_DONE);

   if(!parthandle)
   {
      FreeTempNodes(&packerlist);
      return;
   }

   LT_New(parthandle,
      LA_Type,      HORIZONTAL_KIND,
      LA_LabelText, "Packers",
      TAG_DONE);

      LT_New(parthandle,
         LA_Type,      VERTICAL_KIND,
         TAG_DONE);

         LT_New(parthandle,
            LA_Type,      STRING_KIND,
            GTST_MaxChars,10,
            LA_ID,        4712,
            LAST_Link,    4711,
            GA_Disabled,TRUE,
            TAG_DONE);

         LT_New(parthandle,
            LA_Type,       LISTVIEW_KIND,
            LA_Chars,      20,
            LALV_LockSize, TRUE,
            LALV_Lines,    10,
            LALV_CursorKey,TRUE,
            LALV_Link,4712,
            GTLV_Labels,&packerlist,
            LA_ID,4711,
            TAG_DONE);

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

            LT_New(parthandle,
               LA_Type,      VERTICAL_KIND,
               LAGR_SameSize,TRUE,
               TAG_DONE);

               LT_New(parthandle,
                  LA_Type,      BUTTON_KIND,
                  LA_LabelText, "Add...",
                  LA_Chars,10,
                  LA_ID,10,
                  TAG_DONE);

               LT_New(parthandle,
                  LA_Type,      BUTTON_KIND,
                  LA_LabelText, "Up",
                  GA_Disabled,TRUE,
                  LA_Chars,10,
                  LA_ID,12,
                  TAG_DONE);

            LT_EndGroup(parthandle);

            LT_New(parthandle,
               LA_Type,      VERTICAL_KIND,
               LAGR_SameSize,TRUE,
               TAG_DONE);

               LT_New(parthandle,
                  LA_Type,      BUTTON_KIND,
                  LA_LabelText, "Remove...",
                  LA_Chars,10,
                  GA_Disabled,TRUE,
                  LA_ID,11,
                  TAG_DONE);

               LT_New(parthandle,
                  LA_Type,      BUTTON_KIND,
                  LA_LabelText, "Down",
                  LA_Chars,10,
                  GA_Disabled,TRUE,
                  LA_ID,13,
                  TAG_DONE);

            LT_EndGroup(parthandle);

         LT_EndGroup(parthandle);

      LT_EndGroup(parthandle);

      LT_New(parthandle,
         LA_Type,      VERTICAL_KIND,
         LA_ExtraSpace,TRUE,
         TAG_DONE);

            LT_New(parthandle,
               LA_Type,      STRING_KIND,
               LA_LabelText, "Pack command",
               GA_Disabled,TRUE,
               LA_Chars,30,
               GTST_MaxChars,80,
               LA_ID,50,
               TAG_DONE);

            LT_New(parthandle,
               LA_Type,      STRING_KIND,
               LA_LabelText, "Unpack command",
               GA_Disabled,TRUE,
               LA_Chars,30,
               GTST_MaxChars,80,
               LA_ID,51,
               TAG_DONE);

            LT_New(parthandle,
               LA_Type,      STRING_KIND,
               LA_LabelText, "Recog string",
               GA_Disabled,TRUE,
               LA_Chars,30,
               GTST_MaxChars,80,
               LA_ID,52,
               TAG_DONE);

            LT_New(parthandle,
               LA_Type,      BUTTON_KIND,
               LA_LabelText, "Test recog...",
               LA_ID,99,
               TAG_DONE);

      LT_EndGroup(parthandle);

   LT_EndGroup(parthandle);

   partwin=LT_Build(parthandle,LAWN_IDCMP,    IDCMP_CLOSEWINDOW|IDCMP_RAWKEY,
                               LAWN_Title,    "Packers",
                               WA_Flags,      WFLG_ACTIVATE|WFLG_CLOSEGADGET|WFLG_DEPTHGADGET|WFLG_DRAGBAR|WFLG_NEWLOOKMENUS,
                               LAWN_HelpHook, &PackerHelpHook,
                               TAG_END);

   if(!partwin)
   {
      LT_DeleteHandle(parthandle);
      DisplayBeep(NULL);
      FreeTempNodes(&packerlist);
      return;
   }

   RefreshPackerlist();

   if(packersnum)
   {
      LT_SetAttributes(parthandle,4711,GTLV_Selected,0,TAG_END);
      SetPacker(0);
   }

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

         LT_ReplyIMsg(IntuiMessage);

         switch(class)
         {
            case IDCMP_RAWKEY:         if(code == TAB) LT_Activate(parthandle,4712);
                                       break;
            case IDCMP_GADGETUP:       switch(((struct Gadget *)iaddress)->GadgetID)
                                       {
                                          case 10:
                                             AddPacker();
                                             break;
                                          case 11:
                                             RemPacker();
                                             break;
                                          case 12:
                                             if(currentpacker != 0)
                                             {
                                                tmp=currentpacker;
                                                SetPacker(-1);
                                                MoveUp(&PackerList,tmp);
                                                RefreshPackerlist();
                                                SetPacker(tmp-1);
                                                LT_SetAttributes(parthandle,4711,
                                                   GTLV_Selected,currentpacker,
                                                   GTLV_MakeVisible,currentpacker,
                                                   TAG_END);
                                                saveconfig=TRUE;
                                             }
                                             break;
                                          case 13:
                                             if(currentpacker != packersnum-1)
                                             {
                                                tmp=currentpacker;
                                                SetPacker(-1);
                                                MoveDown(&PackerList,tmp);
                                                RefreshPackerlist();
                                                SetPacker(tmp+1);
                                                LT_SetAttributes(parthandle,4711,
                                                   GTLV_Selected,currentpacker,
                                                   GTLV_MakeVisible,currentpacker,
                                                   TAG_END);
                                                saveconfig=TRUE;
                                             }
                                             break;
                                          case 50:
                                          case 51:
                                          case 52:
                                             saveconfig=TRUE;
                                             break;
                                          case 99:
                                             TestRecog();
                                             break;
                                          case 4711:
                                             SetPacker(code);
                                             break;
                                          case 4712:
                                             if(CheckDupePacker((UBYTE *)LT_GetAttributes(parthandle,4712,TAG_END),currentpacker))
                                             {
                                                packer=PackerList.First;
                                                for(c=0;c<currentpacker;c++) packer=packer->Next;
                                                strcpy(packer->Name,(UBYTE *)LT_GetAttributes(parthandle,4712,TAG_END));

                                                tempnode=packerlist.lh_Head;
                                                for(c=0;c<currentpacker;c++) tempnode=tempnode->Node.ln_Succ;
                                                LT_SetAttributes(parthandle,4711,GTLV_Labels,~0,TAG_END);
                                                strcpy(tempnode->buf,(UBYTE *)LT_GetAttributes(parthandle,4712,TAG_END));
                                                LT_SetAttributes(parthandle,4711,GTLV_Labels,&packerlist,TAG_END);
                                                saveconfig=TRUE;
                                             }
                                             else
                                             {
                                                LT_Activate(parthandle,4712);
                                             }
                                             break;
                                       }
                                       break;
            case IDCMP_CLOSEWINDOW:    SetPacker(-1);
                                       LT_DeleteHandle(parthandle);
                                       parthandle=NULL;
                                       FreeTempNodes(&packerlist);
                                       return;
         }
      }
      WaitPort(partwin->UserPort);
   }
}
