#include "UserEdit.h"

char     ScanFile[128];
char     AreaFile[128];

int      WindowBottom =  0;

long    *NewScan;

long     NumNewScan  =  0;
long     NumAreas    =  0;
long     SIndex      =  0;
long     SPtr        =  0;
long     CurrentArea =  0;

struct   Msg_Area      *Areas;
struct   Msg_Area      *ScAreas;


long     LoadNewScan(void);
long     LoadAreas(void);
long     CopyAreas(long, long);
BOOL     AreaOK(long, long);
long     FindArea(long, long);
long     CleanUpAreas(long, long);
BOOL     ExistsScan(long, long);
void     Display_Areas(char type);
int      sortcmp(struct Msg_Area *, struct Msg_Area *);
void     RemoveArea(long area);

/*
** Possible types:   0  Message
**                   1  File
**                   2  Archive
**
 ******************************/

/// EditScan()
void EditScan(char type)
{
   BOOL  Changed  =  FALSE;

/// Preliminary; loading things up
   switch(type)
   {
      case 0:  ASPrintf(NULL,ScanFile,"USER:%s/GlobalAreas.msg",name);
               ASPrintf(NULL,AreaFile,"MSG:AREA.BBS");
               break;
      case 1:  ASPrintf(NULL,ScanFile,"USER:%s/GlobalAreas.file",name);
               ASPrintf(NULL,AreaFile,"FILE:AREA.BBS");
               break;
      case 2:  ASPrintf(NULL,ScanFile,"USER:%s/GlobalAreas.archive",name);
               ASPrintf(NULL,AreaFile,"MSG:AREA.BBS");
               break;
   }

   UnderScore(ScanFile);

/// Load NewScan file
   NumNewScan = LoadNewScan();

   if(NumNewScan != 0)
   {
      if(NULL == (ScAreas = calloc(NumNewScan,sizeof(struct Msg_Area))))
      {
         free(NewScan);
         return;
      }
   }
//-

/// Load Areas File
   NumAreas = LoadAreas();

   if(NumAreas == 0)
   {
      if(NumNewScan == 0)
      {
         free(ScAreas);
         free(NewScan);
      }

      return;
   }
//-

   // Create NewScan-indicated area file image
   NumNewScan = CopyAreas(NumNewScan,NumAreas);
   free(NewScan);

   // Now remove invalid areas from the areafile image
   NumAreas = CleanUpAreas(NumNewScan,NumAreas);
//-

   WindowBottom = UserDat.Screen_Len - 7;

/// Handle input
   while(TRUE)
   {
      char c[2];

      Chk_Abort();

      Display_Areas(type);

      DLGInput("Command -> ",NULL,c,NULL,1,1,1);

///   Move cursor up (>)
      if(!Strnicmp(c,">",1) || !Strnicmp(c,".",1))
      {
         if(CurrentArea == NumNewScan)
         {
            AFPrintf(&UserDat,sout,"\rAt high area.\n");
            Pause();
            continue;
         }

         CurrentArea++;

         if(CurrentArea == (SIndex + WindowBottom - 5))
         {
            SIndex = SIndex + WindowBottom - 5 - 1;

            if(SIndex >= NumNewScan)
            {
               SIndex = SIndex - WindowBottom + 5;
               if(SIndex < 0) SIndex = 0;
            }
         }
      }
//-

///   Move cursor down (<)
      if(!Strnicmp(c,"<",1) || !Strnicmp(c,",",1))
      {
         if(CurrentArea == 0)
         {
            AFPrintf(&UserDat,sout,"\rAt low area.\n");
            Pause();
            continue;
         }

         CurrentArea--;

         if(CurrentArea <= SIndex)
         {
            SIndex = SIndex - WindowBottom + 6;

            if(SIndex < 0)
            {
               SIndex = 0;
               CurrentArea = SIndex;
            }
         }
      }
//-

///   Page up (+)
      if(!Strnicmp(c,"+",1) || !Strnicmp(c,"=",1))
      {
         if(CurrentArea == NumNewScan)
         {
            AFPrintf(&UserDat,sout,"\rAt high area.\n");
            Pause();
            continue;
         }

         SIndex = SIndex + WindowBottom - 5 - 1;

         if(SIndex >= NumNewScan)
         {
            SIndex = SIndex - WindowBottom + 5;

            if(SIndex < 0)   SIndex = 0;
         }

         CurrentArea = SIndex;
      }
//-

///   Page down (-)
      if(!Strnicmp(c,"-",1) || !Strnicmp(c,"_",1))
      {
         if(CurrentArea == 0)
         {
            AFPrintf(&UserDat,sout,"\rAt low area.\n");
            Pause();
            continue;
         }

         SIndex = SIndex - WindowBottom + 5 + 1;
         if(SIndex < 0) SIndex = 0;
         CurrentArea = SIndex;
      }
//-

///   Move Area Up (U)
      if(!Strnicmp(c,"U",1))
      {
         struct Msg_Area ma;

         if(CurrentArea == NumNewScan)
         {
            AFPrintf(&UserDat,sout,"\rAt High Area.\n");
            Pause();
            continue;
         }

         memcpy(&ma,&ScAreas[CurrentArea],sizeof(struct Msg_Area));
         memcpy(&ScAreas[CurrentArea],&ScAreas[CurrentArea+1],sizeof(struct Msg_Area));
         memcpy(&ScAreas[CurrentArea+1],&ma,sizeof(struct Msg_Area));

         Changed = TRUE;

         CurrentArea++;

         if(CurrentArea == (SIndex + WindowBottom - 5))
         {
            SIndex = SIndex + WindowBottom - 6;

            if(SIndex >= NumNewScan)
            {
               SIndex = SIndex - WindowBottom + 5;
               if(SIndex < 0)   SIndex = 0;
            }
         }
      }
//-

///   Move Area Down (U)
      if(!Strnicmp(c,"D",1))
      {
         struct Msg_Area ma;

         if(CurrentArea == 0)
         {
            AFPrintf(&UserDat,sout,"\rAt Low Area.\n");
            Pause();
            continue;
         }

         memcpy(&ma,&ScAreas[CurrentArea],sizeof(struct Msg_Area));
         memcpy(&ScAreas[CurrentArea],&ScAreas[CurrentArea-1],sizeof(struct Msg_Area));
         memcpy(&ScAreas[CurrentArea-1],&ma,sizeof(struct Msg_Area));

         Changed = TRUE;

         CurrentArea--;

         if(CurrentArea == SIndex)
         {
            SIndex = SIndex - WindowBottom + 6;
            if(SIndex < 0) SIndex = 0;
         }
      }
//-

///   Sort Areas
      if(!Strnicmp(c,"S",1))
      {
         qsort(ScAreas,NumNewScan,sizeof(struct Msg_Area),sortcmp);
         CurrentArea = 0;
         SIndex = 0;
         Changed = TRUE;
      }
//-

///   Add Areas (A)
      if(!Strnicmp(c,"A",1))
      {
         if(SelectArea(type)) Changed = TRUE;
      }
//-

///   Remove Area
      if(!Strnicmp(c,"R",1))
      {
         RemoveArea(CurrentArea);
         CurrentArea--;
         Changed = TRUE;
      }
//-

      if(!Strnicmp(c,"Q",1)) break;
   }
//-

   free(ScAreas);
   free(Areas);
   return;
}
//-

