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

#define BSIZE 2000000
#define CSIZE BSIZE + BSIZE/100
#define SYMS 256

Uint ftbl[SYMS];  /* The frequency table */

/* A simple demonstration of memory to memory compression */
int main () {
	Sint sym;
	Uint i, n;
	uc *op, *s;
	rc_encoder rc;
	rc_decoder rd;
	rc_model rcm;
	
	op = (uc *)malloc(CSIZE);
	s = (uc *)malloc(BSIZE+1);
	srand(clock());
	if (op && s) {
		/* King's worst case expanded 
		for (i = 0; i < BSIZE-3; i+=3) {
			s[i] = rand() % 1 + 0x53;
			s[i+1] = rand() % 1 + 0xa8;
			s[i+2] = rand() % 1 + 0xfe;
		}
		*/
		for (i = 0; i < BSIZE-2; i+=2) {
			s[i] = 0x55;
			s[i+1] = 0xaa;
		}
		
		n = ModelInit (&rcm, SYMS, ftbl, NULL, 4, (Uint)1<<16, ADAPT);
		if (n != RC_OK) {
			fprintf(stderr, "Error: maxFreq or totFreq > 65536\n");
			free(op);
			free(s);
			exit(1);
		}
		fprintf(stderr, "Encoding...\n");
		fflush(stdout);
		StartEncode (&rc, NULL, op, CSIZE);
		for (i = 0; i < BSIZE; i++) {
			EncodeSymbol (&rc, &rcm, s[i]);
			switch (rc.error) {
				case RC_OK:
					break;
				case RC_ERROR:
					fprintf(stderr, "Encode error: Symbol outside range\n");
					free(op);
					free(s);
					exit(1);
				case RC_IO_ERROR:
					fprintf(stderr, "Encode error: Could not output compressed data\n");
					free(op);
					free(s);
					exit(1);
			}
		}
		FinishEncode (&rc);
		fprintf(stderr, "Data length: %ld, passed: %lu\n", (long)BSIZE, (unsigned long)rc.passed);
		
		n = ModelInit (&rcm, SYMS, ftbl, NULL, 4, (Uint)1<<16, ADAPT);
		if (n != RC_OK) {
			fprintf(stderr, "Error: maxFreq or totFreq > 65536\n");
			free(op);
			free(s);
			exit(1);
		}
		fprintf(stderr, "Decoding...\n");
		fflush(stdout);
		StartDecode (&rd, NULL, op, CSIZE);
		n = 0;
		for (i = 0; i < BSIZE; i++) {
			sym = DecodeSymbol (&rd, &rcm);
			switch (rd.error) {
				case RC_OK:
					break;
				case RC_ERROR:
					fprintf(stderr, "Decode error: Symbol outside range\n");
					free(op);
					free(s);
					exit(1);
				case RC_IO_ERROR:
					fprintf(stderr, "Decode error: Could not input compressed data\n");
					free(op);
					free(s);
					exit(1);
			}
			if (s[n++] != sym) break;
		}
		
		fprintf(stderr, "Done!\n");
		fflush(stdout);
		if (i == BSIZE) {
			fprintf(stderr, "Data length: %ld, passed: %lu\n", (long)BSIZE, (unsigned long)rc.passed);
			fprintf(stderr, "Strings are the same!\n");
		}
		else
			fprintf(stderr, "Strings differ at %d...\n", i);
	}
	free(op);
	free(s);
	
	return 0;
}
