#include "StdAfx.h"

#include "LZW.h"
#include <iostream>
using namespace std;

void LZW::initialiseDictionnaire() {
int i;
	for(i=0;i<TAILLE_TABLE;i++)
		DICT(i).code_value=MUNUSED;

	code_suivant=PREMIER_CODE;
	largeur_codage=9;
	prochain_code_saut=511;
}

void LZW::initialiseStockage()
{
	int i;
	for(i=0;i<TABLE_PAGE;i++) {
		dict[i]=(struct Dictionnaire*) calloc(256,sizeof(struct Dictionnaire));
	}
}

unsigned int LZW::trouve_chaine(int parent_code,int child_character) {
unsigned int index;
int offset;

	index=(child_character << (BITS -8)) ^ parent_code;
	if(index==0)
		offset=1;
	else
		offset=TAILLE_TABLE - index;

	for(;;) 
	{
		if(DICT(index).code_value==MUNUSED)
			return ((unsigned int) index);

		if(DICT(index).parent_code==parent_code &&
			DICT(index).character==(char) child_character)
			return index;

		if((int) index>=offset)
			index-=offset;
		else
			index+=TAILLE_TABLE-offset;
	}
}

void LZW::compressFile(FILE*input,BitFile*output) {
int character;
int string_code;
unsigned int index;
	initialiseStockage();
	initialiseDictionnaire();

	cb++;
	if((string_code=getc(input))==EOF)
		string_code=FIN_DE_FLUX_LZ;

	while((character=getc(input))!=EOF) {
		cb++;
		index=trouve_chaine(string_code,character);

		if(DICT(index).code_value != -1) 
			string_code=DICT(index).code_value;
		else {
			DICT(index).code_value=code_suivant++;
			DICT(index).parent_code=string_code;
			DICT(index).character=(char)character;

			output->outputBits(string_code,largeur_codage);
			
			string_code=character;

			if(code_suivant>CODE_MAX) {
				output->outputBits(CODE_PURGE,largeur_codage);
				initialiseDictionnaire();
			} else if(code_suivant>prochain_code_saut) {
				output->outputBits(CHANGEMENT_CODAGE,largeur_codage);
				largeur_codage++;
				prochain_code_saut<<=1;
				prochain_code_saut|=1;
			}
		}
	}
	output->outputBits(string_code,largeur_codage);
	output->outputBits(FIN_DE_FLUX_LZ,largeur_codage);
}


unsigned int LZW::decodage_chaine(int count,int code) 
{
	while(code>255) {
		decode_stack[count++]=DICT(code).character;
		code=DICT(code).parent_code;
	}
	decode_stack[count++]=(char) code;
	return count;
}

void LZW::expandFile(BitFile*input,FILE*output) {
unsigned int new_code;
unsigned int old_code;
int character;
unsigned int count;
	initialiseStockage();
	for(;;) {
		initialiseDictionnaire();
		old_code=(unsigned int) input->inputBits(largeur_codage);

		if(old_code==FIN_DE_FLUX_LZ)
			return;

		character=old_code;
		putc(old_code,output);

		for(;;) {
			new_code=(unsigned int) input->inputBits(largeur_codage);

			if(new_code==FIN_DE_FLUX_LZ)
				return;

			if(new_code==CODE_PURGE)
				break;

			if(new_code==CHANGEMENT_CODAGE) {
				largeur_codage++;
				continue;
			}

			if(new_code>=code_suivant) {
				decode_stack[0]=(char) character;
				count=decodage_chaine(1,old_code);
			} else
				count=decodage_chaine(0,new_code);

			character=decode_stack[count-1];

			while(count>0)
				putc(decode_stack[--count],output);

			DICT(code_suivant).parent_code=old_code;
			DICT(code_suivant).character=(char) character;
			code_suivant++;
			old_code=new_code;
		}
	}
}

int LZW::comprimer(char*nom,FILE*source,FILE*dest)
{
	cout << "LZW de " << nom << " ";
	BitFile*sortie;
	sortie=new BitFile;
	sortie->openOutput(dest);
	compressFile(source,sortie);
	sortie->closeOutput();

	int r=sortie->cb;
	delete sortie;
	return r;
}

void LZW::expanser(char*nom,int taille_originale,int taille_archive,FILE*source)
{
	cout << "DeLzw de " << nom << " ";
	FILE*sortie;
	sortie=fopen(nom,"wb");
	BitFile*entree;
	entree=new BitFile;
	entree->openInput(source);
	expandFile(entree,sortie);
	fclose(sortie);
	delete entree;
}