/// LoadNewScan()
/*
** Loads user's NewScan into a long array. Returns number of areas loaded.
**
 *************************************************************************/
long     LoadNewScan(void)
{
   long  number;

   ULONG fsize =  0;

   if(-1 == FileSize(ScanFile,&fsize))       return(0);
   if(fsize == 0)                            return(0);
   if(NULL == (NewScan = calloc(1,fsize)))   return(0);

   number = fsize / 4;

   if(-1 == GetFirstStruct(ScanFile,(char *)NewScan,fsize))
   {
      free(NewScan);
      return(0);
   }

   return(number);
}
//-

/// LoadAreas()
/*
** Loads AREAS.BBS file into RAM.  Returns number of areas loaded.
**
 ******************************************************************/
long     LoadAreas(void)
{
   long  number;

   ULONG fsize =  0;

   if(-1 == FileSize(AreaFile,&fsize))    return(0);
   if(fsize == 0)                         return(0);
   if(NULL == (Areas = calloc(1,fsize)))  return(0);

   number = fsize / sizeof(struct Msg_Area);

   if(-1 == GetFirstStruct(AreaFile,(char *)Areas,fsize))
   {
      free(Areas);
      return(0);
   }

   return(number);
}
//-

/// CopyAreas()
/*
** Copies area definitions from master area file image into a filtered one
** representing user's newscan array, but with all the area info needed.
**
** NumScan ==  number of areas in user's NewScan file
** NumArea ==  number of areas in BBS master list
**
 **************************************************************************/
