#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/execbase.h>
#include <exec/nodes.h>
#include <dos/dos.h>
#include <dos/dostags.h>
#include <dos/filehandler.h>
#include <libraries/dos.h>
#include <intuition/intuition.h>
#include <intuition/gadgetclass.h>
#include <libraries/reqtools.h>
#include <libraries/dos.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/intuition_protos.h>
#include <clib/gadtools_protos.h>
#include <clib/graphics_protos.h>
#include <clib/reqtools_protos.h>

#include "afcopy_defines.h"
#include "afcopy_protos.h"
#include "afcopy_version.h"
#include "afcopy_vars.h"


void getfiles(int side, char *path)
{
  BPTR FL;
  struct FileInfoBlock *FB;
  long err;
  char errormsg[600],iomsg[50];

#ifdef DEBUG
  puts("getfiles()");
#endif

  pathok[side]=FALSE;
  clearside(side);

  SetAPen(W->RPort,2);
/*  SetBPen(W->RPort,0);*/ /*assume backgroung is color 0 due to clearfiles()*/
  OutTextXY(W,filexpos[side]+50,topborder+50,"Reading Directory...");
  totalfiles[side]=0;
  if ((DoDiskInfo(side,path)==FALSE) || ((FL=Lock(path,(long)ACCESS_READ))==NULL))
  {
    err=IoErr();
    if (!(err==226 && ignorenodisk))
    {
      IoErrMsg(iomsg,err);

      sprintf(errormsg,"Error Getting Directory!\n%s\n%s",path,iomsg);
      rtEZRequest (errormsg,"Okey Dokey!",NULL,(struct TagItem *)&reqtags,NULL);
    }
  }
  else
  {
    NameFromLock(FL,cpath[side],MAX_PATH_LEN);
    addterm(cpath[side]);
    FB=malloc(sizeof(struct FileInfoBlock));
    err= !Examine(FL,FB);
    if (!err)
    {
      pathok[side]=TRUE;
      do
      {
        err=!ExNext(FL,FB);
        if (!err)
        {
          if (totalfiles[side] < MAX_FILES_IN_LIST)
          {
            if (FB->fib_DirEntryType!=0)
            {
              if (ignorehiddenbit || (!ignorehiddenbit && !(FB->fib_Protection & 1<<7)))
              {
                if (allocmemforname(side))
                {
                  strcpy(filename[side][totalfiles[side]],FB->fib_FileName);
                  filesize[side][totalfiles[side]]=FB->fib_Size;
                  filetype[side][totalfiles[side]]=FB->fib_DirEntryType<0 ? -1 : 1;
                  filetags[side][totalfiles[side]]=FALSE;
                  totalfiles[side]++;
                }
                else
                {
                  rtEZRequest("no memory left!!","Bogus",NULL,(struct TagItem *)&reqtags,NULL);
                }
              }
            }
            else
            {
              rtEZRequest ("Encountered A Strange File Entry!","Hmm, I'l check my disk",NULL,(struct TagItem *)&reqtags,NULL);
            }
          }
        }
      } while (!err);
    }
    free(FB);
    UnLock(FL);
  }
  updateslider(side);
  qsortfiles(side,0,totalfiles[side]-1);
  clearside(side);
}

/*
 * i'd just like to thank the author of format for the follow bit of
 * code, some of which is nicked from his source.
 */

void findvolumes(int side)
{
  struct DosList      *DosList;
  struct DeviceNode   *DevNode;
  UBYTE           *Pointer;
  char string[32]="";
  int loop;

  pathok[side]=FALSE;
  totalfiles[side]=0;

  clearside(side);
  DosList = LockDosList(LDF_ALL|LDF_READ);
  while(DosList = NextDosEntry(DosList,LDF_ALL|LDF_READ))
  {
    DevNode = (struct DeviceNode *)DosList;
    if (DevNode->dn_Type==DLT_DIRECTORY || DevNode->dn_Type==DLT_VOLUME)
    {
      Pointer = (UBYTE *)BADDR(DevNode -> dn_Name);
      if (Pointer[0])
      {
        for(loop = 0 ; loop < Pointer[0] ; loop++)
                          string[loop] = Pointer[loop + 1];

        string[Pointer[0]]   = 0; /* terminate string */
        strcat(string,":");
        AddToFileList(side,string,0,1,FALSE);
      }
    }
  }
  UnLockDosList(LDF_ALL|LDF_READ);
  qsortfiles(side,0,totalfiles[side]-1);
  strcpy(cpath[side],"");
  updatepath(side);
  displayoffset[side]=0;
  updateslider(side);
  displayfilelist(side,displayoffset[side]);
}

