/*
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
For a list of contributors, see the accompanying CONTRIBUTORS file.

This file is part of GtkRadiant.

GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "q3data.h"

#if 0
/*
==================
MTF
==================
*/
cblock_t MTF (cblock_t in)
{
	int			i, j, b, code;
	byte		*out_p;
	int			index[256];
	cblock_t	out;

	out_p = out.data = malloc(in.count + 4);

	// write count
	*out_p++ = in.count&255;
	*out_p++ = (in.count>>8)&255;
	*out_p++ = (in.count>>16)&255;
	*out_p++ = (in.count>>24)&255;

	for (i=0 ; i<256 ; i++)
		index[i] = i;

	for (i=0 ; i<in.count ; i++)
	{
		b = in.data[i];
		code = index[b];
		*out_p++ = code;
		
		// shuffle b indexes to 0
		for (j=0 ; j<256 ; j++)
			if (index[j] < code)
				index[j]++;
		index[b] = 0;
	}

	out.count = out_p - out.data;

	return out;
}


//==========================================================================

int		bwt_size;
byte	*bwt_data;

int bwtCompare (const void *elem1, const void *elem2)
{
	int		i;
	int		i1, i2;
	int		b1, b2;

	i1 = *(int *)elem1;
	i2 = *(int *)elem2;

	for (i=0 ; i<bwt_size ; i++)
	{
		b1 = bwt_data[i1];
		b2 = bwt_data[i2];
		if (b1 < b2)
			return -1;
		if (b1 > b2)
			return 1;
		if (++i1 == bwt_size)
			i1 = 0;
		if (++i2 == bwt_size)
			i2 = 0;
	}

	return 0;
}

/*
==================
BWT
==================
*/
cblock_t BWT (cblock_t in)
{
	int		*sorted;
	int		i;
	byte	*out_p;
	cblock_t	out;

	bwt_size = in.count;
	bwt_data = in.data;

	sorted = malloc(in.count*sizeof(*sorted));
	for (i=0 ; i<in.count ; i++)
		sorted[i] = i;
	qsort (sorted, in.count, sizeof(*sorted), bwtCompare);

	out_p = out.data = malloc(in.count + 8);

	// write count
	*out_p++ = in.count&255;
	*out_p++ = (in.count>>8)&255;
	*out_p++ = (in.count>>16)&255;
	*out_p++ = (in.count>>24)&255;

	// write head index
	for (i=0 ; i<in.count ; i++)
		if (sorted[i] == 0)
			break;
	*out_p++ = i&255;
	*out_p++ = (i>>8)&255;
	*out_p++ = (i>>16)&255;
	*out_p++ = (i>>24)&255;

	// write the L column
	for (i=0 ; i<in.count ; i++)
		*out_p++ = in.data[(sorted[i]+in.count-1)%in.count];

	free (sorted);

	out.count = out_p - out.data;

	return out;
}

//==========================================================================

typedef struct hnode_s
{
	int			count;
	qboolean	used;
	int			children[2];
} hnode_t;

int			numhnodes;
hnode_t		hnodes[512];
unsigned	charbits[256];
int			charbitscount[256];

int	SmallestNode (void)
{
	int		i;
	int		best, bestnode;

	best = 99999999;
	bestnode = -1;
	for (i=0 ; i<numhnodes ; i++)
	{
		if (hnodes[i].used)
			continue;
		if (!hnodes[i].count)
			continue;
		if (hnodes[i].count < best)
		{
			best = hnodes[i].count;
			bestnode = i;
		}
	}

	if (bestnode == -1)
		return -1;

	hnodes[bestnode].used = true;
	return bestnode;
}

void BuildChars (int nodenum, unsigned bits, int bitcount)
{
	hnode_t	*node;

	if (nodenum < 256)
	{
		if (bitcount > 32)
			Error ("bitcount > 32");
		charbits[nodenum] = bits;
		charbitscount[nodenum] = bitcount;
		return;
	}

	node = &hnodes[nodenum];
	bits <<= 1;
	BuildChars (node->children[0], bits, bitcount+1);
	bits |= 1;
	BuildChars (node->children[1], bits, bitcount+1);
}