long CopyAreas(long NumScan, long NumArea)
{
   long i;
   long AreaIndex    =  0;
   long SAreaIndex   =  0;

   for(i = 0; i < NumScan; i++)
   {
      Chk_Abort();

      if(AreaOK(NewScan[i],NumArea))
      {
         if(-1 != (AreaIndex = FindArea(NewScan[i],NumArea)))
         {
            memcpy(&ScAreas[SAreaIndex],&Areas[AreaIndex],sizeof(struct Msg_Area));
            SAreaIndex++;
         }
      }
   }

   return(SAreaIndex - 1);
}
//-

/// AreaOK()
/*
** Checks to see if an area is OK for the user to have access to. Fails
** either if an area doesn't exist or if the user doesn't have access to
** the area.
**
** test     == The area to test.
** NumAreas == The number of areas in the master area file image.
**
** Returns  TRUE if access is OK,
**          FALSE if not.
**
 ************************************************************************/
BOOL AreaOK(long test, long NumAreas)
{
   long i;

   for(i = 0; i < NumAreas; i++)
   {
      if(Areas[i].Number == test)
      {
         if((Areas[i].llevel <= udat.User_Level) &&
            (Areas[i].ulevel >= udat.User_Level))
            return(TRUE);
         else
            return(FALSE);
      }
   }

   return(FALSE);
}
//-

/// FindArea()
/*
** Finds the index of an area in the master area file index.
**
** test     == The area to find
** NumAreas == The number of areas in the master area file image
**
** Returns -1 if area not found.
**          the index into the array if area is found
**
 ****************************************************************/
long FindArea(long test, long NumAreas)
{
   long i;

   for(i = 0; i < NumAreas; i++)
      if(Areas[i].Number == test)
         return(i);

   return(-1);
}
//-

/// CleanUpAreas()
/*
** Remove areas from the AREA file image in memory. If an area already
** exists in the newscan file, it is removed, and if it is inaccessable
** it is removed.
**
** NumNew   == Number of areas in the Newscan area image
** NumArea  == Number of areas in the master area file image
**
** Returns the number of remaining areas in the area file image.
**
 ************************************************************************/
long CleanUpAreas(long NumNew, long NumArea)
{
   BPTR fh;

   long i;
   long Top;

   struct Msg_Area ma;

   Top = NumArea;

   for(i = 0; i < NumArea; i++)
   {
      if(ExistsScan(Areas[i].Number,NumNew))
      {
         Top--;
         continue;
      }

      if(!AreaOK(Areas[i].Number,NumArea)) Top--;
   }

   free(Areas);
   Areas = NULL;

   if(Top <= 0)   return(0);

   Areas = calloc(Top,sizeof(struct Msg_Area));
   fh    = Open(AreaFile,MODE_OLDFILE);

   i = 0;

   while(Read(fh,&ma,sizeof(struct Msg_Area)) == sizeof(struct Msg_Area))
   {
      if(ExistsScan(ma.Number, NumNew))      continue;

      if((ma.llevel <= udat.User_Level) &&
         (ma.ulevel >= udat.User_Level))     continue;

      memcpy(&Areas[i],&ma,sizeof(struct Msg_Area));
      i++;

      if(i > Top) break;
   }

   Close(fh);
   return(Top);
}
//-

