#ifndef ZDEFLATE_H
#define ZDEFLATE_H

#include "cryptlib.h"
#include "misc.h"
#include "filters.h"
#include "ztrees.h"

class Deflator : public Filter, private CodeTree
{
public:
    // deflate_level can be from 1 to 9, 1 being fastest, 9 being most compression
    // default for the gzip program is 6
    Deflator(int deflate_level, BufferedTransformation *outQ = NULL);

    void Put(byte inByte)
        {Deflator::Put(&inByte, 1);}
    void Put(const byte *inString, unsigned int length);

    void InputFinished();

private:
#ifdef SMALL_MEM
    enum {HASH_BITS=13};
#else
#  ifdef MEDIUM_MEM
    enum {HASH_BITS=14};
#  else
    enum {HASH_BITS=15};
#  endif
#endif

    enum {HASH_SIZE = 1<<HASH_BITS, HASH_MASK = HASH_SIZE-1,
          WINDOW_SIZE = 2*WSIZE, WMASK = WSIZE-1,
          NIL = 0,  // Tail of hash chains
          // Matches of length 3 are discarded if their distance exceeds TOO_FAR
          TOO_FAR = 4096};

    struct config
    {
       word16 good_length; /* reduce lazy search above this match length */
       word16 max_lazy;    /* do not perform lazy search above this match length */
       word16 nice_length; /* quit search above this match length */
       word16 max_chain;
    };

    static const config configuration_table[10];

    typedef word16 Pos;
    typedef unsigned IPos;

    SecByteBlock window;
    SecBlock<Pos> prev, head;

    unsigned fill_window (const byte*, unsigned);
    void     init_hash   ();

    int longest_match (IPos cur_match);

    int fast_deflate(const byte *buffer, unsigned int length);
    int lazy_deflate(const byte *buffer, unsigned int length);

    unsigned ins_h;  /* hash index of string to be inserted */
    char uptodate;   /* hash preparation flag */

    unsigned int prev_length;
    /* Length of the best match at previous step. Matches not greater than this
     * are discarded. This is used in the lazy match evaluation. */

    unsigned match_start; /* start of matching string */
    unsigned lookahead;   /* number of valid bytes ahead in window */
    unsigned minlookahead;

    unsigned max_chain_length;
    /* To speed up deflation, hash chains are never searched beyond this length.
     * A higher limit improves compression ratio but degrades the speed. */

    unsigned int max_lazy_match;
    /* Attempt to find a better match only when the current match is strictly
     * smaller than this value. This mechanism is used only for compression
     * levels >= 4. */

    unsigned good_match;
    /* Use a faster search when the previous match is longer than this */
    int nice_match; /* Stop searching when current match exceeds this */

    /* A block of local deflate process data to be saved between
     * sequential calls to deflate functions */
    int match_available; /* set if previous match exists */
    unsigned match_length; /* length of best match */
};

#endif

