// Copyright (C) 2019
// Smithsonian Astrophysical Observatory, Cambridge, MA, USA
// For conditions of distribution and use, see copyright notice in "copyright"

#ifndef __tkagif_h__
#define __tkagif_h__

/*
 * Algorithm: use open addressing double hashing (no chaining) on the
 * prefix code / next character combination. We do a variant of Knuth's
 * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
 * secondary probe. Here, the modular division first probe is gives way to
 * a faster exclusive-or manipulation. Also do block compression with an
 * adaptive reset, whereby the code table is cleared when the compression
 * ratio decreases, but after the table fills. The variable-length output
 * codes are re-sized at this point, and a special CLEAR code is generated
 * for the decompressor. Late addition: construct the table according to
 * file size for noticeable speed improvement on small files. Please
 * direct questions about this implementation to ames!jaw.
 *
 * To save much memory, we overlay the table used by compress() with those
 * used by decompress(). The tab_prefix table is the same size and type as
 * the codeTable. The tab_suffix table needs 2**GIFBITS characters. We get
 * this from the beginning of hashTable. The output stack uses the rest of
 * hashTable, and contains characters. There is plenty of room for any
 * possible stack (stack used to be 8000 characters).
 */

#define HSIZE		5003	/* 80% occupancy */

typedef struct {
  int count;
  unsigned char red;
  unsigned char green;
  unsigned char blue;
} Color;

typedef struct {
  unsigned char red;
  unsigned char green;
  unsigned char blue;
} Pixel;

class TkAGIF {
private:
  Tcl_Interp* interp_;
  
  ofstream* out_;
  int width_;
  int height_;
  int resolution_;

  unsigned char* pict_;
  long pictCount_;
  
  Color* colorTable_;
  int colorTableSize_;

  long maxCode_; // Maximum code, given numBits
  int clearCode_;
  int eofCode_;

  int initialBits_;
  int numBits_;
  int currentBits_;

  int clearFlag_;
  int freeEntry_; // First unused entry

  int hashTable_[HSIZE];
  unsigned char packetAccumulator_[256];
  int accumulatedByteCount_;
  unsigned long currentAccumulated_;

private:
  void initColorTable();
  void scanImage(Pixel*);
  void compress();

  int input();
  void output(long);
  void clearForBlock();
  void clearHashTable();
  void charOut(int);
  void flushChar();

 public:
  TkAGIF(Tcl_Interp*);

  int create(int, const char*[]);
  int add(int, const char*[]);
  int close(int, const char*[]);
};

extern TkAGIF* tkagif;

#endif