/// ExistsScan()
/*
** Checks if an area exists in the NewScan area file image
**
** test     == The area to find
** NumAreas == The number of areas in the area file image
**
** Returns -1 if area not found.
**          the index into the array if area is found
**
 ****************************************************************/
BOOL ExistsScan(long test, long NumAreas)
{
   long i;

   for(i = 0; i < NumAreas; i++)
      if(ScAreas[i].Number == test)
         return(TRUE);

   return(FALSE);
}
//-

/// Display_Areas
void Display_Areas(char type)
{
   BOOL flip   =  FALSE;

   int  pos;

   long Index;

   Index = SIndex;

   Clr(udat.Ansi_Flag);
   AFPrintf(&UserDat,sout,"%a7Active %s Areas for %ab%s%ao%a0%b7\n",(type == 1) ? "NewScan File" : "NewScan Message",
                                                                    name);
   Draw_Line(UserDat.Screen_Width);
   AFPrintf(&UserDat,sout,"  %b4%a7%6.6s %-34.34s FL %-30.30s%b7%a0  \n","AREA","AREA NAME","AREA DESCRIPTION");
   Draw_Line(UserDat.Screen_Width);

   if(NumNewScan)
   {
      for(pos = 5; pos <= WindowBottom; pos ++)
      {
         if(Index == CurrentArea)
            AFPrintf(&UserDat,sout,"%b7%a1->");
         else
            AFPrintf(&UserDat,sout,"%b7%a1  ");

         if(flip)
            AFPrintf(&UserDat,sout,"%a4%b7");
         else
            AFPrintf(&UserDat,sout,"%a4%b3");

         AFPrintf(&UserDat,sout,"%6d ",ScAreas[Index].Number);

         AFPrintf(&UserDat,sout,"%a5%-34.34s ",ScAreas[Index].Name);

         AFPrintf(&UserDat,sout,"%b4%a3%s%s",(ScAreas[Index].Flag & ECHO_AREA) ? "E" : " ",
                                             (ScAreas[Index].Flag & NEWSGROUP_AREA) ? "I" : " ");

         if(flip)
            AFPrintf(&UserDat,sout,"%a4%b7");
         else
            AFPrintf(&UserDat,sout,"%a4%b3");

         AFPrintf(&UserDat,sout," %-30.30s%b7  \n","No Description");

         flip = ~flip;
         Index++;

         if(Index >= NumNewScan) break;
      }
   }
   else
   {
      AFPrintf(&UserDat,sout,"%b0%a1   No Areas Selected.\n");
   }

   AFPrintf(&UserDat,sout,"%b7%a0");
   Draw_Line(UserDat.Screen_Width);
   AFPrintf(&UserDat,sout,"%b0%a7");

   AFPrintf(&UserDat,sout,"%a2[%a7<%a2] %a7Cursor Down     ");
   AFPrintf(&UserDat,sout,"%a2[%a7>%a2] %a7Cursor Up       ");
   AFPrintf(&UserDat,sout,"%a2[%a7-%a2] %a7Page Down       ");
   AFPrintf(&UserDat,sout,"%a2[%a7+%a2] %a7Page Up\n");
   AFPrintf(&UserDat,sout,"%a2[%a7U%a2] %a7Move Area Up    ");
   AFPrintf(&UserDat,sout,"%a2[%a7D%a2] %a7Move Area Down  ");
   AFPrintf(&UserDat,sout,"%a2[%a7S%a2] %a7Sort Areas      ");
   AFPrintf(&UserDat,sout,"%a2[%a7A%a2] %a7Add Area(s)\n");
   AFPrintf(&UserDat,sout,"%a2[%a7R%a2] %a7Remove Area     ");
   AFPrintf(&UserDat,sout,"%a2[%a7Q%a2] %a7Quit            \n\n");

   return;
}
//-

