#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <zlib.h>

#include "crypto.h"

#define CHUNK_BLOCK 		(16384)

/* Compress from file source to file dest until EOF on source.
   def() returns Z_OK on success, Z_MEM_ERROR if memory could not be
   allocated for processing, Z_STREAM_ERROR if an invalid compression
   level is supplied, Z_VERSION_ERROR if the version of zlib.h and the
   version of the library linked do not match, or Z_ERRNO if there is
   an error reading or writing the files. */
int GZipFileCompress(const char* pInput, const char* pOutput)
{
    int ret, isFlush;
    unsigned int have;
    z_stream strm;
    char    strPath[256];
    unsigned char in[CHUNK_BLOCK];
    unsigned char out[CHUNK_BLOCK];
    FILE *source, *dest;
    
    if (pInput == NULL)
    {
        return (Z_ERRNO);
    }

    if(access(pInput, F_OK) != 0)
    {
        return (Z_ERRNO);
    }

    //fprintf(stdout, "in: %s\n", pInput);
    
    source = fopen(pInput, "r+");

    memset(strPath, 0, 256);
    if (pOutput == NULL || strlen(pOutput) == 0)
    {
        sprintf(strPath, "%s.gz", pInput);
        dest = fopen(strPath, "w+");

        //fprintf(stdout, "out: %s\n", strPath);
    }
    else
    {
        dest = fopen(pOutput, "w+");
        //fprintf(stdout, "out: %s\n", pOutput);
    }

    /* allocate deflate state */
    strm.zalloc = Z_NULL;
    strm.zfree = Z_NULL;
    strm.opaque = Z_NULL;
    //ret = deflateInit(&strm, level);
	ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS + 16, 8,  Z_DEFAULT_STRATEGY);

    if (ret != Z_OK)
    {
        fclose(source);
        fclose(dest);
        return ret;
    }

    /* compress until end of file */
    do {
        strm.avail_in = fread(in, 1, CHUNK_BLOCK, source);
        if (ferror(source)) {
            (void)deflateEnd(&strm);
            fclose(source);
            fclose(dest);
            return Z_ERRNO;
        }
        isFlush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
        strm.next_in = in;

        /* run deflate() on input until output buffer not full, finish
           compression if all of source has been read in */
        do {
            strm.avail_out = CHUNK_BLOCK;
            strm.next_out = out;
            ret = deflate(&strm, isFlush);    /* no bad return value */
            have = CHUNK_BLOCK - strm.avail_out;
            if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
                (void)deflateEnd(&strm);
                fclose(source);
                fclose(dest);
                return Z_ERRNO;
            }
        } while (strm.avail_out == 0);
        
        /* done when last data in file processed */
    } while (isFlush != Z_FINISH);

    /* clean up and return */
    (void)deflateEnd(&strm);

    fflush(dest);

    fclose(source);
    fclose(dest);
    return Z_OK;
}