LONG getfilesize(char *filename)
{
  BPTR FL;
  struct FileInfoBlock *FB;
  LONG retval=-1;

#ifdef DEBUG
  puts("getfilesize()");
#endif

  if (FL=Lock(filename,(long)ACCESS_READ))
  {
    if(FB=malloc(sizeof(struct FileInfoBlock)))
    {
      if (Examine(FL,FB))
      {
        retval=FB->fib_Size;
      }
      free(FB);
    }
    UnLock(FL);
  }
  return(retval);
}

int ModifyComment(char *filename,BOOL usedefcomm)
{

  /* return -1 if ALL was pressed */

  char comment[MAX_COMMENT_LEN+1];

  int errnum=0;
  BPTR FL;
  struct FileInfoBlock *FB;
  int doit=1;

#ifdef DEBUG
  puts("ModifyComment()");
#endif

  if (!usedefcomm)
  {
    if ((FL=Lock(filename,(long)ACCESS_READ))==NULL)
    {
      errnum=IoErr();
    }
    else
    {
      if(FB=malloc(sizeof(struct FileInfoBlock)))
      {
        errnum= !Examine(FL,FB);
        if (!errnum)
        {
          strcpy(comment,FB->fib_Comment);
          free(FB);
        }
        UnLock(FL);
      }
      else
      {
        errnum=103; /* NO MEM! */
      }
    }
  }
  else
  {
    strcpy(comment,defaultcomment);
  }
  if (!errnum)
  {
    if (!usedefcomm)
    {
      switch(rtGetString (comment, MAX_COMMENT_LEN, "Modify Comment", NULL,
                              RTGS_GadFmt, "Ok|ALL|Cancel",
                              RT_Window,W,
                              TAG_END))
      {
        case 2:
          strcpy(defaultcomment,comment);
          doit=2;
          break;
        case 0:
          doit=0;
          break;
      }
    }
    if (doit)
    {
      SetComment(filename,comment);
      errnum=IoErr();
      if (!errnum && doit==2) errnum=-1;
    }
  }
  return(errnum);
}