/// sortcmp()
int sortcmp(struct Msg_Area *a, struct Msg_Area *b)
{
   if(a->Number > b->Number) return(1);
   if(a->Number < b->Number) return(-1);
   return(0);
}
//-

/// RemoveArea()
void RemoveArea(long area)
{
   long Index;

   for(Index = area; Index < (NumNewScan - 1); Index++)
      memmove(&ScAreas[Index],&ScAreas[Index + 1],sizeof(struct Msg_Area));

   ScAreas = realloc(ScAreas,(NumNewScan - 1) * sizeof(struct Msg_Area));
   NumNewScan--;

   return;
}
//-

/// SelectArea()
BOOL SelectArea(char type)
{
   AreaPtr = AreaIndex;
   AllAreaPtr = AreaIndex;

   while(TRUE)
   {
      char c[2];

      Chk_Abort();

      DisplayAll(type);

      DLGInput("Command -> ",NULL,c,NULL,1,1,1);

///   Move cursor up (>)
      if(!Strnicmp(c,">",1) || !Strnicmp(c,".",1))
      {
         if(AreaPtr == NumAreas)
         {
            AFPrintf(&UserDat,sout,"\rAt high area.\n");
            Pause();
            continue;
         }

         AreaPtr++;

         while(AreaPresent(All_Areas[AreaPtr].Number) || !AreaOK(All_Areas[AreaPtr].Number))
         {
            AreaPtr++;

            if(AreaPtr == NumAreas)
            {
               AreaPtr--;

               while(AreaPresent(All_Areas[AreaPtr].Number) || !AreaOK(All_Areas[AreaPtr].Number))
                  AreaPtr--;

               break;
            }
         }

         if(AreaPtr == (AllAreaPtr + WinBottom - WinTop))
         {
            AllAreaPtr = AllAreaPtr + WinBottom - WinTop - 1;

            if(AllAreaPtr >= NumAreas)
            {
               AllAreaPtr = AllAreaPtr - WinBottom + WinTop;

               if(AllAreaPtr < 0)   AllAreaPtr = 0;
            }
         }
      }
//-

///   Move cursor down (<)
      if(!Strnicmp(c,"<",1) || !Strnicmp(c,",",1))
      {
         if(AreaPtr == 0)
         {
            AFPrintf(&UserDat,sout,"\rAt low area.\n");
            Pause();
            continue;
         }

         AreaPtr--;

         if(AreaPtr == AllAreaPtr)
         {
            AllAreaPtr = AllAreaPtr - WinBottom + WinTop + 1;
            if(AllAreaPtr < 0) AllAreaPtr = 0;
         }
      }
//-

///   Page up (+)
      if(!Strnicmp(c,"+",1) || !Strnicmp(c,"=",1))
      {
         if(AreaPtr == NumAreas)
         {
            AFPrintf(&UserDat,sout,"\rAt high area.\n");
            Pause();
            continue;
         }

         AllAreaPtr = AllAreaPtr + WinBottom - WinTop - 1;

         if(AllAreaPtr >= NumAreas)
         {
            AllAreaPtr = AllAreaPtr - WinBottom + WinTop;

            if(AllAreaPtr < 0)   AllAreaPtr = 0;
         }

         AreaPtr = AllAreaPtr;
      }
//-

///   Page down (-)
      if(!Strnicmp(c,"-",1) || !Strnicmp(c,"_",1))
      {
         if(CurrentArea == 0)
         {
            AFPrintf(&UserDat,sout,"\rAt low area.\n");
            Pause();
            continue;
         }

         AllAreaPtr = AllAreaPtr - WinBottom + WinTop + 1;
         if(AllAreaPtr < 0) AllAreaPtr = 0;
         AreaPtr = AllAreaPtr;
      }
//-

      if(!Strnicmp(c,"Q",1))
         break;
   }

   return(Changed);
}
//-


