#include <cpu_prog_model.h>
#include <stdio.h>

#define FALSE   0
#define TRUE    1

#define WORK_DIR  "*>work_dir"

#define FOPEN_READ_BIN    "i"
#define FOPEN_WRITE_BIN   "o"
#define FOPEN_UPDATE_BIN  "i+"

#     define file_per_sec 15    /* It migt be wrong */

static FILE   * int_drive_pointer      = NULL;
static char  ** ext_drive_pointer [35] = {NULL};
static short    current_slot           = 0x60,
                current_drive          = 1,
                current_volume         = 0,
                current_open_mode      = _CLOSE;

static struct
{
   short  volume,
          track,
          sector,
          byte;
}  ext_drive_info;

typedef struct
{
   short   file_flag;
   char    byte  [256];
}  MEM_SEC;

typedef struct
{
   short   file_flag;
   FILE  * file_pointer;
   long    index;
}  FILE_SEC;

typedef struct
{
   short  file_flag;
}  NONE_SEC;

typedef struct
{
   int  dir_unit;
}  DIR;


/*  tas bort */
static struct
{
   char   in_use,
          track,
          sector;
   char   file_name [18 + 1];
   long   position;
}  sector_info;
/* tas bort */


DIR *open_dir( path_name)
char  path_name [];
{
   void  * malloc();
   DIR   * pointer;

   pointer  = (DIR *) malloc( sizeof (DIR) );
   pointer->dir_unit = open( path_name, 0);

   if (pointer->dir_unit == -1)
      return NULL;

   return pointer;
}

close_dir( dir_pointer)
DIR  * dir_pointer;
{
   return close (dir_pointer->dir_unit);
}


int dir_next_file( buffer, dir_pointer)
char   buffer [];
DIR  * dir_pointer;
{
   char  * lsdir(),
         * temp_pointer;

   if ((temp_pointer = lsdir( dir_pointer->dir_unit)) == NULL)
      return FALSE;

   strcpy( buffer, temp_pointer);
   return TRUE;
}

int fsufix( file_name, sufix)
char  file_name [],
      sufix     [];
{
   short  pos;

   pos = strlen( file_name) - 1;
   while (file_name [pos] && (file_name [pos] != '.') )
      pos --;

   if (!strcmp( file_name + pos + 1, sufix) )
      return TRUE;

   return FALSE;
}

inc_ts_pointer( ts_pointer, inc)
short  * ts_pointer,
         inc;
{
   short    temp_value;

   *ts_pointer  += inc;
   temp_value    = *ts_pointer & 0x00F0;
   *ts_pointer  &= 0xFF0F;
   *ts_pointer  += (temp_value * 0x10);
   while (ext_drive_pointer [*ts_pointer >> 8] [*ts_pointer & 0xFF] != NULL)
   {
printf( "Point over point (inc_ts_pointer)\n");
      *ts_pointer  += 1;
      temp_value    = *ts_pointer & 0x00F0;
      *ts_pointer  &= 0xFF0F;
      *ts_pointer  += (temp_value * 0x10);
   }

   if ( (*ts_pointer & 0xFF00) >= 0x2300)
      *ts_pointer = 0x0300;

   if ( (*ts_pointer & 0xFF00) == 0x1100)
   {
      printf("Internal error DISK_FULL on ext_disk\n");
      exit( -1);
   }
}

mem_sector_malloc( pointer)
void  * pointer;
{
   void  * malloc();
   short   loop;

   (MEM_SEC *) pointer = (MEM_SEC *) malloc( sizeof (MEM_SEC) );
   if (pointer == NULL)
   {
      printf("Out of memory\n");
      exit( -1);
   }

   ( (MEM_SEC *) pointer)->file_flag = FALSE;
   for (loop = 0;loop < 256;loop ++)
      ( (MEM_SEC *) pointer)->byte [loop] = NULL;

}

file_sector_malloc( pointer)
void  * pointer;
{
   void  * malloc();
   short   loop;

   (FILE_SEC *) pointer = (FILE_SEC *) malloc( sizeof (FILE_SEC) );
   if (pointer == NULL)
   {
      printf("Out of memory\n");
      exit( -1);
   }

   ( (FILE_SEC *) pointer)->file_flag = TRUE;
}

