/* optimize.c 22.3.1989 © by Heiner Hückstädt */
extern UBYTE optimizer;
extern UBYTE *bitmapbuffer;
extern UBYTE trackbuffer[80];
extern UBYTE verify;
extern BOOL  form;
extern ULONG bitblock;
extern ULONG trackpos[80];
extern ULONG blockpos[22];
extern char title[];
#define ERROR 1
#define NOERRROR 0
#define NOTUSED 0
#define DATA 1
#define FILEHEADER 2
#define FILELIST 3
#define USERDIR 4
#define ROOT 5
#define BITMAP 6
#define UNDEFINED 7
struct Block
     {
      ULONG HashBlock;
      ULONG FileListBlock;
      ULONG NewBlock;
      UWORD BlockZahl;
      UWORD NextBlock;
      UBYTE BlockType;
     };
 
struct Block block[1760];
ULONG basis;
UBYTE blockmerker[1760];
ULONG *files;
ULONG *bitbuffer;
extern ULONG *writebuffer;
extern ULONG *verifybuffer;

Optimize(sourcereq,destreq)
struct IOStdReq *sourcereq, *destreq;
  {
     register UBYTE err,*bytebuffer;
     register ULONG i,j,*buf,pos;

     basis = 882;
 
     BltClear(verifybuffer,11264L,1L);
     bitbuffer =(ULONG *)verifybuffer;
     files=(ULONG *)verifybuffer+128;

     for (i=0;i<1760;i++)
        {
         blockmerker[i]=0; 
         block[i].HashBlock = 0L;
         block[i].FileListBlock = 0L;
         block[i].NewBlock = 0L;
         block[i].BlockZahl = 0;
         block[i].NextBlock = 0;
         block[i].BlockType = 0;
        }

     bitbuffer =(ULONG *)verifybuffer;
     files=(ULONG *)verifybuffer+128;

     printbox("SCANNING SOURCE DISK     'ESC' TO ABORT",1L);
     print("OPTIMIZER REPORT",8L,80L,2L);
     print("------------------------",8L,90L,3L);
     for (j=0;j<80;j++)
      {
       bytebuffer = (UBYTE *)writebuffer;
       buf = (ULONG *)writebuffer;
       sprintf(&title[0],"SCANNING TRACK    : %ld",j);
       print(&title[0],8L,100L,1L);
       err = 0;
       if(ReadTrack(j,writebuffer,sourcereq) == ERROR)  err = 1;

       i = 0;
       do
        {
         pos = i+j*22;
         if (err)
             ReadBlock(pos,bytebuffer,sourcereq);

         if (!bitmapbuffer[pos])
           {
            block[pos].BlockType = NOTUSED;
           }
         else if (bytebuffer[3] == 0x08)
           {
            block[pos].BlockType = DATA;   /* Data */
            block[pos].NextBlock = (UWORD)buf[4];

           }
         else if (bytebuffer[3] == 0x02 && bytebuffer[511] == 0xfd)
           {
            block[pos].BlockType = FILEHEADER;   /* FileHeader */
            block[pos].HashBlock = buf[124];
            block[pos].FileListBlock  = buf[126];
            block[pos].BlockZahl = (UWORD)buf[2];
            block[pos].NextBlock = (UWORD)buf[4];

           }
         else if (bytebuffer[3] == 0x10 && bytebuffer[511] == 0xfd)
           {
            block[pos].BlockType = FILELIST;   /* FileList */
            block[pos].FileListBlock  = buf[126];

           }
         else if (bytebuffer[3] == 0x02 && bytebuffer[511] == 0x02)
           {
            block[pos].BlockType = USERDIR;   /* UnterDirectory */
            block[pos].HashBlock = buf[124];
 
           }
         else if (bytebuffer[3] == 0x02 && bytebuffer[511] == 0x01)
           {
            block[pos].BlockType = ROOT;   /* RootDirectory */
            block[pos].NewBlock  = pos;
            blockmerker[pos] = 1;
           }
         else if (pos == bitblock)
           {
            block[pos].BlockType = BITMAP;   /* Bam */
            block[pos].NewBlock  = 881;
            blockmerker[881] = 1;

           }
         else {
 
            block[pos].BlockType = UNDEFINED;   /* Boot oder ähnliches */
            block[pos].NewBlock  = pos;   /* kommen an die gleiche Stelle */
            blockmerker[pos] = 1;
           }
loop1:    i++;
         buf = buf + 128L;
         bytebuffer = bytebuffer + 512;
         if (key()==0x75) goto adieu;
        } while (i<22);
      }

       BltClear(writebuffer,11264L,1L);
       printbox("CREATING NEW DISK STRUCTURE     'ESC' TO ABORT",1L);

    if(optimizer == 1) FastLoad(880L,writebuffer,sourcereq);
    else               FastDir(880L,writebuffer,sourcereq);

    CopyBlocks(writebuffer,sourcereq,destreq);

   
adieu:
   i=0;
}

