#include <iostream.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <intuition/intuition.h>
#include <libraries/prog_bar.h>

#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/intuition_protos.h>

#include <string.h>
#include <stdlib.h>

#define BSIZE 100000L
#define S16OFF  3690L

static char ver[] = "\0$VER:Offset 1.12 "__AMIGADATE__;
extern struct IntuitionBase *IntuitionBase;

//+ "class Offset(char *filename, short yset)"

/* ---------------------------------- Offset -----------------------------------

 Commentaire:

*/

class Offset
{
  public:

  Offset(char *filename, short yset)
  {
    unsigned long bufsize = BSIZE;

    buf = 0L;
    ahand = 0L;

    if(ahand = Open(filename, MODE_OLDFILE))
    {
      unsigned long free;

      if(size = GetSize())
      {
        if(size < 1000000L) bufsize = size / 10;

        if(buf = (short *)AllocVec(bufsize, MEMF_CLEAR|MEMF_PUBLIC))
        {
          if(free = GetFree())
          {
            if(free > size)
            {
              strcpy(&edfile[0], filename);
              strcat(&edfile[0], ".edit");
              if(CopyHeader(bufsize)) PlanA(filename, bufsize, yset);
            }
            else
            {
              Close(ahand);
              ahand = 0L;
              PlanB(filename, bufsize, yset);
            }
          }
          else cout << "Can't get free space\n";
        }
        else cout << "No memory for buffer\n";
      }
      else cout << "Can't get file size\n";
    }
    else cout << "Can't open input file " << filename << "\n";
  }

  ~Offset()
  {
    if(buf) FreeVec(buf);
    if(ahand) Close(ahand);
    if(bhand) Close(bhand);
  }

  private:

//+ "struct Window *setupWindow(char *name)"

  struct Window *setupWindow(char *name)
  {
    wnd = 0;
    struct Screen *scr;
    short width, height, y;

    if(scr=LockPubScreen((unsigned char *)"FRONTPUBSCREEN"))
    {
      width = (short)(scr->WBorLeft + scr->WBorRight);
      height = (short)(scr->WBorTop + scr->WBorBottom);
      y = (short)scr->Font->ta_YSize;


      if(wnd=OpenWindowTags(0L,WA_Left, 10,
                               WA_Top, 10,
                               WA_Width, 30 * y + width,
                               WA_Height, 4 * y + height,
                               WA_RMBTrap, 1,
                               WA_Activate, 1,
                               WA_PubScreen, scr,
                               WA_Title, name,
                               TAG_DONE))
      {
        PrBar = CreateProgBar ( wnd, 2 * y + width/2, 2 * y,
                                26 * y, y + y/4, 100,
                                PB_BarValue, 0,
                                PB_BorderType, PBBT_RECESSED,
                                PB_TextMode, PBTM_PERCENT,
                                PB_TextPosition, PBTP_CENTRE,
                                PB_TextFont, scr->Font,
                                TAG_DONE );

        if(!PrBar)
        {
          CloseWindow(wnd);
          wnd = 0;
        }
      }
      UnlockPubScreen(NULL, scr);
    }
    return(wnd);
  }
//-

//+ "void  freeupWindow(struct Window*)"

  void  freeupWindow(struct Window*)
  {
    if(PrBar) FreeProgBar(PrBar);
    if(wnd) CloseWindow(wnd);
  }
//-

//+ "unsigned long GetSize()"

  unsigned long GetSize()
  {
    struct FileInfoBlock *fib;
    size = 0;

    if(fib = (struct FileInfoBlock *)AllocVec(sizeof(struct FileInfoBlock),
                                                   MEMF_CLEAR|MEMF_PUBLIC))
    {
      if(ExamineFH(ahand, fib))
      {
        size = fib->fib_Size;
      }
      FreeVec(fib);
    }
    return(size);
  }
//-

//+ "unsigned long GetFree()"

  unsigned long GetFree()
  {
    BPTR lock;
    struct InfoData *id;
    unsigned long f = 0;

    if(lock = DupLockFromFH(ahand))
    {
      if(id = (struct InfoData *)AllocVec(sizeof(struct InfoData),
                                                    MEMF_CLEAR|MEMF_PUBLIC))
      {
        if(Info(lock, id))
        {
          f = ((id->id_NumBlocks)-(id->id_NumBlocksUsed))*id->id_BytesPerBlock;
        }
        FreeVec(id);
      }
      UnLock(lock);
    }
    return(f);
  }
//-

//+ "BOOL CopyHeader(unsigned long bufsize)"

