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

char buffer [8];
int bufferEcriture [8];//pour compression
char bufferLecture [80]; //pour decompression
char bufferTmp [15];
char bufferFichier[8];
int pointeurBF;
int pointeurBE;
int pointeurBL;
int bit;
int longueur;
int compteur;
int couleurActuelle;
FILE * sortie;
FILE * entree;

void remplirBuffer(char c){
  int i;
  for(i=0;i<8;i++){
    if(c%2==0)
      buffer[7-i]='0';
    else
      buffer[7-i]='1';
    c=c>>1;
  }
  //printf("%s\n",buffer);
}

int power(int a, int n){
  if(n<0)return -1;
  if(n==0)return 1;
  return a*power(a,n-1);
}

void remplirBufferEcriture(int b){
  bufferEcriture[pointeurBE] = b;
  pointeurBE++;
  if(pointeurBE>7){
    pointeurBE=0;
    int caractere=0;
    int i;
    for(i=0;i<8;i++){
      caractere+=(power(2,(7-i)))*bufferEcriture[i];
    }
    fputc(caractere,sortie);
    printf("{%d}",compteur);
    compteur++;
  }
}

/**
 * Ecrit le bit b (dans le fichier decompresse) l fois
 **/
void ecrit(){
  //printf("[%c,%d]",b,l);
  int i;
  int c;
  c=0;
  for(i=0;i<8;i++){
	if(bufferFichier[i]=='1'){
	  c=c+power(2,7-i);
      //printf("car = %d\n",c);
	}
  }
  fputc(c,sortie);
}

/**
 * Bufferise le bit b (dans le fichier decompresse) l fois
 **/
void bufferise(char b, int l){
  //printf("%d ",l);
  int i;
  for(i=0;i<l;i++){
	bufferFichier[pointeurBF] = b;
	pointeurBF++;
	if(pointeurBF>=8){
	  ecrit();
	  pointeurBF=0;
	}
  }
  //printf("\n");
}

int taille(int * a){
  int i;
  for(i=0;i<15;i++)
	if(a[i]==-1)return i;
}

/**
 * retourne 0 si les chaines sont identiques
 * Les chaines sont de tailles égales : strlen(a)==taille(b)
 **/
int comparer(char * a, int * b){
  int i;
  for(i=0;i<strlen(a);i++){
	if((a[i]=='0'&&b[i]==0) || (a[i]=='1'&&b[i]==1)){}
	else return 1;
  }
  return 0;
}

int trouveEtEcrit(char * buf){
  //printf("tEE %s\n",buf);
  //printf("LA %s\n",buf);
  int i;
  for(i=0;i<110;i++){
	//printf("tEE:len(buf)=%d len(tab[%d][1])=%d",strlen(buf),i,taille(tableau[i][1]));
	//printf("tEE:len(buf)=%d len(tab[%d][2])=%d\n",strlen(buf),i,taille(tableau[i][2]));
	//if(strlen(buf) == taille(tableau[i][1])){
	if(couleurActuelle == 0 && strlen(buf) == taille(tableau[i][1]) && comparer(buf,tableau[i][1])==0){
	  //printf("LA0 %s en %d\n",buf,i);
	  //printf("%d==%d\n",strlen(buf),taille(tableau[i][1]));
	  //printf("tEE:buf=%s tab[%d][1]=%d\n",buf,i,taille(tableau[i][1]));
	  bufferise('0',tableau[i][0][0]);
	  return 1;
	}
	//}
	//if(strlen(buf) == taille(tableau[i][2])){
	if(couleurActuelle == 1 && strlen(buf) == taille(tableau[i][2]) && (comparer(buf,tableau[i][2])==0)){
		//printf("LA1 %s en %d et %d==%d\n",buf,i,strlen(buf),taille(tableau[i][2]));
		//printf("tEE:buf=%s tab[%d][2]=%d\n",buf,i,taille(tableau[i][2]));
		bufferise('1',tableau[i][0][0]);
		return 1;
	  }
	//}
  }
  return 0;
}

void initialiserBT(){
  int i;
  for(i=0;i<15;i++)
	bufferTmp[i]='\0';
}

/**
 * ecrit le bufferLecture dans le fichier de sortie apr�s avoir cherch� le motif dans le tableau
 **/