/*
==================
Huffman
==================
*/
cblock_t Huffman (cblock_t in)
{
	int			i;
	hnode_t		*node;
	int			outbits, c;
	unsigned	bits;
	byte		*out_p;
	cblock_t	out;
	int			max, maxchar;

	// count
	memset (hnodes, 0, sizeof(hnodes));
	for (i=0 ; i<in.count ; i++)
		hnodes[in.data[i]].count++;

	// normalize counts
	max = 0;
	maxchar = 0;
	for (i=0 ; i<256 ; i++)
	{
		if (hnodes[i].count > max)
		{
			max = hnodes[i].count;
			maxchar = i;
		}
	}
	if (max == 0)
		Error ("Huffman: max == 0");

	for (i=0 ; i<256 ; i++)
	{
		hnodes[i].count = (hnodes[i].count*255+max-1) / max;
	}

	// build the nodes
	numhnodes = 256;
	while (numhnodes != 511)
	{
		node = &hnodes[numhnodes];

		// pick two lowest counts
		node->children[0] = SmallestNode ();
		if (node->children[0] == -1)
			break;	// no more

		node->children[1] = SmallestNode ();
		if (node->children[1] == -1)
		{
			if (node->children[0] != numhnodes-1)
				Error ("Bad smallestnode");
			break;
		}
		node->count = hnodes[node->children[0]].count + 
			hnodes[node->children[1]].count;
		numhnodes++;
	}

	BuildChars (numhnodes-1, 0, 0);

	out_p = out.data = malloc(in.count*2 + 1024);
	memset (out_p, 0, in.count*2+1024);

	// write count
	*out_p++ = in.count&255;
	*out_p++ = (in.count>>8)&255;
	*out_p++ = (in.count>>16)&255;
	*out_p++ = (in.count>>24)&255;

	// save out the 256 normalized counts so the tree can be recreated
	for (i=0 ; i<256 ; i++)
		*out_p++ = hnodes[i].count;

	// write bits
	outbits = 0;
	for (i=0 ; i<in.count ; i++)
	{
		c = charbitscount[in.data[i]];
		bits = charbits[in.data[i]];
		while (c)
		{
			c--;
			if (bits & (1<<c))
				out_p[outbits>>3] |= 1<<(outbits&7);
			outbits++;
		}
	}

	out_p += (outbits+7)>>3;

	out.count = out_p - out.data;

	return out;
}

//==========================================================================

/*
==================
RLE
==================
*/
#define	RLE_CODE	0xe8
#define	RLE_TRIPPLE	0xe9

int	rle_counts[256];
int	rle_bytes[256];

cblock_t RLE (cblock_t in)
{
	int		i;
	byte	*out_p;
	int		val;
	int		repeat;
	cblock_t	out;

	out_p = out.data = malloc (in.count*2);

	// write count
	*out_p++ = in.count&255;
	*out_p++ = (in.count>>8)&255;
	*out_p++ = (in.count>>16)&255;
	*out_p++ = (in.count>>24)&255;

	for (i=0 ; i<in.count ; )
	{
		val = in.data[i];
		rle_bytes[val]++;
		repeat = 1;
		i++;
		while (i<in.count && repeat < 255 && in.data[i] == val)
		{
			repeat++;
			i++;
		}
if (repeat < 256)
rle_counts[repeat]++;
		if (repeat > 3 || val == RLE_CODE)
		{
			*out_p++ = RLE_CODE;
			*out_p++ = val;
			*out_p++ = repeat;
		}
		else
		{
			while (repeat--)
				*out_p++ = val;
		}
	}

	out.count = out_p - out.data;
	return out;
}

//==========================================================================

unsigned	lzss_head[256];
unsigned	lzss_next[0x20000];

