package com.bytezone.diskbrowser.prodos;

import java.util.ArrayList;
import java.util.List;

import com.bytezone.diskbrowser.applefile.ProdosDirectory;
import com.bytezone.diskbrowser.disk.DiskAddress;
import com.bytezone.diskbrowser.gui.DataSource;
import com.bytezone.diskbrowser.utilities.Utility;

// -----------------------------------------------------------------------------------//
public class VolumeDirectoryHeader extends DirectoryHeader
// -----------------------------------------------------------------------------------//
{
  protected final int bitMapBlock;
  protected int totalBlocks;
  protected int freeBlocks;
  protected int usedBlocks;
  protected int totalBitMapBlocks;

  // ---------------------------------------------------------------------------------//
  VolumeDirectoryHeader (ProdosDisk parentDisk, byte[] entryBuffer)
  // ---------------------------------------------------------------------------------//
  {
    super (parentDisk, entryBuffer, 2, 1);

    bitMapBlock = Utility.getShort (entryBuffer, 35);
    totalBlocks = Utility.getShort (entryBuffer, 37);

    totalBitMapBlocks = (totalBlocks - 1) / BLOCK_SIZE + 1;

    int block = 2;
    do
    {
      dataBlocks.add (disk.getDiskAddress (block));
      byte[] buffer = disk.readBlock (block);
      block = Utility.getShort (buffer, 2);
    } while (block > 0);

    // convert the Free Sector Table
    int bitMapBytes = (totalBlocks - 1) / 8 + 1;                  // one bit per block
    byte[] buffer = new byte[bitMapBytes];
    int bitMapBlocks = (bitMapBytes - 1) / disk.getBlocksPerTrack () + 1;
    int lastBitMapBlock = bitMapBlock + bitMapBlocks - 1;
    int ptr = 0;

    for (block = bitMapBlock; block <= lastBitMapBlock; block++)
    {
      byte[] temp = disk.readBlock (block);
      int bytesToCopy = buffer.length - ptr;
      if (bytesToCopy > temp.length)
        bytesToCopy = temp.length;
      System.arraycopy (temp, 0, buffer, ptr, bytesToCopy);
      ptr += bytesToCopy;
    }

    // nb1 dual-dos disk needs to use totalBlocks obtained from disk
    // int max1 = (totalBlocks - 1) / 8 + 1;             // bytes required for sector map
    // nb2 hard disk may be truncated, so use actual number of blocks
    // int max2 = (disk.getTotalBlocks () - 1) / 8 + 1;  // bytes required for sector map

    int max = (Math.min (totalBlocks, disk.getTotalBlocks ()) - 1) / 8 + 1;
    block = 0;

    for (int i = 0; i < max; i++)
    {
      byte b = buffer[i];
      for (int j = 0; j < 8; j++)
      {
        boolean free = (b & 0x80) != 0;
        if (free)
          freeBlocks++;
        parentDisk.setSectorFree (block++, free);
        b <<= 1;
      }
    }
    usedBlocks = totalBlocks - freeBlocks;    // totalBlocks may not be a multiple of 8
  }

  // ---------------------------------------------------------------------------------//
  @Override
  public DataSource getDataSource ()
  // ---------------------------------------------------------------------------------//
  {
    List<byte[]> blockList = new ArrayList<> ();
    int block = 2;
    do
    {
      byte[] buf = disk.readBlock (block);
      blockList.add (buf);
      block = Utility.getShort (buf, 2);              // next block
    } while (block > 0);

    byte[] fullBuffer = new byte[blockList.size () * 507];
    int offset = 0;
    for (byte[] bfr : blockList)
    {
      System.arraycopy (bfr, 4, fullBuffer, offset, 507);
      offset += 507;
    }

    return new ProdosDirectory (parentDisk, name, fullBuffer, totalBlocks, freeBlocks,
        usedBlocks);
  }

  // ---------------------------------------------------------------------------------//
  @Override
  public List<DiskAddress> getSectors ()
  // ---------------------------------------------------------------------------------//
  {
    List<DiskAddress> sectors = new ArrayList<> ();
    sectors.addAll (dataBlocks);
    return sectors;
  }

  // ---------------------------------------------------------------------------------//
  @Override
  public String getText ()
  // ---------------------------------------------------------------------------------//
  {
    return String.format ("%s  %04X %02X", super.getText (), totalBlocks, bitMapBlock);
  }

  // ---------------------------------------------------------------------------------//
  @Override
  public String toString ()
  // ---------------------------------------------------------------------------------//
  {
    if (false)
    {
      String locked = (access == 0x01) ? "*" : " ";
      String timeC = created == null ? "" : created.format (ProdosDisk.df);
      return String.format ("   %s%-42s %15s", locked, "/" + name, timeC);
    }
    return name;
  }
}