void ecritClair(){
  //printf("ecritclair:compteur=%d\n",compteur);
  int i;
  int j;
  j=0;
  if(compteur!=0){
	j=compteur;
  }
  else initialiserBT();
  for(i=0;i<80;i++){
	bufferTmp[j] = bufferLecture[i];
	if(trouveEtEcrit(bufferTmp)){
	  //printf("ecritclair:%d[%d]\n",strlen(bufferTmp),i);
	  if(couleurActuelle==0)couleurActuelle=1;
	  else couleurActuelle=0;
	  initialiserBT();
	  j=0;
	}
	else{
	  j++;
	}
	if(i==79){
	  compteur=j;
	  //printf("ecritclair2:compteur=%d\n",compteur);
	  return;
	}
  }
}

void remplirBufferLecture(char c){
  int i;
  for(i=0;i<8;i++){
    if(c%2==0)
      buffer[7-i]='0';
    else
      buffer[7-i]='1';
    c=c>>1;
  }
  for(i=0;i<8;i++){
    bufferLecture[pointeurBL] = buffer[i];
    pointeurBL++;
    if(pointeurBL==80){
      ecritClair();
      pointeurBL=0;
    }
  }
}

void ecrire(int b,int l){
  printf("%d,%d,",b,l);
  int ll = l;
  int i,tmp;
  tmp=0;
  if(l>64){
	for(i=65;i<104;i++){
		if(tableau[i][0][0]<l)tmp=i;
		if(tableau[i][0][0]==l){
			l=i;
			break;
		}
	}
  }
  if(tmp!=0)l=tmp;
  for(i=0;tableau[l][b+1][i]!=-1;i++){
    printf("%d[%d]",tableau[l][b+1][i],pointeurBE);
    remplirBufferEcriture(tableau[l][b+1][i]);
  }
  if(tmp!=0)ecrire(b,ll-tableau[tmp][0][0]);
  printf("\n");
}

void compter(){
  int i;
  for(i=0;i<8;i++){
    if(buffer[i]=='0'){
      if(bit==0)longueur++;
      else{
        ecrire(bit,longueur);
        bit=0;longueur=1;
      }
    }
    else{
      if(bit==0){
        ecrire(bit,longueur);
        bit=1;longueur=1;
      }
      else longueur++;
    }
  }
}

void flush(){
  ecrire(bit,longueur);
  int i;
  if(pointeurBE<8)
	for(i=0;i<8;i++)
	  remplirBufferEcriture(0);
}

void flushBL(){
  ecritClair();
}

void afficherCompresse(char * ff){
	printf("%s\n",ff);
	FILE * sor;
	sor = fopen(ff, "r");
	char c;
	int i;
	c = fgetc(sor);
	while (c!=EOF){
		remplirBuffer(c);
		for(i=0;i<8;i++){
			printf("%c",buffer[i]);
		}
		printf("\n");
		c=fgetc(sor);
	}
}

void compresser(char * fichier){
  afficherCompresse(fichier);
  bit = 0; //on commence par lire un paquet de 0
  longueur = 0; //au debut le paquet est vide
  pointeurBE=0;
  compteur=0;
  char c, lectureok;
  char fichierfax[80];
  strcpy(fichierfax,fichier);
  sortie = fopen(strcat(fichierfax,".fax"), "w");
  entree = fopen(fichier, "r");
  if(entree==NULL)printf("null");
  c = fgetc(entree);
  int compteurlu=0;
  while (c!=EOF){
    compteurlu++;
    //printf("%c\n",c);
    remplirBuffer(c);
    c=fgetc(entree);
    compter();
  }
  flush();
  fclose(entree);
  fclose(sortie);
  printf("{%d octets lus}\n",compteurlu);
  printf("{%d octets ecrits}\n",compteur);
  printf("taux : %d%\n",100*compteur/compteurlu);
  afficherCompresse(fichierfax);
}

void decompresser(char * fichier){
  entree = fopen(fichier, "r");
  char sorti[80];
  strncpy(sorti,fichier,strlen(fichier)-4);
  sorti[strlen(fichier)-4]='.';
  sorti[strlen(fichier)-3]='f';
  sorti[strlen(fichier)-2]='\0';
  printf("%s,%d\n",sorti,strlen(sorti));
  sortie = fopen(sorti, "w");
  pointeurBL=0;
  compteur=0;
  couleurActuelle=0;
  pointeurBF = 0;
  initialiserBT();
  char c;
  c = fgetc(entree);
  while (c!=EOF){
    remplirBufferLecture(c);
    c=fgetc(entree);
  }
  flushBL();
  fclose(entree);
  fclose(sortie);
}

int main(int argc, char ** argv){
  if(argv[1][1]=='c')compresser(argv[2]);
  if(argv[1][1]=='d')decompresser(argv[2]);
}

