var compress_buffer_crc32 = require("compress-buffer-crc32");

var Compressor = function (configuration) {
    this._configuration = configuration;
};

Compressor.prototype._getCompressionRate = function(unCompressed, compressed){
    var unCompressedLength = unCompressed ? unCompressed.length : 0;
    var compressedLength = compressed ? compressed.length : 0;

    return {
        times: Math.round(unCompressedLength/compressedLength),
        percentage: Math.round((100-(100*(compressedLength/unCompressedLength)))),
        compressedLength: compressedLength,
        unCompressedLength: unCompressedLength
    };
};

Compressor.prototype.compress = function (data, callback, compressLevel) {
    compressLevel = compressLevel || 6;
    var compressedData = compress_buffer_crc32.compress(data, compressLevel);
    callback(
        compressedData,
        this._getCompressionRate(data, compressedData)
    );
};

Compressor.prototype.uncompress = function (data, callback) {
    var compressedData = compress_buffer_crc32.uncompress(data);
    callback(
        compressedData,
        this._getCompressionRate(compressedData, data)
    );
};

Compressor.prototype.compressBlock = function (data, callback, compressLevel) {
    compressLevel = compressLevel || 6;
    var compressedData = compress_buffer_crc32.compress(data, compressLevel);
    callback(
        compressedData,
        this._getCompressionRate(data, compressedData)
    );
};

Compressor.prototype.uncompressBlock = function (data, callback) {
    var compressedData = compress_buffer_crc32.uncompress(data);
    callback(
        compressedData,
        this._getCompressionRate(compressedData, data)
    );
};

Compressor.prototype.compressBlockSync = function (data, compressLevel) {
    return compress_buffer_crc32.metaCompress(data, compressLevel);
};

Compressor.prototype.uncompressBlockSync = function (data) {
    return compress_buffer_crc32.uncompress(data);
};

Compressor.prototype.combineBlocksSync = function (blocks) {
    var crc = compress_buffer_crc32.getCrc(blocks);
    var estimatedLength = compress_buffer_crc32.estimate(blocks);
    var position = 0;

    var response = new Buffer(estimatedLength);
    compress_buffer_crc32.buffers.header.copy(response, position);
    position += compress_buffer_crc32.buffers.header.length;

    for (var i = 0, l = blocks.length; i < l; i++) {
        var stream = blocks[i];
        var last = stream.body[stream.meta.offsets.right];
        var lastStream = (i + 1) == l;

        //tmpBuf to referencja, nie powinno sie na nim wykonywac zadnych operacji
        tmpBuf = stream.body.slice(stream.meta.offsets.left, stream.meta.offsets.right);
        tmpBuf.copy(response, position);

        if (!lastStream) {
            response[position + stream.meta.offsets.lastBlock] &= ~stream.meta.lastValue;
        }

        position += tmpBuf.length;

        if (lastStream) {
            response[position] = last;
            position++;
        } else {
            stream.boundary.copy(response, position);
            position += stream.boundary.length;
        }
    }
    crc.crc.copy(response, position);
    position += crc.crc.length;

    crc.length.copy(response, position);
    position += crc.length.length;

    console.info("Compressor: estimated: %d, total: %d", estimatedLength, position, crc);
    return response.slice(0, position);
};

Compressor.META = {};
Compressor.META.HEADER = new Buffer([0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03], "binary");
Compressor.META.FOOTER = new Buffer([0x03, 0x00], "binary");
Compressor.META.BLOCK_HEADER_SIZE = 5;

exports.Compressor = Compressor;