ext_drive_write( track, sector, byte, value)
char  track,
      sector,
      byte,
      value;
{
   if ( ((NONE_SEC *) ext_drive_pointer [track] [sector])->file_flag = TRUE)
   {
      printf("Can't  write to disk yet.\n");
      exit(-1);
   }

   if ( ((NONE_SEC *) ext_drive_pointer [track] [sector])->file_flag = FALSE)
   {
printf("Storing in mem_sector\n");
      ( (MEM_SEC *) ext_drive_pointer [track] [sector])->byte [byte] = value;
   }
}

char ext_drive_read( track, sector, byte)
char  track,
      sector,
      byte;
{
   char   value;

   if ( ((NONE_SEC *) ext_drive_pointer [track] [sector])->file_flag = TRUE)
   {
      printf("Can't  read from disk yet.\n");
      exit(-1);
   }

   if ( ((NONE_SEC *) ext_drive_pointer [track] [sector])->file_flag = FALSE)
   {
printf("Reading in mem_sector\n");
      return ( (MEM_SEC *) ext_drive_pointer [track] [sector])->byte [byte];
   }
}

int disk_open( mode, slot, drive, volume)
short  mode,
       slot,
       drive,
       volume;
{
   char  * opening_mode;

   switch (mode)
   {
      case _READ:    opening_mode = FOPEN_READ_BIN;    break;
      case _WRITE:   opening_mode = FOPEN_WRITE_BIN;   break;
      case _MODIFY:  opening_mode = FOPEN_UPDATE_BIN;  break;
   }

   if (int_drive_pointer != NULL)   /* Some drive is already opened */
   {
      if ( (current_open_mode != mode) || (current_drive != drive) )
      {
         if (current_drive == 0x01)
            fclose( int_drive_pointer);
         else
         {
            short  loop_1;
            short  loop_2;

            for (loop_1 = 0;loop_1 < 35;loop_1 ++)
            {
               loop_2 = 0;

               while (ext_drive_pointer [loop_1][loop_2])
                  free( ext_drive_pointer [loop_1][loop_2++]);

printf("Free %d sectors on track %x\n", loop_2, loop_1);
               free( ext_drive_pointer [loop_1]);
               ext_drive_pointer [loop_1]= NULL;
            }
         }

      }

      else
         return FALSE;    /* It's this one which is open */
   }

   switch (drive)
   {
      case 0x01:
         int_drive_pointer = fopen( "tobbe>apple>apple_disk>boot_disk",
                                                           opening_mode );
         if (int_drive_pointer == NULL)
            return TRUE;

         break;

      case 0x02:     /* init VTOC */
         if (ext_drive_pointer == NULL)
         {
            DIR   * dir_pointer;
            void  * malloc();
            short   byte_pos,
                    filenum_on_sec,
                    curr_sector,        /* Current sector in VTOC.track  */
                    next_tsl,           /* T/S List for one prog on disk */
                    next_aloc_sec,
                    loop;
            char    name_buffer [30];

            for (loop = 0;loop < 35;loop ++)
               ext_drive_pointer [loop][0x00] = NULL;

            ext_drive_pointer [0x11] = (char **) malloc( sizeof (char *) * 16);
            if (ext_drive_pointer [0x11] == NULL)
            {
               printf("Out of memory  (ext_drive_pointer [0x11])\n");
               exit( -1);
            }
                                              /* Track  Sector */
            mem_sector_malloc( ext_drive_pointer [0x11] [0x00]);

                         /* Track  Sector Byte   Value */
            ext_drive_write( 0x11,  0x00,  0x00,  0x04);   /* dummy          */
            ext_drive_write( 0x11,  0x00,  0x01,  0x11);   /* Next :  Track  */
            ext_drive_write( 0x11,  0x00,  0x02,  0x0F);   /*         Sector */
            ext_drive_write( 0x11,  0x00,  0x03,  0x03);   /* Dos rev        */
            ext_drive_write( 0x11,  0x00,  0x06,  0x00);   /* Volume         */
            ext_drive_write( 0x11,  0x00,  0x27,  0x7A);   /* 122 T/S pairs  */
            ext_drive_write( 0x11,  0x00,  0x30,  0x11);   /* Last allocated */
            ext_drive_write( 0x11,  0x00,  0x31,  0x01);   /* Next T + 0x01  */
            ext_drive_write( 0x11,  0x00,  0x34,  0x23);   /* 35 Tracks/Disk */
            ext_drive_write( 0x11,  0x00,  0x35,  0x10);   /* 16 Sectors / T */
            ext_drive_write( 0x11,  0x00,  0x36,  0x00);   /* 0x0100 & 0xFF  */
            ext_drive_write( 0x11,  0x00,  0x37,  0x01);   /* >> 8;  Bytes/S */

            for (byte_pos = 0x0038;byte_pos < 0x00C4;byte_pos += 4)
            {
               ext_drive_write( 0x11, 0x00, byte_pos + 0, 0xFF);
               ext_drive_write( 0x11, 0x00, byte_pos + 1, 0xFF);
               ext_drive_write( 0x11, 0x00, byte_pos + 2, 0x00);
               ext_drive_write( 0x11, 0x00, byte_pos + 3, 0x00);
            }

            if ((dir_pointer = open_dir( WORK_DIR)) == NULL)
            {
               printf("Internal error can't open '%s'\n", WORK_DIR);
               exit( -1);
            }

            curr_sector = 0x0F;
            mem_sector_malloc( ext_drive_pointer [0x11] [curr_sector]);

            ext_drive_write( 0x11, curr_sector, 0x01, 0x11);
            ext_drive_write( 0x11, curr_sector, 0x02, curr_sector - 1);

            filenum_on_sec  = 0;
            next_tsl        = 0x1200;
            while (dir_next_file( name_buffer, dir_pointer) )
            {
               short   file_size,
                       number_of_tslist,
                       curr_num_tslist,
                       pos_in_tslist;
               char    temp_path [256];
               long    file_pos;

               sprintf( temp_path, "%s>%s", WORK_DIR, name_buffer);
               file_size = fsize( temp_path);
               number_of_tslist = file_size /
                                     ext_drive_read( 0x11, 0x00, 0x27) + 1;

               ext_drive_write( 0x11, curr_sector,
                                file_per_sec * 0x23 + 0x0B, next_tsl >> 8);
               ext_drive_write( 0x11, curr_sector,
                                file_per_sec * 0x23 + 0x0C, next_tsl & 0xFF);


               ext_drive_write( 0x11, curr_sector,
                                file_per_sec * 0x23 + 0x0D, 0x10);

               if (fsufix( name_buffer, "TXT") )
                  ext_drive_write( 0x11, curr_sector,
                                file_per_sec * 0x23 + 0x0D, 0x00);

               if (fsufix( name_buffer, "BAS") )
                  ext_drive_write( 0x11, curr_sector,
                                file_per_sec * 0x23 + 0x0D, 0x02);

               if (fsufix( name_buffer, "OBJ") )
                  ext_drive_write( 0x11, curr_sector,
                                file_per_sec * 0x23 + 0x0D, 0x04);

               for (loop = 0;loop < 30;loop ++)
                  ext_drive_write( 0x11, curr_sector,
                                   file_per_sec * 0x23 + 0x0E + loop, ' ');

               for (loop = 0;loop < strlen( name_buffer);loop ++)
                  ext_drive_write( 0x11, curr_sector,
                                   file_per_sec * 0x23 + 0x0E + loop,
                                                   name_buffer [loop] );

               ext_drive_write( 0x11, curr_sector,
                                file_per_sec * 0x23 + 0x2C,
                                     (file_size + 1) & 0xFF );
               ext_drive_write( 0x11, curr_sector,
                                file_per_sec * 0x23 + 0x2D,
                                     (file_size + 1) >>  8 );


               /* Fix the T/S List for the current file */
               mem_sector_malloc( ext_drive_pointer [next_tsl >>   8]
                                                    [next_tsl & 0xFF]);
               next_aloc_sec = next_tsl;
               inc_ts_pointer( &next_aloc_sec, 1);

               file_pos        = 0;
               curr_num_tslist = 1;
               while (curr_num_tslist <= number_of_tslist)
               {
                  FILE   * file_pointer;

                  file_sector_malloc( ext_drive_pointer [next_aloc_sec >>   8]
                                                       [next_aloc_sec  & 0xFF]);

                  file_pointer = fopen( temp_path, opening_mode);
                  if (file_pointer == NULL)
                  {
                     printf("Can't open file '%s' (open_ext_drive)\n",
                                                               temp_path );
                     exit( -1);
                  }

                  pos_in_tslist = 0;
                  while (pos_in_tslist < ext_drive_read( 0x11, 0x00, 0x27) )
                  {
                     ext_drive_write( next_tsl >> 8, next_tsl & 0xFF +
                                                     pos_in_tslist + 0x0C,
                                                     next_aloc_sec >>   8 );
                     ext_drive_write( next_tsl >> 8, next_tsl & 0xFF +
                                                     pos_in_tslist + 0x0D,
                                                     next_aloc_sec & 0xFF );
                     pos_in_tslist += 2;
                     inc_ts_pointer( &next_aloc_sec, 1);


                     ( (FILE_SEC *) ext_drive_pointer)->file_pointer =
                                                                file_pointer;
                     ( (FILE_SEC *) ext_drive_pointer)->index = file_pos;

                     file_pos += 256;

                     file_sector_malloc( ext_drive_pointer [next_aloc_sec >> 8]
                                                       [next_aloc_sec & 0xFF]);

                  }

                  curr_num_tslist ++;



               next_aloc_sec = next_tsl;
               inc_ts_pointer( &next_aloc_sec, 1);






               /* Fix the T/S List for the current file */

               ext_drive_pointer [next_tsl >>   8]
                                 [next_tsl & 0xFF] [0x

               number_of_tslist = 1;
               while (number_of_tslist)
               {
                  if (loop > 1)


                  inc_ts_pointer( &next_tsl,

short  **ext_drive_sectors;


inc_ts_pointer(
   short  alocat_pointer [35][16];


               file_per_sec ++;
               if (file_per_sec >= 8)
               {
                  curr_sector --;

                  inc_ts_pointer( &next_tsl, number_of_tslist);

                  ext_drive_pointer [(curr_sector << 8) | 0x01] = 0x11;
                  ext_drive_pointer [(curr_sector << 8) | 0x02] =
                                                              curr_sector - 1;
                  ext_drive_pointer [(curr_sector << 8) | 0x0B] =
                                                              next_tsl >> 8;
                  ext_drive_pointer [(curr_sector << 8) | 0x0C] =
                                                              next_tsl & 0xFF;

                  file_per_sec = 0;
               }

               if (curr_sector == 0)
               {
                  printf("Internal error To meny Files in ext_dir\n");
                  exit( -1);
               }

            }  /* Until end of dir */

            if (curr_sector != 0)
            {
               ext_drive_pointer [(curr_sector << 8) | 0x01] = 0x11;
               ext_drive_pointer [(curr_sector << 8) | 0x02] = curr_sector - 1;
            }

         }  /* End of   VTOC init  */
         break;

      default:
         printf("Can't find the drive %d  (open)\n", drive);
         exit( -1);

   }

   current_drive     = drive;
   current_open_mode = mode;
   return FALSE;
}

disk_seek( track, sector, relative_pos)
short  track,
       sector,
       relative_pos;
{
   long    position;

   if (int_drive_pointer == NULL)
   {
      printf("You haven't open the drive yet!\n");
      exit (-1);
   }

   switch (current_drive)
   {
      case 0x01:
         position = track * 0x1040 + sector * 0x104 + relative_pos;
         fseek( int_drive_pointer, (long) position, 0);
         break;

      case 0x02:
         ext_drive_info.track  = track;
         ext_drive_info.sector = sector;
         ext_drive_info.byte   = relative_pos;
         break;

      default:
         printf("Internal error in seek\n");
         exit( -1);
   }

}

disk_read( buffer, length)
char   buffer [];
short  length;
{
   if (int_drive_pointer == NULL)
   {
      printf("You haven't open the drive yet!\n");
      exit (-1);
   }

   switch (current_drive)
   {
      case 0x01:
         fread( buffer, sizeof (char), length, int_drive_pointer);
         break;

      case 0x02:
         if (ext_drive_info.track == 0x11)
         {
            buffer [0] = ext_drive_info.volume;
            buffer [1] = ext_drive_info.track;
            buffer [2] = ext_drive_info.sector;
            buffer [3] = 0x55;   /* Dummy */

            memcpy( buffer + 4,
                    &ext_drive_pointer [(ext_drive_info.sector << 8) |
                                                    ext_drive_info.byte],
                                                                   length );
            break;
         }

printf("track %x   sector %x  byte %x\n", ext_drive_info.track,
                                          ext_drive_info.sector,
                                          ext_drive_info.byte);
break;
         fread( &sector_info, sizeof (sector_info), 1, int_drive_pointer);
         if (sector_info.in_use)
         {
            FILE   * file_pointer;
            char     temp_path [256];

            sprintf( temp_path, "%s>%s", WORK_DIR, sector_info.file_name);
            file_pointer = fopen( temp_path, "i");
            if (file_pointer == NULL)
            {
               printf("Iternal error in read from file '%s'\n", temp_path);
               exit( -1);
            }

            fread( buffer, sizeof (char), length, file_pointer);
            fclose( file_pointer);
         }

         else
         {
            short loop;

            for (loop = 0;loop < length;loop ++)
               buffer [loop] = '\0';
         }
         break;

      default:
         printf("Internal error in read\n");
         exit( -1);


   }
}

disk_write( buffer, length)
char   buffer [];
short  length;
{
   if (int_drive_pointer == NULL)
   {
      printf("You haven't open the drive yet!\n");
      exit (-1);
   }

   if (current_drive == 0x01)
      return fwrite( buffer, sizeof (char), length, int_drive_pointer);

   if (current_drive == 0x02)
   {
      FILE   * file_pointer;
      char     temp_path [256];

printf("Not istall yet\n");
exit(-1);
      fread( &sector_info, sizeof (sector_info), 1, int_drive_pointer);
      if (!sector_info.in_use)
      {
         sector_info.in_use = TRUE;
         sprintf( sector_info.file_name, "sector%02x%02x", sector_info.track,
                                                           sector_info.sector);
         sector_info.position = 0;
         disk_open( _WRITE, current_slot, 0x02, current_volume);
         disk_seek( sector_info.track, sector_info.sector,
                                       sector_info.position);
         fwrite( &sector_info, sizeof (sector_info), 1, int_drive_pointer);
      }

      sprintf( temp_path, "%s>%s", WORK_DIR, sector_info.file_name);
      file_pointer = fopen( temp_path, "o");
      if (file_pointer == NULL)
      {
         printf("Internal error in write, can't read from file '%s'\n",
                                                  sector_info.file_name );
         exit( -1);
      }

      fwrite( buffer, sizeof (char), length, file_pointer);
      fclose( file_pointer);

      return;
   }

   printf("Internal error in write, can't found the drive %d\n",
                                                   current_drive  );
   exit( -1);
}

disk_close()
{
   if (int_drive_pointer == NULL)
   {
      printf("You haven't open the drive yet!\n");
      exit (-1);
   }

/*
put on waiting
   fclose( int_drive_pointer);
   int_drive_pointer = NULL;
*/
}

format_ext_drive( slot)
short  slot;
{
   short  track,
          sector;

   disk_open( _WRITE, slot, 0x02, 0x00);
   for (track = 0;track < 35;track ++)
   {
      for (sector = 0;sector < 16;sector ++)
      {
         sector_info.in_use       = FALSE;
         sector_info.track        = track;
         sector_info.sector       = sector;
         (*sector_info.file_name) = '\0';
         sector_info.position     = 0;
printf("init\n");
/*         fwrite( &sector_info, sizeof (sector_info), 1, int_drive_pointer);*/
      }
   }

}