  BOOL CopyHeader(unsigned long bufsize)
  {
    if(bhand = Open(&edfile[0], MODE_NEWFILE))
    {
      if(bufsize < S16OFF)
      {
        unsigned long x;

        for(x=0;x < S16OFF;x=x+bufsize)
        {
          actlen = Read(ahand, buf, bufsize);

          if(actlen < 0)
          {
            cout << "error reading file\n";
            return(NULL);
          }
          actlen = Write(bhand , buf, actlen);

          if(actlen < 0)
          {
            cout << "error writing file\n";
            return(NULL);
          }
        }
      }
      else
      {
        actlen = Read(ahand, buf, S16OFF);

        if(actlen != S16OFF)
        {
          cout << "error reading file\n";
          return(NULL);
        }

        actlen = Write(bhand , buf, S16OFF);

        if(actlen != S16OFF)
        {
          cout << "error writing file\n";
          return(NULL);
        }
      }
    }
    else
    {
      cout << "can't open " << &edfile[0] << "\n";
      return(NULL);
    }
    return(TRUE);
  }
//-


//+ "void PlanA(char *filename, unsigned long bufsize, short yset)"

  void PlanA(char *filename, unsigned long bufsize, short yset)
  {
    unsigned long total=0;

    Seek(ahand, S16OFF, OFFSET_BEGINNING);
    Seek(bhand, S16OFF, OFFSET_BEGINNING);

    if(wnd = setupWindow(filename))
    {
      while(actlen = Read(ahand, buf, bufsize))
      {
        if(actlen < 0)
        {
          cout << "error reading file\n";
          break;
        }

        int x;

        for(x = 0; x < actlen/2; x++)
        {
          buf[x] = (short)((short)buf[x] + (short)yset);
        }
        actlen = Write(bhand, buf, actlen);

        if(actlen < 0)
        {
          cout << "error writing file\n";
          break;
        }
        total = total + actlen;
        UpdateProgBar ( PrBar, total/((size/100)+1));
      }
      freeupWindow(wnd);
    }
    else cout << "can't open window\n";

    Close(ahand);
    ahand = 0;
    Close(bhand);
    bhand = 0;

    if(DeleteFile(filename))
    {
      Rename(&edfile[0], filename);
    }
    else cout << "can't delete source file you have now\ntwo file named "
              << filename << " and " << &edfile[0] << "\n";
  }
//-

//+ "void PlanB(char *filename, unsigned long bufsize, short yset)"

  void PlanB(char *filename, unsigned long bufsize, short yset)
  {
    unsigned long total = 0;

    if(ahand = Open(filename, MODE_READWRITE))
    {
      if(wnd = setupWindow(filename))
      {
        Seek(ahand, S16OFF, OFFSET_BEGINNING);

        while(actlen = Read(ahand, buf, bufsize))
        {
          if(actlen < 0)
          {
            cout << "error reading file\n";
            break;
          }

          int x;

          for(x = 0; x < actlen/2; x++)
          {
            buf[x] = (short)((short)buf[x] + (short)yset);
          }
          Seek(ahand, - (actlen), OFFSET_CURRENT);

          actlen = Write(ahand, buf, actlen);

          if(actlen < 0)
          {
            cout << "error writing file\n";
            break;
          }
          total = total + actlen;
          UpdateProgBar ( PrBar, total/((size/100)+1));
        }
        freeupWindow(wnd);
      }
      else cout << "can't open window\n";
    }
    else cout << "can't open file " << filename << "\n";
  }
//-

  protected:

  short         *buf;
  BPTR          ahand;
  BPTR          bhand;
  PBAR          *PrBar;
  long          actlen;
  unsigned long size;
  struct        Window *wnd;
  char          edfile[255];
};
//-

//+ "void main(int argc, char *argv[])"

/* ----------------------------------- main ------------------------------------

 Commentaire:

*/

void main(int argc, char *argv[])
{
  if(argc > 2)
  {
    int tmpargc;
    tmpargc = argc;

    if(argc & 1)
    {
      tmpargc = tmpargc - 1;
      while(tmpargc)
      {
        Offset o(argv[argc-tmpargc], (short)atol(argv[argc-tmpargc+1]));
        tmpargc = tmpargc - 2;
      }
    }
    else cout << "Wrong number of argument\n";
  }
  else cout << "Usage: Offset filename offset ...\n";
}

//-