CopyBlocks(buffer,source,dest)
ULONG *buffer;
struct IOStdReq *source,*dest;
   {
   register ULONG i,j,k,l;
   register ULONG *buf;

   buf=(ULONG *)buffer;

    printbox("TRANSFERRING BLOCKS     'ESC' TO ABORT",1L);

    for(k=0;k<80;k++) block[k].BlockZahl = 0;
    for(k=0;k<1760;k++) block[k].HashBlock = 0;
    for(k=0;k<1760;k++)
       {     
             block[block[k].NewBlock/22].BlockZahl = 1;
             block[block[k].NewBlock].HashBlock = k;
       }     

    for(k=0;k<80;k++)
    {
     BltClear(buf,11264L,1L);
     if(block[k].BlockZahl) 
      {
       buffer = (ULONG *)buf;
       for(i=0;i<22;i++)
        {
         j=block[k*22+i].HashBlock;
         if(j)
          {
           sprintf(&title[0],"READING BLOCK     : %ld    ",j);
           print(&title[0],8L,110L,1L);
           ReadBlock(j,buffer,source);
           switch (block[j].BlockType)
            {
             case DATA:
                buffer[1]=block[buffer[1]].NewBlock;
                buffer[4]=block[buffer[4]].NewBlock;
                CorrectChecksum(buffer,5);
                break;
             case FILEHEADER:
                buffer[1]=block[i].NewBlock;
                buffer[4]=block[buffer[4]].NewBlock;
                buffer[124]=block[buffer[124]].NewBlock;
                buffer[125]=block[buffer[125]].NewBlock;
                buffer[126]=block[buffer[126]].NewBlock;
                for(l=0;l<72;l++)
                    buffer[6+l] = block[buffer[6+l]].NewBlock;
                CorrectChecksum(buffer,5);
                break;
             case FILELIST:
                buffer[1]=block[i].NewBlock;
                buffer[125]=block[buffer[125]].NewBlock;
                buffer[126]=block[buffer[126]].NewBlock;
                for(l=0;l<72;l++)
                    buffer[6+l] = block[buffer[6+l]].NewBlock;
                CorrectChecksum(buffer,5);
             case USERDIR:
                buffer[1]=block[i].NewBlock;
                buffer[4]=block[buffer[4]].NewBlock;
                buffer[124]=block[buffer[124]].NewBlock;
                buffer[125]=block[buffer[125]].NewBlock;
                for(l=0;l<72;l++)
                    buffer[6+l] = block[buffer[6+l]].NewBlock;
                CorrectChecksum(buffer,5);
                break;
             case ROOT:
                buffer[79]=881L;
                for(l=0;l<72;l++)
                    buffer[6+l] = block[buffer[6+l]].NewBlock;
                CorrectChecksum(buffer,5);
                break;
             case BITMAP:
                goto loopweiter;
             case UNDEFINED:
                break;
            }
          }
loopweiter:
         if(key()==0x75) goto copyexit;
         buffer += 128L; /* 128*4(long) = 512 Bytes */
        }
       sprintf(&title[0],"WRITING TRACK     : %ld",k);
       print(&title[0],8L,120L,1L);
       FormatTrack(k,buf,dest);
       if(verify) VerifyTrack(k,buf,verifybuffer,dest);
      }
    else {if(form)
                 {
                 sprintf(&title[0],"FORMATTING TRACK  : %ld",k);
                 print(&title[0],8L,130L,1L);
                 FormatTrack(k,buf,dest);}
                 }
    }
   ReadTrack(0L,buf,source);   
   WriteBlock(0L,buf,dest);
   WriteBlock(1L,buf+128L,dest); /* 128*4 = 512 Bytes */
   BltClear(bitbuffer,512L,1L);

   printbox("CREATING BITMAP",1L);
   CreateBitMap();
   WriteBlock(881L,bitbuffer,dest);
   dest->io_Command = CMD_UPDATE;
   DoIO(dest);
copyexit:
   k=0;
 }
 CreateBitMap()
 {
 register ULONG i,j,k;

   for(i=0;i<55;i++) bitbuffer[1+i]=0xffffffffL;
   j=2L;
   for(i=0;i<55;i++)
      {
       for(k=0;k<32;k++)
          {
          if(blockmerker[j]) bitbuffer[1+i] -= (1L << k);
          j++;
          }
      }
  CorrectChecksum(bitbuffer,0);
 }

SetBlock(oldblock)
register ULONG oldblock;
   {

    while (blockmerker[basis])
      {
        basis++;
        if (basis > 1759) basis = 2;
      }
    block[oldblock].NewBlock = basis;
    blockmerker[basis] = 1;
   }
FastDirBlocks()
 {
 register ULONG i,bl;
 i=0L;

 while(files[i])
  {
   bl = (ULONG)files[i];
   while(block[bl].NextBlock)
     {
      bl = (ULONG)block[bl].NextBlock;
      SetBlock(bl);
     }
   i++;
  }
}
FastLoadBlocks()
{
 register ULONG i,j,bl;
 i=0L;

 while(files[i])
  {
   bl = files[i];
   SetBlock(bl);
   j = bl;
   while(block[bl].FileListBlock)
      {
       bl = block[bl].FileListBlock;
       SetBlock(bl);
      }
   bl = j;
   while(block[bl].NextBlock)
      {
       bl = block[bl].NextBlock;
       SetBlock(bl);
      }
    i++;
  }
}

