#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "range.h"

#define SYMS 256
/* Change nr. of models here, e.g. 1<<11 means 2048 models */
#define MODELS (Uint)(1<<11)
#define MASK (Uint)(MODELS-1)
#define IOBUF_SIZE 32*1024
#define COUNT 256

Uint ftbl[MODELS][SYMS], ftblp[SYMS];
rc_model rcm[MODELS], rcp;
char ibuf[IOBUF_SIZE];
char obuf[IOBUF_SIZE];

/* An order 1 decoder file to file demonstration */
int main (int argc, char **argv) {
	int sym;
	rc_decoder rd;
	FILE *fp, *ofp;
	Uint fsize, i, n, lastsym, lastsym2, lastsym3, s1, s2, c, p, flag;
	
	if (argc != 3) {
		fprintf(stderr, "Usage:\n%s infile outfile\n", argv[0]);
		exit(1);
	}
	fp = fopen(argv[1], "rb");
	ofp = fopen(argv[2], "wb");
	if (fp && ofp) {
		setvbuf(fp, ibuf, _IOFBF, IOBUF_SIZE);
		setvbuf(ofp, obuf, _IOFBF, IOBUF_SIZE);
		fsize = (Uint)getc(fp);  /* Get filesize */
		fsize |= (Uint)getc(fp) << 8;
		fsize |= (Uint)getc(fp) << 16;
		fsize |= (Uint)getc(fp) << 24;
		
		/* Initiate all the models */
		for (n = 0; n < MODELS; n++) {
			i = ModelInit (&rcm[n], SYMS, ftbl[n], NULL, 100, (Uint)1<<15, ADAPT);
			if (i != RC_OK) {
				fprintf(stderr, "Error: maxFreq or totFreq > 65536\n");
				exit(1);
			}
		}
		i = ModelInit (&rcp, SYMS, ftblp, NULL, 1, (Uint)1<<16, ADAPT);
		if (i != RC_OK) {
			fprintf(stderr, "Error: maxFreq or totFreq > 65536\n");
			exit(1);
		}
		StartDecode (&rd, fp, NULL, 0);
		printf("Decoding...\n");
		fflush(stdout);
		c = p = s1 = s2 = lastsym = lastsym2 = lastsym3 = 0;
		flag = 1;
		for (i = 0; i < fsize; i++) {
			if (flag) {
				/* If data is text-like then use more bits */
				if (s1 > s2) {
					n = (lastsym^lastsym2<<5^lastsym3<<10) & MASK;
					sym = DecodeSymbol (&rd, &rcm[n]);
					rcm[n].maxFreq = (Uint)1<<16;
				}
				else {
					n = (lastsym^lastsym2<<8) & MASK;
					sym = DecodeSymbol (&rd, &rcm[n]);
					rcm[n].maxFreq = (Uint)1<<14;
				}
			}
			else
				sym = DecodeSymbol (&rd, &rcp);
			if (rd.error != RC_OK) break;
			fputc(sym, ofp);
			c++;
			if (c >= COUNT) {
				c = 0;
				if (rd.passed >= p + COUNT)
					flag = 0;
				else
					flag = 1;
				p = rd.passed;
			}
			if (sym < 128) s1++;
			else           s2+=8;
			if (s1 + s2 > 8192) {
				s1 /= 2;
				s2 /= 2;
			}
			lastsym3 = lastsym2;
			lastsym2 = lastsym;
			lastsym = sym;
		}
		
		switch (rd.error) {
			case RC_OK:
				printf("Decompressed %lu bytes to %lu bytes\n", (unsigned long)rd.passed, (unsigned long)fsize);
				fflush(stdout);
				break;
			case RC_ERROR:
				fprintf(stderr, "Decode error: Symbol outside range\n");
				break;
			case RC_IO_ERROR:
				fprintf(stderr, "Decode error: Could not input compressed data\n");
		}
	}
	fclose(fp);
	fclose(ofp);
	
	return 0;
}
