/*
    CaPriCe Forever - Amstrad CPC 464/664/6128 emulator
    Copyright (C) 2015-2019 by Frédéric Coste

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/


#include "..\Native_CPC.h"


/*
** Make sure we can call this stuff from C++.
*/
#ifdef __cplusplus
extern "C" {
#endif


//===================
// PATCH begin
#ifdef _PATCH_ENABLE

#endif /* _PATCH_ENABLE */
// PATCH end
//===================


#define FILE_ENTRY_SIZE                32


extern tULong AMSDOS_GetFirstSectorOfBlock(tDiskOperation* DiskOperation, tULong Block);
extern tULong AMSDOS_GetNextSector(tDiskOperation* DiskOperation, tULong CHRN);


tULong AMSDOS_DiskGetNextSector(tDiskOperation* DiskOperation)
/***********************************************************************
 *
 *  AMSDOS_DiskGetNextSector
 *
 ***********************************************************************/
{
tTrack* actualTrackP;
tSector* sectorP;
tULong indexSector;
tULong loopSector;
tULong loopEntry;
tULong loopBlock;
tULong loopChar;
tULong CHRN;
tUChar EntryIndex;
tBool  ReturnNextSector;

  actualTrackP = &DiskOperation->Drive->track[DiskOperation->CatalogueTrack][0]; // Side = 0

  CHRN = 0L;
  EntryIndex = 0;
  ReturnNextSector = cFalse;

  do
  {
    // Only find file entries into four first sectors.
    indexSector = 1; // Begin to find the first sector
		while ( (indexSector <= 4) && (CHRN == 0L) )
    {
      tULong nbofentries;
      tUChar* fileEntryP;

      //
      // Find sector
      //
      sectorP = 0;
      for (loopSector=0; loopSector < actualTrackP->sectors; loopSector++)
      {
        if ( ((actualTrackP->sector[loopSector].CHRN[SECTOR_CHRN_R] & 0x0FU) == indexSector)
             && (actualTrackP->sector[loopSector].CHRN[SECTOR_CHRN_N] == 2) )
        {
          sectorP = &actualTrackP->sector[loopSector];
          break;
        }
      }

  	  // Do not take into account empty or missing sector
  	  if (!sectorP || (!sectorP->size) )
  	  {
  		  // Next sector
  		  indexSector++;
  	 	  continue;
  	  }

      // Prepare sector read
      nbofentries = sectorP->declared_size / FILE_ENTRY_SIZE; // 32 bytes per file entry
  	  fileEntryP = sectorP->data; // Point at beginning of sector.

      // For all entries
      for (loopEntry=0;
           (loopEntry < nbofentries) && (CHRN == 0L);
					 loopEntry++, fileEntryP += FILE_ENTRY_SIZE)
      {
        tUChar* bytePtr;
        tUChar* fileStoredEntryP;

        //
        // Parse File Entry
        //
        // Entry documentation
        // ===================
        // Byte 0x0 = USER; 229(0xe5) for deleted files, 0 by default.
        // Byte 0x1 to 0x8 = filename
        // Byte 0x9 to 0xb = extension. Byte 0x9 bit7 = 1 = Read Only. Byte 0xa bit7 = 1 = Hidden.
        // Byte 0xc = entry index (First entry = 0)
        // Byte 0xd to 0xe = Not used ??
        // Byte 0xf = size in records (1 record=128 bytes). 0x80 for full entry => check another entry
        // Byte 0x10 to 0x1f = list of numbers of 1k blocks (2 sectors length).

				// How to locate a block
        // =====================
        // Cylinder (C) = INT(block * 2 / 9); 9 sectors per track !! For EXTENDED, check number of sectors per Tracks
        // Head     (H) = Always 0
        // Sector   (R) = (block * 2) MODULO 9 + 1 + TYPE (0xC0 for DATA, 0x40 for VENDOR)
        // Size     (N) = Size (*256 bytes)

        // Entry size is non null
        if (!fileEntryP[0xf])
          continue;

    	  // Compare filename and extension
  	    fileStoredEntryP = DiskOperation->CatalogueEntries[DiskOperation->CatalogueEntryIndex];
    	  bytePtr = &fileEntryP[0x1]; // Point at the beginning of the filename.
    	  for (loopChar=0; loopChar < 11; loopChar++)
    	  {
    		  if ((*bytePtr++ & 0x7f) != *fileStoredEntryP++)
    		    break;
        }
        // Not Matching filename ?
        if (loopChar < 11)
          continue;

        // Not matching USER ?
        if (fileEntryP[0x0] != DiskOperation->CatalogueEntryUser[DiskOperation->CatalogueEntryIndex])
          continue;

        // Not matching entry index ?
        if (fileEntryP[0xc] != EntryIndex)
          continue;

        // For all blocks
        for (loopBlock=0; (loopBlock < 16) && (CHRN == 0L); loopBlock++)
        {
					tULong FirstCHRN;
          tULong SecondCHRN;
          tUChar Block;

          Block = fileEntryP[0x10 + loopBlock];
          // End of entry ?
          if (!Block)
          {
            ReturnNextSector = cFalse;
            break;
          }

          FirstCHRN = AMSDOS_GetFirstSectorOfBlock(DiskOperation, Block);
          SecondCHRN = AMSDOS_GetNextSector(DiskOperation, FirstCHRN);

          // Return Next sector ?
          if (ReturnNextSector == cTrue)
          {
						CHRN = FirstCHRN;
            ReturnNextSector = cFalse;
          }
          // First CHRN matching ?
          else if (FirstCHRN == DiskOperation->CatalogueLastCHRN)
          {
            CHRN = SecondCHRN;
          }
          // Second CHRN matching ?
          else if (SecondCHRN == DiskOperation->CatalogueLastCHRN)
          {
            // Another entry ?
            if ( (loopBlock == 15) && (fileEntryP[0xf] == 0x80) )
            {
              ReturnNextSector = cTrue;
            }
            else if (loopBlock < 15)
            {
							ReturnNextSector = cTrue;
						}
					}
					else
					{
						// continue with next block.
					}
				}

				// Next entry ?
				if ( (loopBlock == 16) && (fileEntryP[0xf] == 0x80) )
				{
					EntryIndex++;
				}
			}

			indexSector++; // Next sector
		}
	}
	while ( (ReturnNextSector == cTrue) && (indexSector <= 4) );

  DiskOperation->CatalogueLastCHRN = CHRN;

  return CHRN;
}
/*----------------------------------------------------------------------------*/


#ifdef __cplusplus
}  /* End of the 'extern "C"' block */
#endif
