/* UtilLib - Copyright (c) 2020 Vincent Calame - Exemole
 * Logiciel libre donné sous triple licence :
 * 1) selon les termes de la CeCILL V2
 * 2) selon les termes de l’EUPL V.1.1
 * 3) selon les termes de la GNU GPLv3
 * Voir le fichier licences.txt
 *
 * From : https://github.com/plantuml/plantuml/blob/master/src/net/sourceforge/plantuml/code/CompressionZlib.java
 */


package net.mapeadores.util.uml;

import java.io.IOException;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;


/**
 *
 * @author Vincent Calame
 */
public class CompressionZlib {

    private static final int COMPRESSION_LEVEL = 9;

    public byte[] compress(byte[] in) {
        if (in.length == 0) {
            return null;
        }
        int len = in.length * 2;
        if (len < 1000) {
            len = 1000;
        }
        return tryCompress(in, len);
    }

    private byte[] tryCompress(byte[] in, final int len) {
        // Compress the bytes
        final Deflater compresser = new Deflater(COMPRESSION_LEVEL, true);
        compresser.setInput(in);
        compresser.finish();

        final byte[] output = new byte[len];
        final int compressedDataLength = compresser.deflate(output);
        if (compresser.finished() == false) {
            return null;
        }
        final byte[] result = copyArray(output, compressedDataLength);
        return result;
    }

    public byte[] decompress(byte[] in) throws IOException {
        final byte in2[] = new byte[in.length + 256];
        System.arraycopy(in, 0, in2, 0, in.length);
        int len = 100000;
        byte[] result = null;
        result = tryDecompress(in2, len);
        if (result == null) {
            throw new IOException("Too big?");

        }
        return result;

    }

    private byte[] tryDecompress(byte[] in, final int len) throws IOException {
        if (len > 200000) {
            throw new IOException("OutOfMemory");
        }
        // Decompress the bytes
        final byte[] tmp = new byte[len];
        final Inflater decompresser = new Inflater(true);
        decompresser.setInput(in);
        try {
            final int resultLength = decompresser.inflate(tmp);
            if (decompresser.finished() == false) {
                return null;
            }
            decompresser.end();

            final byte[] result = copyArray(tmp, resultLength);
            return result;
        } catch (DataFormatException e) {
            throw new IOException(e.toString());
        }
    }

    private byte[] copyArray(final byte[] data, final int len) {
        final byte[] result = new byte[len];
        System.arraycopy(data, 0, result, 0, len);
        return result;
    }

}
