/*
 *	Frequency Table Class
 *	By Jeremy Lennert
 *	January 17, 2001
 *	v. 1.2.1
 *	
 *	FreqTable.cpp
 *	
 *	Defines the methods for the class defined in FreqTable.h
 */

#include "FreqTable.h"

FreqTable::FreqTable()	// Initialize all pointers to NULL
{
	for (int x = 0; x < 701; x++)
	{
		table[x] = NULL;
	}
	current = NULL;
}

/*
 *	IMPORTANT:
 *	My hash() methods do not clean up old data; that is, if
 *	you store a value with the exact same coordinate twice,
 *	it adds a new value without removing the old one.
 *
 *	For my purposes, I happen to know that I will not need
 *	to overwrite data previously placed in the hash table,
 *	so this is OK.  If this were not the case, the function
 *	would need to be modified to check if the collision chain
 *	for the hash value already contains an element whose 
 *	'unhashed' variable matches the variable x.
 */

void FreqTable::hash(unsigned long x, int value)
{
	if (value == 0) return;	// Zero is the default value returned,
							// so there is no need to store it
	if (x == 0x0d0d0a) {
		cout << "0x0d0d0a\n";
	}
	int coord;
	coord = doHash(x);			// Hash coordinate
	if (table[coord] == NULL)	// Create new data if it doesn't exist
	{
		table[coord] = new Chain;
		table[coord]->unhashed = x;
		table[coord]->value = value;
		table[coord]->next = NULL;
	}
	else		// Use linked list chaining to handle collisions
	{
		Chain *foo;
		foo = new Chain;
		foo->next = table[coord];
		table[coord] = foo;
		table[coord]->unhashed = x;
		table[coord]->value = value;
	}
}

void FreqTable::hash(unsigned long x, unsigned long y, int value)
{
	hash((x * 256 + y), value);		// Combine coordinates and call first hash method
}

void FreqTable::hash(unsigned char x, unsigned char y, unsigned char z, int value)
{
	hash(((x * 256 + y) * 256 + z), value);	// Combine coordinates and call first hash method
}

int FreqTable::find(unsigned long x)
{
	if (x == 0x0d0d0a) {
		cout << "0x0d0d0a\n";
	}
	int returnval = 0;	// Return 0 if no data is stored with that value
	Chain *search;
	unsigned long unhashed = x;
	int coord = doHash(unhashed);	// Find requested data on hash table
	search = table[coord];
	while (search != NULL)		// Start looking through collision chain
	{
		if (search->unhashed == unhashed)	// If the data we're looking at
		{									// is the one we want
			returnval = search->value;	// Return appropriate value
			search = NULL;				// and stop searching
		}
		else
		{
			search = search->next;	// Otherwise continue the search
		}
	}
	return returnval;
}

int FreqTable::find(unsigned long x, unsigned long y)
{
	return find((x * 256 + y));	// Combine coordinates and call first find method
}

int FreqTable::find(unsigned char x, unsigned char y, unsigned char z)
{
	return find(((x * 256 + y) * 256 + z));// Combine coordinates and call first find method
}

Chain* FreqTable::dump()
{
	if (current == NULL)	// If this is the first time it was called,
	{						// find first value in table
		for (int x = 0; x < 701; x++)
		{
			if (table[x] != NULL)
			{
				current = table[x];
				currenth = x;
				break;
			}
		}
	}
	else		// Otherwise, find next value in table
	{
		if (current->next != NULL) current = current->next;
		else
		{
			current = NULL;		// If there are no more, use NULL and reset
			for (int x = currenth+1; x < 701; x++)
			{
				if (table[x] != NULL)
				{
					current = table[x];
					currenth = x;
					break;
				}
			}
		}
	}

	return current;
}

void FreqTable::resetDump()
{
	current = NULL;
}

int FreqTable::doHash(unsigned long unhashed)
{
	int x;
	x = unhashed % 701;
	return x;
}

FreqTable::~FreqTable()
{
	Chain *consign;

	if (dump() != NULL)
	{
		consign = current;
		while (dump() != NULL)
		{
			delete consign;
			consign = current;
		}
		delete consign;
	}
}