/*
This product contains certain software code or other information
("AT&T Software") proprietary to AT&T Corp. ("AT&T").  The AT&T
Software is provided to you "AS IS".  YOU ASSUME TOTAL RESPONSIBILITY
AND RISK FOR USE OF THE AT&T SOFTWARE.  AT&T DOES NOT MAKE, AND
EXPRESSLY DISCLAIMS, ANY EXPRESS OR IMPLIED WARRANTIES OF ANY KIND
WHATSOEVER, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, WARRANTIES OF
TITLE OR NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS, ANY
WARRANTIES ARISING BY USAGE OF TRADE, COURSE OF DEALING OR COURSE OF
PERFORMANCE, OR ANY WARRANTY THAT THE AT&T SOFTWARE IS "ERROR FREE" OR
WILL MEET YOUR REQUIREMENTS.

Unless you accept a license to use the AT&T Software, you shall not
reverse compile, disassemble or otherwise reverse engineer this
product to ascertain the source code for any AT&T Software.

(c) AT&T Corp. All rights reserved.  AT&T is a registered trademark of AT&T Corp.

***********************************************************************

History:

      24/11/99  - initial release by Hartmut Liefke, liefke@seas.upenn.edu
                                     Dan Suciu,      suciu@research.att.com
*/

//**************************************************************************
//**************************************************************************

// This module contains the label dictionary manager
// The label dictionary stores the associations between label IDs and
// the actual label name.

#pragma once

/* includes */
#include "XMillData.h"
#include "Types.hpp"
#include "MemStreamer.hpp"
#include "Load.hpp"
#include "ZLib.hpp"
#include "SmallUncompress.hpp"

/* macros */
#define ISATTRIB(labelid)  (((labelid)&ATTRIBLABEL_STARTIDX)?1:0)

class Session;

// For the compressor, the dictionary is implemented as a hash table,
// since we need to look up the ID for a given name

/* defines */
// Maximum number of labels
#define MAXLABEL_NUM       65535L

#define HASHTABLE_SIZE    256
#define HASHTABLE_MASK    255
#define HASHTABLE_SHIFT   8
#define HASHTABLE_SHIFT2  16
#define HASHTABLE_SHIFT3  24

#define LABELDICT_MINLABELNUM 32

// For the compressor, we store each label dictionary item
// in the following data structure.
// The label data is stored *directly* after the CompressLabelDictItem object.

/* structs */
struct CompressLabelDictItem
{
   unsigned short          len;           // The length of the label
   TLabelID                labelid;       // The label ID
   CompressLabelDictItem   *nextsamehash; // The next label with the same hash value
   CompressLabelDictItem   *next;         // The label with the next higher ID

   char IsAttrib();

   char *GetLabelPtr();
      // Returns the pointer to the label name

   unsigned short GetLabelLen();
      // Returns the label length
};

//******************************************************************************
// For the decompressor, the label dictionary is implemented through a
// lookup table. New entries can be added through the decompressor runs

struct UncompressLabelDictItem
   // Each label is represented in this structure
{
   unsigned short    len;        // The length of the label
   unsigned char     isattrib;   // Is it an attribute?
   char              *strptr;    // The pointer to the actual string
};

struct UncompressLabelDict
   // Represents a sequence of labels.
   // The labels are stored in 'UncompressLabelDictItem'-objects directly
   // after the 'UncompressLabelDict'-object.
{
   TLabelID                labelnum;   // The number of labels in this sequence 
   UncompressLabelDict     *next;      // The next label sequence

   UncompressLabelDictItem* GetArrayPtr();
      // Returns the pointer to the UncompressLabelDictItem
};

/* classes */
class LabelDict 
{
protected:
   TLabelID                   labelnum;            // The number of labels
	bool initialized;

public:
	Session *session;
#ifdef PROFILE
   unsigned long              lookupcount,hashitercount;
   void PrintProfile()
#endif
   LabelDict(Session *s);

	void Init();
	void PrintLabel(TLabelID labelid);
	void Print();

	virtual void InitMore()=0;
	virtual void Reset()=0;
	virtual unsigned long LookupCompressLabel(TLabelID labelid,char **ptr,unsigned char *isattrib)=0;
};

class DecompLabelDict: public LabelDict
{
   UncompressLabelDict        *labeldictlist;      // The list of label groups
   UncompressLabelDict        *lastlabeldict;      // The last label group

public:
	DecompLabelDict(Session *s);
	void InitMore();
	void Reset();
	void Load(SmallBlockUncompressor *uncompress);
	unsigned long LookupCompressLabel(TLabelID labelid,char **ptr,unsigned char *isattrib);
};

class CompLabelDict: public LabelDict
{
   TLabelID                   predefinedlabelnum; 
      // The number of labels predefined through the FSMs
      // Those labels will *not* be deleted in a Reset() invocation

   CompressLabelDictItem      **hashtable;         // The hash table
   CompressLabelDictItem      *labels,**labelref;  // The list of labels

   // This describes how many of the labels already have been saved
   // in the compressed file - i.e. in a previous run
   TLabelID                   savedlabelnum;    
   CompressLabelDictItem      **savedlabelref;

public:
	CompLabelDict(Session *s);
	~CompLabelDict();

	void InitMore();
	void Reset();
	void FinishedPredefinedLabels();
	int CalcHashIdx(char *label,int len);
	TLabelID FindLabelOrAttrib(char *label,unsigned len,unsigned char isattrib);
	TLabelID CreateLabelOrAttrib(char *label,unsigned len,unsigned char isattrib);
	TLabelID GetLabelOrAttrib(char *label,unsigned len,unsigned char isattrib);
	void Store(Compressor *compressor);
	unsigned long LookupCompressLabel(TLabelID labelid,char **ptr,unsigned char *isattrib);
};
