#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;
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 bufferfichier dans le fichier de sortie
 **/
void ecrit(){
  //  printf("PBF = %d et %s\n",pointeurBF,bufferfichier); 
  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("bufferise : PBF = %d et %s\n",pointeurBF,bufferfichier); 
  //printf("[%c,%d]",b,l);
  int i;
  for(i=0;i<l;i++){
    bufferfichier[pointeurBF] = b;
    //printf("%c",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("%s\n",buf);
  int i;
  for(i=0;i<110;i++) {
    if(strlen(buf) == taille(tableau[i][1])){
      if(comparer(buf,tableau[i][1])==0){
    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]));
    exit(0);
        //printf("tEE:buf=%s tab[%d][1]=%d\n",buf,i,taille(tableau[i][1]));
        //printf("0,%d\n",tableau[i][0][0]);
        bufferise('0',tableau[i][0][0]);
        return 1;
      }
    }
    if(strlen(buf) == taille(tableau[i][2])){
      if(comparer(buf,tableau[i][2])==0){
    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]));
    exit(0);
        //printf("tEE:buf=%s tab[%d][2]=%d\n",buf,i,taille(tableau[i][2]));
        //printf("1,%d\n",tableau[i][0][0]);
        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:bufferlecture=%s\n",bufferLecture);
  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);
      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);
}

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);
	}
        fclose(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("{%doctets lus}\n",compteurlu);
  printf("{%doctets 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;
  pointeurBF = 0;
  compteur=0;
  initialiserBT();
  char c;
  c = fgetc(entree);
  while (c!=EOF){
    remplirBufferLecture(c);
    c=fgetc(entree);
  }
  flushBL();
  fclose(entree);
  fclose(sortie);
  //afficherCompresse("monfichier.f");
}

int main(int argc, char ** argv){
  compresser(argv[1]);
  //decompresser(argv[1]);
}

