package ar.com.hjg.pngj.pixels;

import java.util.zip.Deflater;

import ar.com.hjg.pngj.IDatChunkWriter;
import ar.com.hjg.pngj.PngjOutputException;

/**
 * This class uses a quick compressor to get a rough estimate of deflate
 * compression ratio.
 *
 * This just ignores the outputStream, and the deflater related parameters
 */
public class CompressorStreamLz4 extends CompressorStream {

	private final DeflaterEstimatorLz4 lz4;

	private byte[] buf; // lazily allocated, only if needed
	private final int buffer_size;
	// bufpos=bytes in buffer yet not compressed (bytesIn include this)
	private int inbuf = 0;

	private static final int MAX_BUFFER_SIZE = 16000;

	public CompressorStreamLz4(final IDatChunkWriter os, final int maxBlockLen, final long totalLen) {
		super(os, maxBlockLen, totalLen);
		lz4 = new DeflaterEstimatorLz4();
		buffer_size = (int) (totalLen > CompressorStreamLz4.MAX_BUFFER_SIZE ? CompressorStreamLz4.MAX_BUFFER_SIZE : totalLen);
	}

	public CompressorStreamLz4(final IDatChunkWriter os, final int maxBlockLen, final long totalLen, final Deflater def) {
		this(os, maxBlockLen, totalLen);// edlfater ignored
	}

	public CompressorStreamLz4(final IDatChunkWriter os, final int maxBlockLen, final long totalLen, final int deflaterCompLevel, final int deflaterStrategy) {
		this(os, maxBlockLen, totalLen); // paramters ignored
	}

	@Override
	public void mywrite(final byte[] b, int off, int len) {
		if (len == 0)
			return;
		if (done || closed)
			throw new PngjOutputException("write beyond end of stream");
		bytesIn += len;
		while (len > 0)
			if (inbuf == 0 && (len >= CompressorStreamLz4.MAX_BUFFER_SIZE || bytesIn == totalbytes)) {
				// direct copy (buffer might be null or empty)
				bytesOut += lz4.compressEstim(b, off, len);
				len = 0;
			} else {
				if (buf == null)
					buf = new byte[buffer_size];
				final int len1 = inbuf + len <= buffer_size ? len : buffer_size - inbuf; // to copy
				if (len1 > 0)
					System.arraycopy(b, off, buf, inbuf, len1);
				inbuf += len1;
				len -= len1;
				off += len1;
				if (inbuf == buffer_size)
					compressFromBuffer();
			}
	}

	void compressFromBuffer() {
		if (inbuf > 0) {
			bytesOut += lz4.compressEstim(buf, 0, inbuf);
			inbuf = 0;
		}
	}

	@Override
	public void done() {
		if (!done) {
			compressFromBuffer();
			done = true;
		}
	}

	@Override
	public void close() {
		done();
		if (!closed) {
			super.close();
			buf = null;
		}
	}

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

}
