package de.ivu.elect.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * Die gespeicherten Bytes können <i>copyless</i> weiterverwendet werden.
 * <p/>
 * NOTE, dass beim Schreiben in diesen Stream dennoch Kopieroperationen auftreten (können)!
 */
public class CopylessByteArrayOutputStream extends ByteArrayOutputStream {

  private boolean closed = false;

  public CopylessByteArrayOutputStream() {
  }

  public CopylessByteArrayOutputStream(int sizeInBytes) {
    super(sizeInBytes);
  }

  /**
   * Erlaubt es, den Stream copyless in einen InputStream umzuwandeln.
   */
  public synchronized InputStream toInputStreamAndClose() throws IOException {
    close();

    // NOTE, dass der Puffer größer sein kann als der tatsächliche Inhalt
    return new ByteArrayInputStream(buf, 0, count);
  }

  /**
   * Ein geschlossener Stream kann weiterhin gelesen werden (<code>writeTo</code>, <code>toByteArray</code>,
   * <code>toInputStreamAndClose</code>), jedoch nicht verändert (<code>write</code>, <code>reset</code>).
   * <p/>
   * Grund: der interne Puffer kann von anderen Klassen weiterverwendet werden und ist deshalb ab einem bestimmten
   * Punkt nicht mehr zu verändern.
   *
   * @throws IOException
   */
  @Override
  public synchronized void close() throws IOException {
    if (!closed) {
      super.close();
      closed = true;
    }
  }

  protected void assertOpen() {
    if (closed) {
      throw new IllegalStateException("Der Stream wurde bereits geschlossen!");
    }
  }

  @Override
  public synchronized void write(int b) {
    assertOpen();
    super.write(b);
  }

  @Override
  public synchronized void write(byte[] b, int off, int len) {
    assertOpen();
    super.write(b, off, len);
  }

  @Override
  public synchronized void reset() {
    assertOpen();
    super.reset();
  }
}