int filecopy(char *fromname,char *toname)
{

/*
 * Simple function to copy a file, return IoErr if it fails, else it returns 0
 * (if it fails it *will* delete the destination file if it exists.)
 */
  LONG f1,f2;
  ULONG *buf;
  ULONG allocd,fromsize,nr,nw; /* ho ho ho, I forget to add the U to uword the first time..... */
               /* makes life interesting when you can only copy files less than*/
               /* 32768 bytes long......... hehehe!! */
  BOOL cancel=FALSE,ChangedIt=FALSE;
  int errnum=0;
  BPTR FL;
  struct FileInfoBlock *FB;
  UWORD prot=240;
  char reqstr[300]="\0";


#ifdef DEBUG
  puts("filecopy()");
#endif

  if (FB=malloc(sizeof(struct FileInfoBlock)))
  {

    if ((FL=Lock(fromname,(long)ACCESS_READ))==NULL)
    {
      errnum=IoErr();
    }
    else
    {
      errnum= !Examine(FL,FB);
      if (!errnum)
      {
        prot=FB->fib_Protection;
        fromsize=FB->fib_Size;
      }
      UnLock(FL);
      if (prot & FIBF_READ)
      {
        if ((!setprotverify) || ((setprotverify) && (rtEZRequest("File Protected From Reading!\n"
                                          "Shall I change the protection for a mo ?",
                                          "_Ok|_Dont you dare!",NULL,(struct TagItem *)&reqtags,NULL))))
        {
          ChangedIt=TRUE;
          SetProtection(fromname,240);
        }
      }
    }

    if (!autooverwrite && ((f1=Open(toname,MODE_OLDFILE))!=NULL))
    {
      IoErr(); // Clear IO Error..
      ExamineFH(f1,FB);
      Close(f1);
      sprintf(reqstr,"Destination File Exists!\nNEW: %-32s %ld\nOLD: %-32s %ld\nOverwrite ?",fromname,fromsize,toname,FB->fib_Size);
      if (!skipall)
      {
        switch (rtEZRequest(reqstr,"_Yes|_All|_Skip|Sk_ip All|_Cancel",NULL,(struct TagItem *)&reqtags,NULL))
        {
          case 0:
            cancel=TRUE;
            errnum=1;
            break;
          case 2:
            tempautooverwrite=TRUE;
            autooverwrite=TRUE;
            break;
          case 3:
            cancel=TRUE;
            break;
          case 4:
            skipall=TRUE;
            break;
        }
      }
      if (skipall) cancel=TRUE;
    }
    else
    {
      cancel=FALSE;
    }

    free(FB);
  }

  if (!cancel)
  {
    if ((f1=Open(fromname,MODE_OLDFILE))!=NULL)
    {
      if ((f2=Open(toname,MODE_NEWFILE))!=NULL)
      {
        allocd=0;
        if (fromsize>max_copy_buf_size) fromsize=max_copy_buf_size;
        if ((buf=AllocMem(fromsize,MEMF_PUBLIC))!=NULL)
        {
          allocd=fromsize;
        }
        if ((allocd==0) && (buf=AllocMem(COPYBUFSIZE,MEMF_PUBLIC))!=NULL)
        {
          allocd=COPYBUFSIZE;
        }
        if (allocd)
        {
          do
          {
            if (!(cancel=CheckStatCancel() ))
            {
              nr=Read(f1,buf,allocd-1);
              nw=Write(f2,buf,nr);
            }
          } while (nr==nw && nr!=0 && !cancel);
          if (nr!=nw)
          {
            errnum=IoErr();
            if (!errnum) errnum=224;
          }
          FreeMem(buf,allocd);
          if (cancel) errnum=1;
        }
        else
        {
          errnum=103;  /* NO FREE STORE! */
        }
        Close(f2);
        if (errnum)
        {
          DeleteFile(toname);
          IoErr();  /* Clear IO Error */
        }
      }
      else
      {
        errnum=IoErr();
      }
      Close(f1);
    }
    else
    {
      errnum=IoErr();
    }
  }

  if (!errnum)
  {
    if ((FL=Lock(fromname,(long)ACCESS_READ))==NULL)
    {
      errnum=IoErr();
    }
    else
    {
      FB=malloc(sizeof(struct FileInfoBlock));
      errnum= !Examine(FL,FB);
      if (!errnum)
      {
        SetComment(toname,FB->fib_Comment);
        SetProtection(toname,prot);
        SetFileDate(toname,&FB->fib_Date);
        free(FB);
      }
      UnLock(FL);
      if (ChangedIt) SetProtection(fromname,prot);
    }
  }
  return(errnum);
}

int filenuke(char *nukename)
{
  int errnum;

#ifdef DEBUG
  puts("filenuke()");
#endif

  DeleteFile(nukename);
  errnum=IoErr();
  if (errnum)
  {
    SetProtection(nukename,240);
    errnum=IoErr();
    if (!errnum)
    {
      DeleteFile(nukename);
      errnum=IoErr();
    }
  }
  return(errnum);
}

int fileswap(char *fromname,char *toname)
{
  int errnum=0;

#ifdef DEBUG
  puts("fileswap()");
#endif

  if (!Rename(fromname,toname))
  {
    errnum=filecopy(fromname,toname);
    if (!errnum)
    {
      errnum=filenuke(fromname);
    }
  }
  return(errnum);
}