/*
==================
LZSS
==================
*/
#define	BACK_WINDOW		0x10000
#define	BACK_BITS		16
#define	FRONT_WINDOW	16
#define	FRONT_BITS		4
cblock_t LZSS (cblock_t in)
{
	int		i;
	byte	*out_p;
	cblock_t	out;
	int		val;
	int		j, start, max;
	int		bestlength, beststart;
	int		outbits;

if (in.count >= sizeof(lzss_next)/4)
Error ("LZSS: too big");

	memset (lzss_head, -1, sizeof(lzss_head));

	out_p = out.data = malloc (in.count*2);
	memset (out.data, 0, in.count*2);

	// write count
	*out_p++ = in.count&255;
	*out_p++ = (in.count>>8)&255;
	*out_p++ = (in.count>>16)&255;
	*out_p++ = (in.count>>24)&255;

	outbits = 0;
	for (i=0 ; i<in.count ; )
	{
		val = in.data[i];
#if 1
// chained search
		bestlength = 0;
		beststart = 0;

		max = FRONT_WINDOW;
		if (i + max > in.count)
			max = in.count - i;

		start = lzss_head[val];
		while (start != -1 && start >= i-BACK_WINDOW)
		{			
			// count match length
			for (j=0 ; j<max ; j++)
				if (in.data[start+j] != in.data[i+j])
					break;
			if (j > bestlength)
			{
				bestlength = j;
				beststart = start;
			}
			start = lzss_next[start];
		}

#else
// slow simple search
		// search for a match
		max = FRONT_WINDOW;
		if (i + max > in.count)
			max = in.count - i;

		start = i - BACK_WINDOW;
		if (start < 0)
			start = 0;
		bestlength = 0;
		beststart = 0;
		for ( ; start < i ; start++)
		{
			if (in.data[start] != val)
				continue;
			// count match length
			for (j=0 ; j<max ; j++)
				if (in.data[start+j] != in.data[i+j])
					break;
			if (j > bestlength)
			{
				bestlength = j;
				beststart = start;
			}
		}
#endif
		beststart = BACK_WINDOW - (i-beststart);

		if (bestlength < 3)
		{	// output a single char
			bestlength = 1;

			out_p[outbits>>3] |= 1<<(outbits&7);	// set bit to mark char
			outbits++;
			for (j=0 ; j<8 ; j++, outbits++)
				if (val & (1<<j) )
					out_p[outbits>>3] |= 1<<(outbits&7);
		}
		else
		{	// output a phrase
			outbits++;	// leave a 0 bit to mark phrase
			for (j=0 ; j<BACK_BITS ; j++, outbits++)
				if (beststart & (1<<j) )
					out_p[outbits>>3] |= 1<<(outbits&7);
			for (j=0 ; j<FRONT_BITS ; j++, outbits++)
				if (bestlength & (1<<j) )
					out_p[outbits>>3] |= 1<<(outbits&7);
		}

		while (bestlength--)
		{
			val = in.data[i];
			lzss_next[i] = lzss_head[val];
			lzss_head[val] = i;
			i++;
		}
	}

	out_p += (outbits+7)>>3;
	out.count = out_p - out.data;
	return out;
}

//==========================================================================

#define	MIN_REPT	15
#define	MAX_REPT	0
#define	HUF_TOKENS	(256+MAX_REPT)

unsigned	charbits1[256][HUF_TOKENS];
int			charbitscount1[256][HUF_TOKENS];

hnode_t		hnodes1[256][HUF_TOKENS*2];
int			numhnodes1[256];

int			order0counts[256];

/*
==================
SmallestNode1
==================
*/
int	SmallestNode1 (hnode_t *hnodes, int numhnodes)
{
	int		i;
	int		best, bestnode;

	best = 99999999;
	bestnode = -1;
	for (i=0 ; i<numhnodes ; i++)
	{
		if (hnodes[i].used)
			continue;
		if (!hnodes[i].count)
			continue;
		if (hnodes[i].count < best)
		{
			best = hnodes[i].count;
			bestnode = i;
		}
	}

	if (bestnode == -1)
		return -1;

	hnodes[bestnode].used = true;
	return bestnode;
}


/*
==================
BuildChars1
==================
*/
void BuildChars1 (int prev, int nodenum, unsigned bits, int bitcount)
{
	hnode_t	*node;

	if (nodenum < HUF_TOKENS)
	{
		if (bitcount > 32)
			Error ("bitcount > 32");
		charbits1[prev][nodenum] = bits;
		charbitscount1[prev][nodenum] = bitcount;
		return;
	}

	node = &hnodes1[prev][nodenum];
	bits <<= 1;
	BuildChars1 (prev, node->children[0], bits, bitcount+1);
	bits |= 1;
	BuildChars1 (prev, node->children[1], bits, bitcount+1);
}


