#include "tree.h"

void cons_tree(struct node ** ptr_tree, wchar_t val)
{
  *ptr_tree = malloc(sizeof(struct node));
  (*ptr_tree)->val = val;
  (*ptr_tree)->fin = 0;
  (*ptr_tree)->nbr_fils=0;
  (*ptr_tree)->fils = malloc(sizeof(struct node*));
  (*ptr_tree)->fils[0]=NULL;
}

void mk_empty_tree(dico *Dico)
{
  for(int i = 0; i < Dico->taille; i++)
  {
    Dico->tab_ptr_tree[i] = NULL;
  }
}

void init_dico(dico *Dico)
{
  Dico->taille = 26;
  Dico->tab_ptr_tree = malloc(Dico->taille*sizeof(struct node*));
  mk_empty_tree(Dico);
}

void add(struct node **tab_ptr_tree, wchar_t val[],int taille, int fl)
{
  if(tab_ptr_tree[fl]==NULL)cons_tree(&(tab_ptr_tree[fl]),val[0]+97);
  Node* noeudtest = tab_ptr_tree[fl];
  for(int i = 1;i<taille;i++)
    {
      int trouve = -1;
      for(int j=0;j<noeudtest->nbr_fils;j++)
	{
	  if(noeudtest->fils[j]->val==val[i])trouve=j;
	}
      if(trouve==-1)
	{	  
	  //ajouter lettre
	   noeudtest->nbr_fils++;
	   noeudtest->fils = realloc(noeudtest->fils,(noeudtest->nbr_fils)*sizeof(struct node*));
	   cons_tree(&(noeudtest->fils[(noeudtest->nbr_fils)-1]),val[i]);
	   trouve = noeudtest->nbr_fils-1;
	}
      
      noeudtest = noeudtest->fils[trouve];//on jump au noeud suivant
    }
  noeudtest->fin = 1;

}

int size(wchar_t val[])
{
  int cpt = 0;
  while(val!= NULL && val[cpt]!='\0')
    {
      cpt++;
    }
  return cpt;
}

void toLowerCase(wchar_t mot[])
{
  for(int i=0;i<size(mot);i++)
    {
      if((mot[i]<='Z' && mot[i]>='A') || (mot[i]>=192 && mot[i]<=214) || (mot[i]>=216 && mot[i]<=222))mot[i]+=32;
      else if(mot[i]==138|| mot[i]==140 || mot[i]==142) mot[i]+=16;
      else if(mot[i]==159) mot[i]+=96;
    }
}

void splitcarac(dico *Dico,wchar_t message[],wchar_t separateur[])
{
  int first_letter =-1;
  if(message[0]>='a' && message[0]<='z')
  {
    first_letter = (int)message[0]-97;
  }
  else
  {
    for(int i = 26; i < Dico->taille; i++)
    {
      if(Dico->tab_ptr_tree[i]->val == message[0]){first_letter = i;break;}
    }
    if(first_letter == -1)
    {
      first_letter = Dico->taille;
      Dico->taille++;
      Dico->tab_ptr_tree = realloc(Dico->tab_ptr_tree,(Dico->taille)*sizeof(struct node*));
      Dico->tab_ptr_tree[first_letter] = NULL;
      cons_tree(&(Dico->tab_ptr_tree[first_letter]),message[0]);
    }
  }
  
  wchar_t *buffer;
  wchar_t *token = wcstok(message, separateur, &buffer);
  add(Dico->tab_ptr_tree,token,size(token),first_letter);
  if(buffer!=NULL)splitcarac(Dico,buffer,separateur);
}

void load_dico(FILE *fp, dico *Dico, wchar_t separateur[])
{
  wchar_t val[3000];
  
  while(fwscanf(fp, L"%ls",val)==1)
    {
      toLowerCase(val);
      splitcarac(Dico,val,separateur);
    }

    //On peut tester la bonne ou mauvaise terminaison de la lecture
    if(feof(fp))    printf("Fin normal de lecture\n");
    if(ferror(fp))  printf("ERREUR de lecture\n");
}

void free_tree(struct node *ptr_tree)
{
  if(ptr_tree==NULL)return;
  if(ptr_tree->nbr_fils==0){free(ptr_tree->fils);return;}
  for(int i=(ptr_tree->nbr_fils)-1;i>=0;i--)
  {
    free_tree(ptr_tree->fils[i]);
    free(ptr_tree->fils[i]);
  }
  free(ptr_tree->fils);
}

void free_dico(dico Dico)
{
  for(int i=0;i<Dico.taille;i++)
  {
    if(Dico.tab_ptr_tree[i]!=NULL)
    {
      free_tree(Dico.tab_ptr_tree[i]);
      free(Dico.tab_ptr_tree[i]);
    }
  }
  free(Dico.tab_ptr_tree);
}

/*Recherche dans le dictionnaire*/
int find_mot(dico Dico,wchar_t mot[])
{
    if (mot==NULL) {
      return 0;
    }
    if(mot[0]>='0' && mot[0]<='9')return 0;

    int fl =-1;
    if(mot[0]>='a' && mot[0]<='z')
    {
      fl = (int)mot[0]-97;
    }
    else
    {
      for(int i = 26; i < Dico.taille; i++)
      {
        if(Dico.tab_ptr_tree[i]->val == mot[0]){fl = i;break;}
      }
      if(fl == -1)return 1;
    }

    int taille = size(mot);
    if(taille==1 && Dico.tab_ptr_tree[fl]!=NULL)
    {
        if(Dico.tab_ptr_tree[fl]->fin==0)return 1;
        else return 0;//vrais
    }
    if(taille==1 && Dico.tab_ptr_tree[fl]==NULL)return 1;//faux

    struct node *ptr_node = Dico.tab_ptr_tree[fl];
    for(int i=1;i<taille;i++)
    {
        if(ptr_node->nbr_fils==0)return 1;
        for(int k=0;k<(ptr_node->nbr_fils);k++)
        {
            if(ptr_node->fils[k]->val==mot[i])
            {
                ptr_node=ptr_node->fils[k];
                break;
            }
	    else if(k+1==ptr_node->nbr_fils)return 1;
        }
    }

    if(ptr_node->fin==0)return 1;
    else return 0;
}

int find_erreur(dico Dico, FILE *fp,wchar_t separateur[])
{
  wchar_t val[3000];
  int cpt_erreur =0;
  
  while(fwscanf(fp, L"%ls",val)==1)
    {
      toLowerCase(val);
      cpt_erreur += split_text(Dico,val,separateur);
    }

    //On peut tester la bonne ou mauvaise terminaison de la lecture
    if(feof(fp))    printf("Fin normal de lecture\n");
    if(ferror(fp))  printf("ERREUR de lecture\n");

    return cpt_erreur;
}

int split_text(dico Dico,wchar_t message[], wchar_t separateur[])
{  
  if(message[0] == 0)return 0;
  wchar_t *buffer;
  wchar_t *token = wcstok(message, separateur, &buffer);
  int err = find_mot(Dico,token);
  if(buffer!=NULL)err += split_text(Dico,buffer,separateur);

  return err;
}