FastLoad(dirblock,buffer,dreq)
ULONG dirblock,*buffer;
struct IOStdReq *dreq;
 {
    register ULONG i,k,j,l,m,o;
    ULONG dirs[100];   /* für alle Fälle */
    j=l=m=0;
    for (i=0;i<100;i++) dirs[i] = 0L;

selbeprozedur:
    ReadBlock(dirblock,buffer,dreq);
    if(key()==0x75) goto loadexit;
    for(i=0;i<72;i++)
       {
        k = buffer[6+i];
        if (block[k].BlockType == USERDIR)
           {
            SetBlock(k);
            dirs[j] = k;
            j++;
           }
         else if (block[k].BlockType == FILEHEADER)
            {
             if (block[k].BlockZahl > 5)
                  {
                   files[m] = k;
                   m++;
                  }
             else
                 {
                  o = k;
                  SetBlock(o);
                  while (block[o].NextBlock)
                    {
                     o = (ULONG)block[o].NextBlock;
                     SetBlock(o);
                    }
                 }
            }
          while(block[k].HashBlock)
              {
                  k = block[k].HashBlock;
                  if(block[k].BlockType == USERDIR)
                      {
                        SetBlock(k);
                        dirs[j] = k;
                        j++;
                      }
                  else
                    {
                     if (block[k].BlockZahl > 5)
                        {
                         files[m] = k;
                         m++;
                        }
                     else
                        {
                        o = k;
                        SetBlock(o);
                        while (block[o].NextBlock)
                          {
                           o = (ULONG)block[o].NextBlock;
                           SetBlock(o);
                          }
                        }
                    }
              }

       }
     dirblock = dirs[l];
     if (dirblock)
      {
       l++;
       goto selbeprozedur;  /* as every year ...... für alle USERDIRS */
      }
 FastLoadBlocks();

loadexit: l=0;
 }
FastDir(dirblock,buffer,dreq)
ULONG dirblock,*buffer;
struct IOStdReq *dreq;
 {
    register ULONG i,k,j,l,m,n,o;
    ULONG dirs[100];   /* für alle Fälle */
    j=l=m=0;
    for (i=0;i<100;i++) dirs[i] = 0L;

sameprocedure:
    ReadBlock(dirblock,buffer,dreq);
    if(key()==0x75) goto direxit;
    for(i=0;i<72;i++)
       {
        k = buffer[6+i];
        if (block[k].BlockType == USERDIR)
           {
            SetBlock(k);
            n = k;
zet:        dirs[j] = k;j++;
hashagain:
             while(block[k].FileListBlock)
              {
               k = block[k].FileListBlock;
               SetBlock(k);
              }
             k = n;
             if(block[k].HashBlock)
                 {
                  k = block[k].HashBlock;
                  SetBlock(k);
                  n = k;
                  if(block[k].BlockType == USERDIR) goto zet;
                  else
                      {
                       if(block[k].BlockZahl < 3)
                           {
                            o = k;
                            while(block[o].NextBlock)
                               {
                                o = (ULONG)block[o].NextBlock;
                                SetBlock(o);
                               }
                           }
                       else { files[m] = k; m++; }
                      }
                  goto hashagain;
                 }
           }
       }
    for(i=0;i<72;i++)
       {
        k = buffer[6+i];
        if (block[k].BlockType == FILEHEADER)
           {
            SetBlock(k);
             if(block[k].BlockZahl < 3)
               {
                o = k;
                while(block[o].NextBlock)
                  {
                   o = (ULONG)block[o].NextBlock;
                   SetBlock(o);
                  }
               }
            else { files[m] = k; m++; }
        n = k;
hash1again:
             while(block[k].FileListBlock)
              {
               k = block[k].FileListBlock;
               SetBlock(k);
              }
             k = n;
            if(block[k].HashBlock)
                 {
                  k = block[k].HashBlock;
                  SetBlock(k);
                  n = k;
                  if(block[k].BlockType == USERDIR){dirs[j]=k;j++;}
                  else
                      {
                       if(block[k].BlockZahl < 3)
                           {
                            o = k;
                            while(block[o].NextBlock)
                               {
                                o = (ULONG)block[o].NextBlock;
                                SetBlock((ULONG)o);
                               }
                           }
                       else { files[m] = k; m++; }
                      }
                  goto hash1again;
                 }
           }
       }


     dirblock = dirs[l];
     if (dirblock)
      {
       l++;
       goto sameprocedure;  /* as every year ...... für alle USERDIRS */
      }


 FastDirBlocks();

direxit: l=0;
 }
CorrectChecksum(buf,position)
register ULONG *buf;
register int position;
  {
  register ULONG i,checksum;

    checksum = 0L;
    for(i=0;i<128;i++) checksum +=buf[i];

    buf[position] -= checksum;
  }
