package com.bytezone.diskbrowser.utilities;

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

class LZW
{
  static protected final String[] st = new String[0x1000];
  static protected final int TRACK_LENGTH = 0x1000;

  protected final List<byte[]> chunks = new ArrayList<byte[]> ();
  protected int volume;
  protected byte runLengthChar;
  protected int crc;
  protected int crcBase;

  private int buffer;            // one character buffer
  private int bitsLeft;          // unused bits left in buffer

  private int ptr;
  private int startPtr;
  protected byte[] bytes;

  static
  {
    for (int i = 0; i < 256; i++)
      st[i] = "" + (char) i;
  }

  public void setBuffer (byte[] buffer, int ptr)
  {
    bytes = buffer;
    startPtr = this.ptr = ptr;
    bitsLeft = 0;
  }

  public int bytesRead ()
  {
    return ptr - startPtr;
  }

  private void fillBuffer ()
  {
    buffer = bytes[ptr++] & 0xFF;
    bitsLeft = 8;
  }

  private boolean readBoolean ()
  {
    if (bitsLeft == 0)
      fillBuffer ();

    bitsLeft--;
    boolean bit = ((buffer << bitsLeft) & 0x80) == 0x80;
    return bit;
  }

  int readInt (int width)
  {
    if (width < 8 || width > 12)
      throw new RuntimeException ("Illegal value of r = " + width);

    int x = 0;
    for (int i = 0, weight = 1; i < width; i++, weight <<= 1)
      if (readBoolean ())
        x |= weight;

    return x;
  }

  byte[] undoRLE (byte[] inBuffer, int inPtr, int length)
  {
    byte[] outBuffer = new byte[TRACK_LENGTH];
    int outPtr = 0;
    int max = inPtr + length;

    while (inPtr < max)
    {
      byte b = inBuffer[inPtr++];
      if (b == runLengthChar)
      {
        b = inBuffer[inPtr++];
        int rpt = inBuffer[inPtr++] & 0xFF;
        while (rpt-- >= 0)
          outBuffer[outPtr++] = b;
      }
      else
        outBuffer[outPtr++] = b;
    }

    assert outPtr == TRACK_LENGTH;
    return outBuffer;
  }

  public byte[] getData ()
  {
    byte[] buffer = new byte[chunks.size () * TRACK_LENGTH];
    int trackNumber = 0;

    for (byte[] track : chunks)
      System.arraycopy (track, 0, buffer, trackNumber++ * TRACK_LENGTH, TRACK_LENGTH);

    if (crc != NuFX.getCRC (buffer, crcBase))
      System.out.println ("\n*** LZW CRC mismatch ***");

    return buffer;
  }

  protected int width (int maximumValue)
  {
    return 32 - Integer.numberOfLeadingZeros (maximumValue);
  }
}