#include <exec/types.h>
#include <string.h>
#include <stdlib.h>

#include <dlg/msg.h>
#include <dlg/resman.h>
#include <dlg/user.h>

#include <link/io.h>

#include <proto/dlg.h>
#include <proto/dos.h>

#include <pragmas/dlg.h>

extern   BPTR                 sout;

extern   int                  AreaType;

extern   struct   Library    *DLGBase;
extern   struct   USER_DATA   UserDat;

extern   BYTE  Sort_List(char *name);
extern   BOOL  Change_Path(struct Msg_Area *, BOOL );

int CompareWM(struct WaitingMail *wm1, struct WaitingMail *wm2);

/// Move_Area()
BOOL Move_Area(void)
{
   BPTR fh = NULL;

   char t[256];         // General purpose char buffer
   char AreaFile[256];  // Buffer for area.bbs file name
   char AreaPath[256];  // Buffer for area's path info

   long AreaToMove = 0;
   long NewAreaNumber = 0;
   long l;              // General purpose long

   struct DLGAreaInfo ai;
   struct Msg_Area    ma;
   struct Msg_Area   *areas   =  NULL;
   struct NameStruct *ns      =  NULL;
   struct SearchCookie *msc;

   ULONG size  =  0;


/// Get area to move, and find out if it exists
   OneLine();
   AreaToMove = iinput(1,9999,0, "%a3Area to move (RETURN for a list) %a7-> ");
   OneLine();

   if(AreaToMove == 0)
   {
      OneLine();
      ListAreas(NULL,&UserDat,AreaType,0);
      AreaToMove = iinput(1,9999,0, "%a3Area to move (RETURN to abort) %a7-> ");
      OneLine();

      if(AreaToMove == 0)
      {
         AFPrintf(&UserDat, sout, "%a7Aborted ... \n\n");
         return( FALSE );
      }
   }

   OneLine();

   if(!ReadArea(AreaToMove, &ma, AreaType))
   {
      AFPrintf(&UserDat, sout, "%a1Error! %a7%s area %ld does not exist!\nAborted...\n\n",(AreaType ? "File" : "Message"), AreaToMove);
      return( FALSE );
   }

   ASPrintf(NULL, AreaPath, "%s:%ld", (AreaType ? "File" : "Msg"), AreaToMove);

   if(!Exists(AreaPath))
   {
      AFPrintf(&UserDat,sout, "%a1Error: %a3Area directory %s does not exist!\n\n", AreaPath);
      return(FALSE);
   }

//-
/// Get new area number, and ensure it doesn't exist

   NewAreaNumber = iinput(1,9999,0, "%a3New area number (RETURN for a list) %a7-> ");
   OneLine();

   if(NewAreaNumber == 0)
   {
      OneLine();
      ListAreas(NULL,&UserDat,AreaType,0);
      NewAreaNumber = iinput(1,9999,0, "%a3New Area Number (RETURN to abort) %a7-> ");
      OneLine();

      if(NewAreaNumber == 0)
      {
         AFPrintf(&UserDat, sout, "%a7Aborted ... \n\n");
         return( FALSE );
      }
   }

   OneLine();

   if(ReadArea(NewAreaNumber, &ma, AreaType))
   {
      AFPrintf(&UserDat, sout, "%a1Error! %a7%s area %ld alread exists!\nAborted...\n\n",(AreaType ? "File" : "Message"), NewAreaNumber);
      return( FALSE );
   }
//-
/// Ensure no one is in the area
   EnterArea(AreaToMove,(AreaType ? FILELOCK : MSGLOCK));

   ai.area = AreaToMove;

   if(0 != GetAreaInfo(&ai,(AreaType ? FILELOCK : MSGLOCK)))
   {
      AFPrintf(&UserDat,sout, "%a1Error: %a7Could not get info for %s area %ld\nAborting...\n\n",(AreaType ? "file" : "message"), AreaToMove);
      LeaveArea(AreaToMove,(AreaType ? FILELOCK : MSGLOCK));
      return(FALSE);
   }

   if(ai.users != 1)
   {
      AFPrintf(&UserDat,sout, "%a3Error: %a6%ld users are present in %s area %ld\n",(ai.users - 1),(AreaType ? "file" : "message"), AreaToMove);
      AFPrintf(&UserDat,sout,"Area cannot be moved while users are in it.\n\n");
      FreeAreaInfo(&ai);
      LeaveArea(AreaToMove, (AreaType ? FILELOCK : MSGLOCK));
      return(FALSE);
   }

   FreeAreaInfo(&ai);
   LeaveArea(AreaToMove,(AreaType ? FILELOCK : MSGLOCK));
//-
/// Now, lock the area away from everyone else
   if(0 != LockArea(AreaToMove,"DLG_AreaEd","Moving area",120, (AreaType ? FILELOCK : MSGLOCK) | WRITELOCK))
   {
      AFPrintf(&UserDat,sout, "%a1Error: %a3Could not get lock on area ld!\n\n",AreaToMove);
      return(FALSE);
   }
//-
/// Rename alt path
   if(AreaType == 1)
   {
      if(strlen(ma.path))
      {
         l = finput(1, "%a3Rename alt path? %a7-> ");
         TwoLines();

         if(l == 1)
         {
            strcpy(t, ma.path);
            Change_Path(&ma, TRUE );
            AFPrintf(&UserDat, sout, "%a3\nDon't forget to move the actual directory!\n\n");
            Pause();
         }
      }
   }
//-
/// Now, change the number in area.bbs
   ASPrintf(NULL, AreaFile, "%s:Area.BBS",(AreaType ? "File" : "Msg"));
   AFPrintf(&UserDat,sout, "%a7Updating %a5[%a3%s%a5] ... ",AreaFile);

   if(-1 == FileSize(AreaFile,&size))
   {
      AFPrintf(&UserDat,sout, "%a1Error: %a3Cannot open file: %a5[%a6%s%a5]\n\n",AreaFile);
      FreeArea(AreaToMove,"DLG_AreaEd",(AreaType ? FILELOCK : MSGLOCK));
      return(FALSE);
   }

   if(size == 0)
   {
      AFPrintf(&UserDat,sout, "%a1Error: %a3Cannot open file: %a5[%a6%s%a5]\n\n",AreaFile);
      FreeArea(AreaToMove,"DLG_AreaEd",(AreaType ? FILELOCK : MSGLOCK));
      return(FALSE);
   }

   areas = calloc(1,size);

   if(!areas)
   {
      AFPrintf(&UserDat,sout, "%a1Error: %a3Cannot allocate %ld bytes of memory!\n\n",size);
      FreeArea(AreaToMove,"DLG_AreaEd",(AreaType ? FILELOCK : MSGLOCK));
      return(FALSE);
   }

   fh = Open(AreaFile,MODE_READWRITE);

   if(!fh)
   {
      free(areas); areas = NULL;
      AFPrintf(&UserDat,sout, "%a1Error: %a3Cannot open file: %a5[%a6%s%a5]\n\n",AreaFile);
      FreeArea(AreaToMove,"DLG_AreaEd",(AreaType ? FILELOCK : MSGLOCK));
      return(FALSE);
   }

   Read(fh,areas,size);

   for(l = 0; l < (size / sizeof(struct Msg_Area)); l++)
   {
      if(areas[l].Number == AreaToMove)
      {
         areas[l].Number = NewAreaNumber;
         strcpy(areas[l].path, ma.path);
      }
   }

   Seek(fh,0,OFFSET_BEGINNING);
   Write(fh,areas,size);
   Close(fh); fh = NULL;
   free(areas); areas = NULL;
   Sort_List("MSG:AREA.BBS");
   AFPrintf(&UserDat,sout," done.\n\n");
//-
/// Now do the same for all SIGs

   msc = SearchStart("DLGConfig:SIGs",(AreaType ? "*.file" : "*.msg"));

   if(msc)
   {
      char *SigFileName;
      char  SigPathName[256];

      while(SigFileName = SearchNext(msc))
      {
         if(!Stricmp(SigFileName,(AreaType ? "sigs.file" : "sigs.msg"))) continue;

         ASPrintf(NULL,SigPathName,"DLGConfig:SIGs/%s",SigFileName);
         AFPrintf(&UserDat,sout,"Updating [%s] ... ",SigFileName);

         if(-1 == FileSize(SigPathName,&size))
         {
            AFPrintf(NULL,sout," ...no areas.\n");
            continue;
         }

         if(size == 0)
         {
            AFPrintf(NULL,sout," ...no areas.\n");
            continue;
         }

         areas = calloc(1,size);
         if(areas == NULL) continue;

         fh = Open(SigPathName,MODE_READWRITE);

         if(!fh)
         {
            AFPrintf(&UserDat,sout,"error!\n");
            free(areas); areas = NULL;
            continue;
         }

         Read(fh,areas,size);

         for(l = 0; l < (size / sizeof(struct Msg_Area)); l++)
            if(areas[l].Number == AreaToMove)
            {
               AFPrintf(NULL,sout," ...found area... ");
               areas[l].Number = NewAreaNumber;
            }

         Seek(fh,0,OFFSET_BEGINNING);
         Write(fh,areas,size);
         Close(fh); fh = NULL;
         free(areas); areas= NULL;
         Sort_List(SigPathName);
         AFPrintf(&UserDat,sout,"done.\n");
      }

      SearchEnd(msc);
   }

//-
/// Rename the dir
   AFPrintf(&UserDat,sout, "%a6Moving directory ... ");
   ASPrintf(NULL,t,"%s:%ld",(AreaType ? "file" : "msg"), NewAreaNumber);

   if(0 != SmartRename(AreaPath,t))
   {
      AFPrintf(&UserDat,sout, "%a1Error: %a7Could not rename %a3%s %a6-> %a3%s%a7!\n\n",AreaPath,t);
      FreeArea(AreaToMove,"DLG_AreaEd",MSGLOCK);
      return(FALSE);
   }

   AFPrintf(&UserDat,sout," done.\n\n");
//-
/// Load up users & change newscans
   AFPrintf(&UserDat,sout, "%a3Updating users in area\n\n");

   if(-1 == FileSize("DLGConfig:Misc/Users.BBS",&size))
   {
      AFPrintf(&UserDat,sout, "%a1Error: %a3Cannot open file %a6DLGConfig:Misc/Users.BBS%a3!\n\n");
      FreeArea(AreaToMove,"DLG_AreaEd",(AreaType ? FILELOCK : MSGLOCK));
      return(FALSE);
   }

   if(size == 0)
   {
      AFPrintf(&UserDat,sout, "%a1Error: %a3Cannot open file %a6DLGConfig:Misc/Users.BBS%a3!\n\n");
      FreeArea(AreaToMove,"DLG_AreaEd",(AreaType ? FILELOCK : MSGLOCK));
      return(FALSE);
   }

   ns = calloc(1,size);

   if(!ns)
   {
      AFPrintf(&UserDat,sout, "%a1Error: %a3Cannot allocate %ld bytes of memory!\n\n",size);
      FreeArea(AreaToMove,"DLG_AreaEd",(AreaType ? FILELOCK : MSGLOCK));
      return(FALSE);
   }

   GetFirstStruct("DLGconfig:Misc/Users.BBS",(char *)ns, size);

   for(l = 0; l < (size / sizeof(struct NameStruct)); l++)
   {
      AFPrintf(&UserDat,sout, "%a7%-30.30s ... ",ns[l].name);

///   Convert arc global scan
      if(!AreaType)
      {
         ASPrintf(NULL,t,"USER:%s/globalareas.archive",ns[l].name);
         UnderScore(t);

         if(ExistsGlobalArea(t,AreaToMove))
         {
            DelArea(t,AreaToMove);
            AddArea(t,NewAreaNumber);
            AFPrintf(&UserDat,sout,"archive ... ");
         }
      }
//-
///   Convert global scan
      ASPrintf(NULL,t,"USER:%s/globalareas.%s",ns[l].name,(AreaType ? "file" : "msg"));
      UnderScore(t);

      if(ExistsGlobalArea(t,AreaToMove))
      {
         DelArea(t,AreaToMove);
         AddArea(t,NewAreaNumber);
         AFPrintf(&UserDat,sout,(AreaType ? "file... " : "msg ... "));
      }
//-
///   Convert Waitingmail
      if(AreaType == 0)
      {
         ASPrintf(NULL,t,"USER:%s/waitingmail.dat",ns[l].name);
         UnderScore(t);

         if(Exists(t))
         {
            ULONG wmsize = 0;
            long NumberOfWM = 0;
            struct WaitingMail *wm = NULL;

            FileSize(t,&wmsize);
            NumberOfWM = wmsize / sizeof(struct WaitingMail);

            if(wmsize != 0)
            {
               wm = calloc(1,wmsize);

               if(wm != NULL)
               {
                  BOOL  Changed = FALSE;

                  fh = NULL;
                  fh = Open(t,MODE_READWRITE);

                  if(fh)
                  {
                     long wl;

                     Read(fh,wm,wmsize);

                     Changed = FALSE;

                     for(wl = 0; wl < NumberOfWM; wl++)
                     {
                        if(wm[wl].areanum == AreaToMove)
                        {
                           ASPrintf(NULL,wm[wl].msgid,"%04ld:%05d",NewAreaNumber,wm[wl].messagenum);
                           Changed = TRUE;
                           wm[wl].areanum = NewAreaNumber;

                        }
                     }

                     if(Changed)
                     {
                        qsort(wm,NumberOfWM,sizeof(struct WaitingMail),CompareWM);
                        Seek(fh,0,OFFSET_BEGINNING);
                        Write(fh,wm,wmsize);
                        AFPrintf(&UserDat,sout,"Waitingmail.dat ... ");
                     }

                     Close(fh);  fh = NULL;
                  }

                  free(wm); wm = NULL;
               }
            }
         }
      }
//-

      AFPrintf(&UserDat,sout, "%a6done.\n");
   }

   free(ns); ns = NULL;
//-
/// Wrap up
   FreeArea(AreaToMove,"DLG_AreaEd",(AreaType ? FILELOCK : MSGLOCK));
   TwoLines();
   return(TRUE);
//-

}
//-
/// CompareWM
int CompareWM(struct WaitingMail *wm1, struct WaitingMail *wm2)
{
   return(Stricmp(wm1->msgid, wm2->msgid));
}
//-

