package btools.util;

public final class ByteArrayUnifier implements IByteArrayUnifier
{
  private byte[][] byteArrayCache;
  private int[] crcCrosscheck;
  private int size;

  public ByteArrayUnifier( int size, boolean validateImmutability )
  {
    this.size = size;
    byteArrayCache = new byte[size][];
    if ( validateImmutability ) crcCrosscheck = new int[size];
  }

  /**
   * Unify a byte array in order to reuse instances when possible.
   * The byte arrays are assumed to be treated as immutable,
   * allowing the reuse
   * @param ab  the byte array to unify
   * @return the cached instance or the input instanced if not cached
   */
  public byte[] unify( byte[] ab )
  {
    return unify( ab, 0, ab.length );
  }

  public byte[] unify( byte[] ab, int offset, int len )
  {
    int crc = Crc32.crc( ab, offset, len );
    int idx = ( crc & 0xfffffff ) % size;
    byte[] abc = byteArrayCache[idx];
    if ( abc != null && abc.length == len )
    {
      int i = 0;
      while (i < len)
      {
        if ( ab[offset + i] != abc[i] )
          break;
        i++;
      }
      if ( i == len )
        return abc;
    }
    if ( crcCrosscheck != null )
    {
      if ( byteArrayCache[idx] != null )
      {
        byte[] abold = byteArrayCache[idx];
        int crcold = Crc32.crc( abold, 0, abold.length );
        if ( crcold != crcCrosscheck[idx] )
          throw new IllegalArgumentException( "ByteArrayUnifier: immutablity validation failed!" );
      }
      crcCrosscheck[idx] = crc;
    }
    byte[] nab = new byte[len];
    System.arraycopy( ab, offset, nab, 0, len );
    byteArrayCache[idx] = nab;
    return nab;
  }
}