/*
==================
BuildTree1
==================
*/
void BuildTree1 (int prev)
{
	hnode_t		*node, *nodebase;
	int			numhnodes;

	// build the nodes
	numhnodes = HUF_TOKENS;
	nodebase = hnodes1[prev];
	while (1)
	{
		node = &nodebase[numhnodes];

		// pick two lowest counts
		node->children[0] = SmallestNode1 (nodebase, numhnodes);
		if (node->children[0] == -1)
			break;	// no more

		node->children[1] = SmallestNode1 (nodebase, numhnodes);
		if (node->children[1] == -1)
			break;

		node->count = nodebase[node->children[0]].count + 
			nodebase[node->children[1]].count;
		numhnodes++;
	}
	numhnodes1[prev] = numhnodes-1;
	BuildChars1 (prev, numhnodes-1, 0, 0);
}


/*
==================
Huffman1_Count
==================
*/
void Huffman1_Count (cblock_t in)
{
	int		i;
	int		prev;
	int		v;
	int		rept;

	prev = 0;
	for (i=0 ; i<in.count ; i++)
	{
		v = in.data[i];
		order0counts[v]++;
		hnodes1[prev][v].count++;
		prev = v;
#if 1
		for (rept=1 ; i+rept < in.count && rept < MAX_REPT ; rept++)
			if (in.data[i+rept] != v)
				break;
		if (rept > MIN_REPT)
		{
			hnodes1[prev][255+rept].count++;
			i += rept-1;
		}
#endif
	}
}


/*
==================
Huffman1_Build
==================
*/
byte	scaled[256][HUF_TOKENS];
void Huffman1_Build (FILE *f)
{
	int		i, j, v;
	int		max;
	int		total;

	for (i=0 ; i<256 ; i++)
	{
		// normalize and save the counts
		max = 0;
		for (j=0 ; j<HUF_TOKENS ; j++)
		{
			if (hnodes1[i][j].count > max)
				max = hnodes1[i][j].count;
		}
		if (max == 0)
			max = 1;
		total = 0;
		for (j=0 ; j<HUF_TOKENS ; j++)
		{	// easy to overflow 32 bits here!
			v = (hnodes1[i][j].count*(double)255+max-1)/max;
			if (v > 255)
				Error ("v > 255");
			scaled[i][j] = hnodes1[i][j].count = v;
			if (v)
				total++;
		}
		if (total == 1)
		{	// must have two tokens
			if (!scaled[i][0])
				scaled[i][0] = hnodes1[i][0].count = 1;
			else
				scaled[i][1] = hnodes1[i][1].count = 1;
		}

		BuildTree1 (i);
	}

#if 0
	// count up the total bits
	total = 0;
	for (i=0 ; i<256 ; i++)
		for (j=0 ; j<256 ; j++)
			total += charbitscount1[i][j] * hnodes1[i][j].count;

	total = (total+7)/8;
	printf ("%i bytes huffman1 compressed\n", total);
#endif

	fwrite (scaled, 1, sizeof(scaled), f);
}

/*
==================
Huffman1

Order 1 compression with pre-built table
==================
*/
cblock_t Huffman1 (cblock_t in)
{
	int			i;
	int			outbits, c;
	unsigned	bits;
	byte		*out_p;
	cblock_t	out;
	int			prev;
	int			v;
	int			rept;

	out_p = out.data = malloc(in.count*2 + 1024);
	memset (out_p, 0, in.count*2+1024);

	// write count
	*out_p++ = in.count&255;
	*out_p++ = (in.count>>8)&255;
	*out_p++ = (in.count>>16)&255;
	*out_p++ = (in.count>>24)&255;

	// write bits
	outbits = 0;
	prev = 0;
	for (i=0 ; i<in.count ; i++)
	{
		v = in.data[i];

		c = charbitscount1[prev][v];
		bits = charbits1[prev][v];
		if (!c)
			Error ("!bits");
		while (c)
		{
			c--;
			if (bits & (1<<c))
				out_p[outbits>>3] |= 1<<(outbits&7);
			outbits++;
		}

		prev = v;
#if 1
		// check for repeat encodes
		for (rept=1 ; i+rept < in.count && rept < MAX_REPT ; rept++)
			if (in.data[i+rept] != v)
				break;
		if (rept > MIN_REPT)
		{
			c = charbitscount1[prev][255+rept];
			bits = charbits1[prev][255+rept];
			if (!c)
				Error ("!bits");
			while (c)
			{
				c--;
				if (bits & (1<<c))
					out_p[outbits>>3] |= 1<<(outbits&7);
				outbits++;
			}
			i += rept-1;
		}
#endif
	}

	out_p += (outbits+7)>>3;

	out.count = out_p - out.data;

	return out;
}

#endif
