//////////////////////////////////////////////////////////////////////
// hash_table.h: interface for the hash_table class.
//
//////////////////////////////////////////////////////////////////////

#ifndef HASH_TABLE_H 
#define HASH_TABLE_H

#include "fsout.h"

class K_tree;

class Data;

struct KeyHashNode
{
	int  *iset;
	int  length;
	int  support;
	
	int closeIndex;
};


struct CloseHashNode
{
	int  *iset;
	int  length;
	int  support;

	K_tree* keys;

	//for maintenance
	int versionNo; //to avoid update twice
	int splite_versionNO;

	int* diffSet;
	int* shareSet;

	int diffLen;
	int shareLen;
	
};

typedef KeyHashNode *LPKeyHashNode;
typedef CloseHashNode *LPCloseHashNode;
typedef void * HashNode;

#define LOADFACTOR 0.9

#define OFFSET  (-1)

//#define INITSIZE 10
//#define SINITSIZE 10007
#define SINITSIZE 100003
//#define SINITSIZE 378253
#define INITSIZE 16000057
//#define INITSIZE 32000011

#define MAXPOWER  32

#define INCREMENT(x) x+x+x

class hash_table
{
public:
	HashNode *hashTable;

	int maxSize;
	int currNodeNum;
	int threshold;

	int *hashMap;
	int hashMapSize;
	bool localHashMap; //indicate whether the hashmap is stored in the class

	bool initModMap(int num, int * &map, int prime);
	bool initModMap(int* map, int mapLen);

	int  getPrime(int start);
	bool isPrime(int num);

    inline int  single_mod(int i, int prime); //2^i % prime
    inline int  set_mod(int *iset, int length, int order, int *map, int size);
    //inline int  getProbe(int *iset, int length, int ipass);

	//bool rehashTable();
	//void releaseTable();

	hash_table();
	~hash_table();

	void initTable(int* map, int maplength, int tableSize);
	void initTable(int itemno, int tableSize);
};

class closeHashTable : public hash_table
{
private:
	LPCloseHashNode *closeTable;

	bool rehashTable();	
	int getCloseSupport(LPCloseHashNode closeNode);

public:
	closeHashTable();
	~closeHashTable();

	void releaseTable();

	void initTable(int* map, int maplength, int tableSize); //init with global hash map
	void initTable(int itemno, int tableSize); //init with local hash map

	int insert(int *&iCloseSet, int clen, int support, int *iKeySet, int iLen);
	int insert(int *&iCloseSet, int clen, int support, K_tree* ktree, int index);
	
	int find(int *iset, int length, int &support);
	LPCloseHashNode find(int* iset, int length);
	CloseHashNode* find(int index) {return closeTable[index];}

	void outputClose(FSout *fout, double &closeNum);

	LPCloseHashNode *getTable(){return closeTable;}

	//int readStat(Data *fdat);
	//int readClose(Data *fdat);
};

class keyHashTable : public hash_table
{
private:
	LPKeyHashNode *keyTable;

	int currPos;	//for function get next
	int returnedNodeNum; //for function get next

	bool rehashTable();

public:
	keyHashTable();
	~keyHashTable();

	void releaseTable();

	void initTable(int* map, int maplength, int tableSize); //init with global hash map
	void initTable(int itemno, int tableSize); //init with local hash map

	int insert(int &keynum, int *&iKeySet, int klen, int support, int cindex=-1);
	int insert(int *&iKeySet, int klen, int support, int cindex=-1);
	
	int find(int *iset, int length, int &support);
	LPKeyHashNode find(int* iset, int length);
	LPKeyHashNode find(int index) {return keyTable[index];}

	void outputKey(FSout *fout, double &keyNum);

	KeyHashNode* getNext();
};

#endif
