#include <stdio.h>
#include <stdlib.h>



/* --------------------------------------------------- */
/*  Declarations des fonctions et procedures utilisees */ 
/* --------------------------------------------------- */


void creeFichierReels(const char * nomFichier, const double lesElements[], int nb);
/* Preconditions : nomFichier est une chaine de caracteres designant le nom du fichier 
   a creer, lesElements est un tableau contenant nb reels
   Postconditions : le fichier nomFichier contient les nb reels, ecrits en binaire
   comme ils sont representes en memoire vive. Si le fichier existait déjà, son 
   ancien contenu est écrasé. */


void litFichierReels(const char * nomFichier);
/* Preconditions : nomFichier est le nom d'un fichier produit par une machine de meme
   architecture, contenant des reels ecrits en binaire comme ils sont representes en
   memoire vive. 
   Postcondition : affichage du contenu du fichier sur la sortie standard (un reel
   par ligne, ecrit en notation scientifique). */



void triFusion(const char * nomFic);
/* Precondition : le fichier appele nomFic contient des double codes en binaire et a 
   ete produit par une machine de meme architecture que celle qui va executer la
   procedure de tri.
   Postcondition : le fichier appele nomFic contient les memes elements, mais tries.*/  


void eclatement(const char * nomFicX, int lg, \
		const char * nomFicA, const char * nomFicB) ;
/* Precondition : le fichier appele nomFicX contient des monotonies de longueur lg, 
   sauf peut-etre la derniere qui peut etre plus courte
   Postcondition : Les monotonies de nomFicX sont reparties dans des fichiers appeles 
   nomFicA et nomFicB : la premiere monotonie est copiee dans le fichier A, la seconde 
   dans le fichier B, la troisieme dans le A, etc. Si ces fichiers existaient deja, 
   leur contenu est ecrase. Le fichier A peut recueillir une monotonie de plus que le 
   fichier B, et cette derniere monotonie peut etre de longueur inferieure a lg. 
   Si au contraire ficA et ficB recueillent le meme nombre de monotonies, la derniere
   monotonie ecrite dans ficB peut etre de longueur inferieure a lg. */


void fusion(const char * nomFicA, const char * nomFicB, int lg,\
	    const char * nomFicX, int * nbMonoDansX);
/* Preconditions : les fichiers appeles nomFicA et nomFicB contiennent des monotonies 
   de longueur lg. FicA peut contenir une monotonie de plus (eventuellement incomplete) 
   que FicB. Si au contraire FicA et FicB contiennent le meme nombre de monotonies, 
   alors la derniere monotonie de FicB peut etre incomplete.
   Postconditions : le fichier appele nomFicX contient nbMonoApres monotonies de 
   longueur 2*lg, la derniere pouvant etre plus courte. Ces monotonies resultent de 
   la fusion 2 a 2 des monotonies de FicA et de FicB. Si FicX existait deja, son ancien 
   contenu est ecrase. */  




/* ------------------------------------------------------- */
/*  Definitions des fonctions et procedures : A COMPLETER  */ 
/* ------------------------------------------------------- */


int main()
{
  double mesReels[] = {9.5, -0.00033, 56.1, -2.0, 695.84, 5e10, -13.7};

  creeFichierReels("mesReels.bin", mesReels, 7);

  printf("Fichier avant le tri : \n");
  litFichierReels("mesReels.bin");

  triFusion("mesReels.bin");

  printf("Fichier apres le tri : \n");
  litFichierReels("mesReels.bin");


  return 0;
}





void triFusion(const char * nomFic)
{

  int nbMonotonies;
  int longueur = 1;

  char nomA[] = "fichierAnnexeA.bin";
  char nomB[] = "fichierAnnexeB.bin";


  do
    {
      eclatement(nomFic, longueur, nomA, nomB);
      printf("Resultats de l'eclatement : \n");
      printf("Fichier A : \n");
      litFichierReels("fichierAnnexeA.bin");
      printf("Fichier B : \n");
      litFichierReels("fichierAnnexeB.bin");

      fusion(nomA, nomB, longueur, nomFic, &nbMonotonies);
      printf("Resultat de la fusion (nbMono = %d): \n", nbMonotonies);
      litFichierReels(nomFic);

      longueur *= 2;
    } 
  while (nbMonotonies > 1);

}



void eclatement(const char * nomFicX, int lg, \
		const char * nomFicA, const char * nomFicB)
{
  FILE * ficX, * ficA, *ficB;
  int mettreDansFicA = 1;
  int i = 0;
  double elem_lu;

  ficX = fopen(nomFicX, "rb");
  if (ficX == NULL)
    {
      printf("Impossible de lire le fichier %s\n", nomFicX);
      printf("Il s'agit peut-etre d'un probleme de droits d'acces, \n");
      printf("ou peut-etre que le fichier n'existe pas. \n");
      exit(2);
    }
  
  ficA = fopen(nomFicA, "wb");
  if (ficA == NULL)
    {
      printf("Impossible de creer le fichier %s en ecriture\n", nomFicA);
      printf("Il s'agit peut-etre d'un probleme de droits d'acces.\n");
      exit(2);
    }


  ficB = fopen(nomFicB, "wb");
  if (ficB == NULL)
    {
      printf("Impossible de creer le fichier %s en ecriture\n", nomFicB);
      printf("Il s'agit peut-etre d'un probleme de droits d'acces.\n");
      exit(2);
    }


  /* On boucle en fonction de la valeur de retour de fread et non en fonction
     de feof */
  while(fread(&elem_lu, sizeof(double), 1, ficX) == 1)
    {
      if (mettreDansFicA == 1)  fwrite(&elem_lu, sizeof(double), 1, ficA);
      else fwrite(&elem_lu, sizeof(double), 1, ficB);
	
      i++;
      if (i == lg) 
	{
	  if (mettreDansFicA == 1) mettreDansFicA = 0;
	  else mettreDansFicA = 1;
	  i = 0;
	}
    }

  fclose(ficX);
  fclose(ficA);
  fclose(ficB);

}