void Makedir(int side)
{
  char strbuf[MAX_PATH_LEN+1];
  BPTR FL;
  int errnum;

#ifdef DEBUG
  puts("Makedir()");
#endif

  if (pathok[side])
  {
    strcpy(strbuf,cpath[side]);
    addterm(strbuf);
    if (rtGetString (strbuf, MAX_PATH_LEN, "Enter Directory Name", NULL,RT_Window,W, TAG_END))
    {
      if (strlen(FilePart(strbuf))>30)
      {
        rtEZRequest("Name Too Long!","Bogus!",NULL,(struct TagItem *)&reqtags,NULL);
      }
      else
      {
        FL=CreateDir(strbuf);
        if (FL==NULL)
        {
          rtEZRequest ("Error Creating Directory","Bogus",NULL,(struct TagItem *)&reqtags,NULL);
        }
        else
        {
          UnLock(FL);

          if (SameDir(strbuf,cpath[side]))
          {
            if (AddToFileList(side,FilePart(strbuf),0,1,FALSE)) Updatedisplay(side);
          }

          if (rtEZRequest("Do you want an icon ?","Yes|No",NULL,(struct TagItem *)&reqtags,NULL))
          {
            strfcat(strbuf,".info",MAX_PATH_LEN);
            errnum=filecopy(defaulticonfile,strbuf);
            if (errnum) DosError("Error Copying Icon File",defaulticonfile,errnum,"Ok, I'll check my config.");
            if (!errnum && SameDir(strbuf,cpath[side]))
            {
              if (AddToFileList(side,FilePart(strbuf),getfilesize(strbuf),-1,FALSE)) Updatedisplay(side);
            }
          }
        }
      }         /* it's attack of the killer pretty patterns!!! */
    }           /* sorry, I just couldnt resist it... :-0 */
  }
}

int DirFunc(char *dirname,char *todirname,int mode)
{
  char fname[MAX_PATH_LEN+1],tofname[MAX_PATH_LEN+1];
  BOOL cancel=FALSE;
  int FuncErr=0;
  BPTR FL;
  struct FileInfoBlock *FB;
  long err;
  int rret=FALSE;

#ifdef DEBUG
  puts("DirFunc()");
#endif

  /* attempt a rename on a swap command for a directory */

  if (mode==G_Swap)
  {
    rret=Rename(dirname,todirname);
  }

  if ((!rret && mode==G_Swap) || mode!=G_Swap)
  {
    switch (mode)
    {
      case G_Swap:
      case G_Copy:
        if ((FL=CreateDir(todirname))!=NULL)
        {
          UnLock(FL);
        }
        break;
    }

    if ((FL=Lock(dirname,(long)ACCESS_READ))==NULL)
    {
      FuncErr=IoErr();
      DosError("Error Getting Directory",dirname,FuncErr,"Ok!");
    }
    else
    {
      FB=malloc(sizeof(struct FileInfoBlock));
      err= !Examine(FL,FB);
      if (!err)
      {
        do
        {
          cancel=CheckStatCancel();
          if (!cancel)
          {
            FuncErr=0;
            err=!ExNext(FL,FB);
            if (!err)
            {
              strcpy(fname,dirname);
              addterm(fname);
              strfcat(fname,FB->fib_FileName,MAX_PATH_LEN);

              strcpy(tofname,todirname);
              addterm(tofname);
              strfcat(tofname,FB->fib_FileName,MAX_PATH_LEN);

              if (FB->fib_DirEntryType<0)
              { /* FILE */
                switch (mode)
                {
                  case G_Delete:
                    UpdateStat("Delete",dirname,"",FB->fib_FileName);
                    FuncErr=filenuke(fname);
                    break;
                  case G_Copy:
                    UpdateStat("Copy",dirname,todirname,FB->fib_FileName);
                    FuncErr=filecopy(fname,tofname);
                    break;
                  case G_Swap:
                    UpdateStat("Swap",dirname,todirname,FB->fib_FileName);
                    FuncErr=fileswap(fname,tofname);
                    break;
                }
              }
              else
              {
                if (FB->fib_DirEntryType>0)
                {
                  switch (mode)
                  {
                    case G_Delete:
                      UpdateStat("Delete",dirname,"",FB->fib_FileName);
                      FuncErr=DirFunc(fname,NULL,mode);
                      break;
                    case G_Copy:
                      UpdateStat("Copy",dirname,todirname,FB->fib_FileName);
                      FuncErr=DirFunc(fname,tofname,mode);
                      break;
                    case G_Swap:
                      UpdateStat("Swap",dirname,todirname,FB->fib_FileName);
                      FuncErr=DirFunc(fname,tofname,mode);
                      break;
                  }
                }
                else
                {
                  rtEZRequest ("Encountered A Strange File Entry!","Hmm, I'll check my disk",NULL,(struct TagItem *)&reqtags,NULL);
               }
              }
              if (FuncErr>1)
              {
                cancel=DosError("Error On File/Dir",fname,FuncErr,cancelcontmsg);
              }
            }
            if (FuncErr==1) cancel=TRUE;
          }
          else
          {
            FuncErr=1; /* CANCEL */
          }
        } while (!err && !cancel);
      }
      UnLock(FL);
      free(FB);
      if (!cancel /*&& !FuncErr*/  )
      {
        switch (mode)
        {
          case G_Swap:
          case G_Delete:
            DeleteFile(dirname);
            FuncErr=IoErr();
  /*          if (FuncErr) DosError("Error Removing Directory",fname,FuncErr,"Ok!");  dont need errmsg here as it returns the error
                                                                                      so you get the same error message twice :-( */
            break;
        }
      }
    }
  }
  return(FuncErr);
}



