package de.ivu.elect.util;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class CountingZipOutputStream extends ZipOutputStream {

  private final AtomicLong byteCount = new AtomicLong(0L);

  private final AtomicLong fileCount = new AtomicLong(0L);

  private final AtomicBoolean lock = new AtomicBoolean(false);

  public CountingZipOutputStream(OutputStream out) {
    super(out);
  }

  public CountingZipOutputStream(OutputStream out, Charset charset) {
    super(out, charset);
  }

  @Override
  public void putNextEntry(ZipEntry e) throws IOException {
    try {
      lock.set(true);
      super.putNextEntry(e);
      fileCount.addAndGet(1);
    } finally {
      lock.set(false);
    }
  }



  private void addContent(long len2) {
    byteCount.addAndGet(len2);
  }

  public long getByteCount() {
    return byteCount.get();
  }

  public long getFileCount() {
    return fileCount.get();
  }

  @Override
  public synchronized void write(byte[] b, int off, int len) throws IOException {
    try {
      boolean previous = lock.getAndSet(true);
      super.write(b, off, len);
      if (!previous) {
        addContent(len);
      }
    } finally {
      lock.set(false);
    }
  }
  @Override
  public void write(int b) throws IOException {
    try {
      boolean previous = lock.getAndSet(true);
      super.write(b);
      if (!previous) {
        addContent(1L);
      }
    } finally {
      lock.set(false);
    }
  }

  @Override
  public void write(byte[] b) throws IOException {
    try {
      boolean previuos = lock.getAndSet(true);
      super.write(b);
      if (!previuos){
        addContent(b.length);
      }
    } finally {
      lock.set(false);
    }
  }

  @Override
  public void closeEntry() throws IOException {
    try {
      lock.set(true);
      super.closeEntry();
    } finally {
      lock.set(false);
    }
  }

  @Override
  public void finish() throws IOException {
    try {
      lock.set(true);
      super.finish();
    } finally {
      lock.set(false);
    }
  }

  @Override
  public void close() throws IOException {
    try {
      lock.set(true);
      super.close();
    } finally {
      lock.set(false);
    }
  }
}