void fusion(const char * nomFicA, const char * nomFicB, int lg,\
		   const char * nomFicX, int * nbMonoDansX)
{
  FILE * ficA, * ficB, *ficX;
  int nbAtraites, nbBtraites;
  double e1, e2;
  *nbMonoDansX = 0;

  ficA = fopen(nomFicA, "rb");
  if (ficA == NULL)
    {
      printf("Impossible de lire le fichier %s\n", nomFicA);
      printf("Il s'agit peut-etre d'un probleme de droits d'acces, \n");
      printf("ou peut-etre que le fichier n'existe pas. \n");
      exit(2);
    }
  
  ficB = fopen(nomFicB, "rb");
  if (ficB == NULL)
    {
      printf("Impossible de lire le fichier %s\n", nomFicB);
      printf("Il s'agit peut-etre d'un probleme de droits d'acces, \n");
      printf("ou peut-etre que le fichier n'existe pas. \n");
      exit(2);
    }
  

  ficX = fopen(nomFicX, "wb");
  if (ficX == NULL)
    {
      printf("Impossible de creer le fichier %s en ecriture\n", nomFicX);
      printf("Il s'agit peut-etre d'un probleme de droits d'acces.\n");
      exit(2);
    }


 
  while(fread(&e2, sizeof(double), 1, ficB)==1) 
    /* tant qu'il reste des monotonies a fusionner (s'il en reste dans le fichier 2, 
       alors il en reste dans le fichier 1, et celle dans le fichier 1 est de longueur lg) */
    {
      nbAtraites = 0;
      nbBtraites = 0;
      fread(&e1, sizeof(double), 1, ficA);
      do
	{	
	  if (e1 <= e2)
	    {
	      /* write e1 in the output file and update e1 */
	      fwrite(&e1, sizeof(double), 1, ficX);
	      nbAtraites ++;
	      if (nbAtraites < lg)
		{
		  fread(&e1, sizeof(double), 1, ficA);
		}
	    }
	  else
	    {
	      fwrite(&e2, sizeof(double), 1, ficX);
	      nbBtraites ++;
	      if (nbBtraites < lg)
		{
		  if(fread(&e2, sizeof(double), 1, ficB) != 1) nbBtraites = lg;
		  /* cas d'une monotonie finale incomplete dans nomfentree2,
		     on force la condition de sortie du do..while */
		}
	    }
	} while ((nbAtraites < lg) && (nbBtraites < lg));

      if (nbAtraites == lg) 
	{
	  while(nbBtraites <lg)
	    {
	      fwrite(&e2, sizeof(double), 1, ficX);
	      nbBtraites ++;
	      if (nbBtraites < lg)
		{
		  if(fread(&e2, sizeof(double), 1, ficB) != 1) nbBtraites = lg;
		}
	    }	  
	}
      else 
	{
	  while(nbAtraites <lg)
	    {
	      fwrite(&e1, sizeof(double), 1, ficX);
	      nbAtraites ++;
	      if (nbAtraites < lg) fread(&e1, sizeof(double), 1, ficA);
	    }
	}
      
      (*nbMonoDansX) ++;
    }

  /* N'oublions pas l'eventuelle monotonie supplementaire de ficA */
  if (fread(&e1, sizeof(double), 1, ficA)==1)
    {
      (*nbMonoDansX) ++;
      do
	{
	  fwrite(&e1, sizeof(double), 1, ficX);
	}
      while(fread(&e1, sizeof(double), 1, ficA)==1);
    }


  fclose(ficX);
  fclose(ficA);
  fclose(ficB);

}





void creeFichierReels(const char * nomFichier, const double lesElements[], int nb)
{
  FILE * fd = fopen(nomFichier,"wb");
  int i = 0;

  if (fd==NULL)
    {
      printf("Impossible d'ouvrir le fichier %s en écriture \n",nomFichier);
      exit(EXIT_FAILURE);
    }

  for(i=0;i<nb;i++)
    {
      fwrite(&lesElements[i], sizeof(double), 1, fd);
    }

  fclose(fd);
}




void litFichierReels(const char * nomFichier)
{
  double temp;
  FILE * fd = fopen(nomFichier,"rb");
  if (fd==NULL)
    {
      printf("Impossible d'ouvrir le fichier %s en lecture \n",nomFichier);
      exit(EXIT_FAILURE);
    }


  while(fread(&temp, sizeof(double), 1, fd)==1)
    {printf("%e \n",temp);}
 
  fclose(fd);
}