long ExecCommand(char *command,BOOL asynch,BOOL shuffle)
{
  static ULONG sysargs[] =
  {
    SYS_Input,NULL,
    SYS_Output,NULL,
    SYS_Asynch,FALSE,  /* add option to this */
    SYS_UserShell,TRUE,
    NP_Priority,0L,
    TAG_DONE
  };
  BPTR outputfile;
  long retval=0;

  remspaces(command,command);

  if (shuffle && customscreenopen) ScreenToBack(mysc);

  sysargs[5]=asynch ? TRUE : FALSE;

  if (sysargs[5]) /* open a new window if asynch otherwise use normal one */
  {
    outputfile = Open(outputcon,MODE_OLDFILE);
  }
  else
  {
    /* test to see if one is already open, if not open it! */
    if (outputconfile==NULL) outputconfile = Open(outputcon,MODE_OLDFILE);
    outputfile=outputconfile;
  }
  if (outputfile) /* have we got an output file ? */
  {
    sysargs[1]=(ULONG)outputfile;
    retval=SystemTagList(command,(struct TagItem *)sysargs);
    if (shuffle && customscreenopen && !asynch) ScreenToFront(mysc);
  }
  return(retval);
}

void DoFormat( void )
{
  LONG which,FFS,DC,ICONS;
  char cmdstr[81]="\0",name[33]="\0";

  if ((which=rtEZRequest("Format What Drive ?","DF_0:|DF_1:|DF_2:|DF_3:|_CANCEL",NULL,(struct TagItem *)&reqtags,NULL))
    && (rtGetString (name, 32, "Enter Volume Name", NULL,RT_Window,W, TAG_END))
    && (name[0]!='\0'))
  {
    FFS=rtEZRequest("Fast File System ?","Yup|Nope",NULL,(struct TagItem *)&reqtags,NULL);
    DC=rtEZRequest("Directory Cache ?","Yup|Nope",NULL,(struct TagItem *)&reqtags,NULL);
    ICONS=!rtEZRequest("Trashcan ?","Nope|Yup",NULL,(struct TagItem *)&reqtags,NULL);
    sprintf(cmdstr,"FORMAT DRIVE DF%d: NAME %s %s %s %s",which-1,name,FFS ? "FFS" : "",DC ? "DIRCACHE" : "",ICONS ? "" : "NOICONS");
    ExecCommand(cmdstr,TRUE,shufflescreens);
  }
}

void cdto( char *path )
{
  BPTR FL,NFL;

  if (FL=Lock(path,(long)ACCESS_READ))
  {
    NFL=CurrentDir(FL);
    UnLock(NFL);
  }
}
