#!/bin/bash

#On saute quelques lignes 
echo -e "\n\n\n\n\n"
clear


# On teste le bon nombre d'arguments
if [ $# -ne 1 ] 
then
        echo -e "\n\n==============================="
        echo "=== ERREUR DANS LA COMMANDE ==="
        echo -e "===============================\n"
        echo -e "La commande est :  \"./lancer fichierCode.cpp\"\n\n"
        exit 1
fi

# On teste si le fichier existe
if [ ! -f $1 ]
then
        echo -e "\n\n==============================="
        echo "=== ERREUR DANS LA COMMANDE ==="
        echo -e "===============================\n"
        echo -e "Le fichier de code n'existe pas\n\n"
        exit 2
fi

# Deux manières de compiler, avec ou sans la SDL.
# Pour savoir si la SDL existe, on teste si 
FichierIncludeSDL="/usr/include/SDL/SDL.h"
CompilationAvecSDL=false

#Si le fichier d'include de la SDL existe
if [ -f $FichierIncludeSDL ] 
then
	CompilationAvecSDL=true
fi





# On cree le fichier tmp.cpp contenant le fichier iutv.h et le code source
echo "#include <cmath>     //Pour utiliser abs(float), abs(double), etc
#include <iostream>  //Pour cin et cout
#include <string>    //Pour les strings
#include <cstdlib>   //Pour utiliser abs(int)
#include <sstream>   //Pour les conversions string/nombre
#include <cctype>    //Pour utiliser tolower et toupper
#include <algorithm> //Pour utiliser transform
#include <cstdio> //Pour getchar
#include <algorithm>    // std::count_if
#include <utility>" > tmp.cpp







echo "#include<math.h>


using namespace std;







#define cout (cout << boolalpha) //Redefinition de cout pour afficher les booleens sous forme litterale










template <class T> void print_(T &&arg) { cout << arg; }
template <class T, class ... Args>
   void print_(T && val, Args &&... args)
   {
      print_(std::forward<T>(val));
      print_(std::forward<Args>(args)...);
   }
template <class ... Args>
   void affichage(Args &&... args)
   {
      
      print_(std::forward<Args>(args)...);
   }
/*!
 * \fn int size(string s)
 *
 * Fonction retournant le nombre de caractères d'un string
 */
int size(string s) {return (int) s.size();}

int string2int(string s) 
{ int tmp; stringstream st; st << s; st >> tmp; return tmp; 
}

float string2float(string s)
{
    float tmp; stringstream st; st << s;    st >> tmp;  return tmp;
}

/*!
 *  \fn double string2double(string s)
 *
 *  Transforme une chaîne de caractères en un nombre flottant double precision
 *
 *  \param s : chaîne de caractères 
 */
double string2double(string s)
{
    float tmp;
    stringstream st; 
    st << s;
    st >> tmp;
    return tmp;
}

/*!
 *  \fn string float2string(float f)
 *  Transforme un nombre flottant en une chaîne de caractères
 *
 *  \param f : nombre flottant  
 */
string float2string(float f)
{
  ostringstream os;
  os << f;
  return os.str();
}

/*!
 *  \fn string double2string(double f)
 *
 *  Transforme un nombre flottant double precision en une chaîne de caractères
 *
 *  \param f : nombre flottant double precision 
 */
string double2string(double f)
{
  ostringstream os;
  os << f;
  return os.str();
}

/*!
 *  \fn string int2string(int f)
 *
 *  Transforme un nombre entier en une chaîne de caractères
 *
 *  \param f : nombre entier
 */
string int2string(int f)
{
  ostringstream os;
  os << f;
  return os.str();
}

//Pour la conversion minuscules/majuscules
struct my_tolower
{ 
    char operator()(char c) const 
    {
        return (char) std::tolower(static_cast<unsigned char>(c));
    } 
};
 
struct my_toupper
{ 
    char operator()(char c) const 
    {
        return (char) std::toupper(static_cast<unsigned char>(c));
    } 
};

/*!
 *  \fn string lower(string s)
 *
 *  Retourne la chaîne de caractères passee en paramètre en lettres minuscules
 *
 *  \param s : chaîne de caractères 
 */
string lower(string s)
{
    string tmp = s;
    std::transform(tmp.begin(), tmp.end(), tmp.begin(), my_tolower());
    return tmp; 
}

/*!
 *  \fn string upper(string s)
 *
 *  Retourne la chaîne de caractères passee en paramètre en lettres majuscules
 *
 *  \param s : chaîne de caractères 
 */
string upper(string s)
{
    string tmp = s;
    std::transform(tmp.begin(), tmp.end(), tmp.begin(), my_toupper());  
    return tmp;
}


/*!
 *  \fn char lower(char c)
 *  Retourne le caractère minuscule associe au caractère passe en paramètre
 *  \param c : caractère
 */
char lower(char c)
{
    return (char) tolower(c);//Car tolower retourne un int, pas un char (donc pour l'affichage d'un caractère, il faut un cast)
}

/*!
 *  \fn char upper(char c)
 *
 *  Retourne le caractère majuscule associe au caractère passe en paramètre
 *
 *  \param c : caractère
 */
char upper(char c)
{
    return (char) toupper(c);//Idem, toupper renvoit un int
}

/*!
 *  \fn bool saisie(string & str, int maxCar = 256)
 *
 *  Permet de lire une chaîne au clavier. Insère au plus maxCar - 1 caractères dans str.
 *  Retourne true s'il y a moins de maxCar-1 caractères lus dans la saisie
 *
 *  \param str : chaîne de caractères contenant la saisie à la fin
 *  \param maxCar : nombre de caractères au plus dans la chaîne à la fin (en comptant \0, donc au plus (maxCar-1) caractères affichables
 */
bool saisie(char * str, int maxCar = 256)
{
    bool ok = true; 
    int nbCarLus = 1;
    string tmp=\"\";
    char c=(char) getchar();
    while(c!='\n')
    {
        if(nbCarLus < maxCar)
        {
            tmp+=c;
            nbCarLus++;
        }
        else
            ok = false;
        c = (char) getchar();
        
    }
    unsigned int i = 0;
    while(i < tmp.size())
    {
        str[i] = tmp[i];
        i++;
    }
    str[i] = '\0';
    return ok;
}
/*!
 *  \fn bool saisie(string & str, int maxCar = 256)
 *
 *  Permet de lire une chaîne au clavier. Insère au plus maxCar - 1 caractères dans str.
 *  Retourne true s'il y a moins de maxCar-1 caractères lus dans la saisie
 *
 *  \param str : chaîne de caractères contenant la saisie à la fin
 *  \param maxCar : nombre de caractères au plus dans la chaîne à la fin (en comptant \0, donc au plus (maxCar-1) caractères affichables
 */
bool saisie(string & str, int maxCar = 256)
{
    bool ok = true; 
    int nbCarLus = 1;
    string tmp=\"\";
    char c= (char) getchar();
    while(c!='\n')
    {
        if(nbCarLus < maxCar)
        {
            tmp+=c;
            nbCarLus++;
        }
        else
            ok = false;
        c = (char) getchar();
        
    }
    str = tmp;
    return ok;
}

bool saisie(char & val)
{
    string tmp;
    saisie(tmp);
    if(tmp.size() < 1)
        return false;
    val = tmp.at(0);
    return true;
}

/*!
 *  \fn bool clavier(int & entier, int maxCar = 256)
 *
 *  Permet de lire un nombre au clavier. Insère au plus maxCar - 1 caractères dans str.
 *  Retourne true s'il y a moins de maxCar-1 caractères lus dans la saisie et la valeur saisie est un nombre
 *
 *  \param entier : int contenant la saisie à la fin
 *  \param maxCar : nombre de caractères au plus dans la chaîne à la fin (en comptant \0, donc au plus (maxCar-1) caractères affichables
 */
bool saisie(int & entier, int maxCar=256)
{
    entier = 0; //Valeur par defaut (en cas de problème de lecture)
    string tmp;
    bool ok = saisie(tmp,maxCar);//On lit la chaîne tmp
    
    //On verifie que la chaîne est de type \"^ *-?[0-9]\" (s'il y a une autre erreur, elle est attrapee dans la suite par le stringstream.good()
    unsigned int i=0;
    while(i < tmp.size() && tmp[i] == ' ')
        i++;
    if(i == tmp.size() )
        return false;
    if(tmp[i]=='-')
        i++;
    if(i == tmp.size() )
        return false;   
    if( tmp[i] < '0' or tmp[i] > '9')
        return false; 
        
    //Conversion
    stringstream st; 
    st << tmp;
    st >> entier;
    
    return ok && !st.good() ;   
}

/*!
 *  \fn bool clavier(float & reel, int maxCar = 256)
 *
 *  Permet de lire un nombre au clavier. Insère au plus maxCar - 1 caractères dans str.
 *  Retourne true s'il y a moins de maxCar-1 caractères lus dans la saisie et la valeur saisie est un nombre
 *
 *  \param reel : float contenant la saisie à la fin
 *  \param maxCar : nombre de caractères au plus dans la chaîne à la fin (en comptant \0, donc au plus (maxCar-1) caractères affichables
 */
bool saisie(float & reel, int maxCar=256)
{
    reel = 0.; //Valeur par defaut (en cas de problème de lecture)
    string tmp;
    bool ok = saisie(tmp,maxCar);//On lit la chaîne tmp
    
//  //On verifie que la chaîne est de type \"^ *-?.?[0-9]\" (s'il y a une autre erreur, elle est attrapee dans la suite par le stringstream.good()
    unsigned int i=0;
    while(i < tmp.size() && tmp[i] == ' ')
        i++;
    if(i == tmp.size() )
        return false;
    if(tmp[i]=='-')
        i++;
    if(i == tmp.size() )
        return false;       
    if(tmp[i]=='.')
        i++;
    if(i == tmp.size() )
        return false;       
    if( tmp[i] < '0' or tmp[i] > '9')
        return false; 
        
    //Conversion
    stringstream st; 
    st << tmp;
    st >> reel;
    
    return ok && !st.good() ;   
}

/*!
 *  \fn bool clavier(double & reel, int maxCar = 256)
 *
 *  Permet de lire un nombre au clavier. Insère au plus maxCar - 1 caractères dans str.
 *  Retourne true s'il y a moins de maxCar-1 caractères lus dans la saisie et la valeur saisie est un nombre
 *
 *  \param reel : double contenant la saisie à la fin
 *  \param maxCar : nombre de caractères au plus dans la chaîne à la fin (en comptant \0, donc au plus (maxCar-1) caractères affichables
 */

bool saisie(double & reel, int maxCar=256)
{
    reel = 0.; //Valeur par defaut (en cas de problème de lecture)
    string tmp;
    bool ok = saisie(tmp,maxCar);//On lit la chaîne tmp
    
//  //On verifie que la chaîne est de type \"^ *-?[.0-9]\" (s'il y a une autre erreur, elle est attrapee dans la suite par le stringstream.good()
    unsigned int i=0;
    while(i < tmp.size() && tmp[i] == ' ')
        i++;
    if(i == tmp.size() )
        return false;
    if(tmp[i]=='-')
        i++;
    if(i == tmp.size() )
        return false;       
    if(tmp[i]=='.')
        i++;
    if(i == tmp.size() )
        return false;       
    if( tmp[i] < '0' or tmp[i] > '9')
        return false; 
        
    //Conversion
    stringstream st; 
    st << tmp;
    st >> reel;
    
    return ok && !st.good() ;   
}

bool saisie(bool &var)
{
  string tmp;
  saisie(tmp);
  if(tmp==\"true\")
  {
    var = true;
    return true;
  }
  var = false;
  return tmp==\"false\";
}

int intAlea(int min, int max)
{
    if(min >= max)
        return -1;  
   return rand()%(max-min) +min;
}

double doubleAlea(double min, double max)
{
    if(min >= max)
        return -1;
  return ( rand()/(double) RAND_MAX ) * (max-min) + min;
}

void initAlea()
{
    srand((unsigned int)time(NULL));
}

void initAlea(int graine)
{
    srand( (unsigned int) graine);
}" >> tmp.cpp


if  [ "$CompilationAvecSDL" == "true" ] 
then
echo "
/** 
 * Gestion de la tortue
 * KHAFIF
 * Modification juin 2016
 */

#include <SDL/SDL.h>
#define DIM_X 600
#define DIM_Y 600



    // la constante de conversion de degres en gradient
    double convDegGrad = 0.0174533;

    /**
     * les coordonnées courante de la tortue
     */
     int old_x, old_y;  //
     int new_x, new_y;

    /**
     * la direction de la tortue que pointe le nez de la tortue
     */
         int dir;

    /**
     * Etat du crayon de la tortue
     */

    /**
     * crayon (boolean)
     * true : baissé (par défaut)
     * false : levé
     */


     bool crayon=true;

    /**
     * coul : couleur du tracé de la tortue
     */
     string couleur;


/**
 * bacASable contient l'adresse de la surface où dessinera la tortue
 */
SDL_Surface *bacASable=NULL;




 /*! Permet d'attendre la fermeture de la fenêtre
 * graphique pour quitter le programme 
 */

void pause(){
  int continuer = 1;

  SDL_Event event;

  while(continuer){
    SDL_WaitEvent(&event);

    switch(event.type){
      case SDL_QUIT :
      continuer = 0;}
    }
}



/*!
 *  \fn Uint32 convertCouleur(string couleur)
 *
 *  Permet de convertir une couleur (string) en une valeur de
 *  couleur de type Uint32.
 *  Retourne la couleur de type Uint32
 *
 *  \param couleur : string contenant la couleur parmi rouge, vert, bleu, blanc et noir
 */
Uint32 convertCouleur(string couleur){

  string coul = lower(couleur);

  if (coul==\"rouge\")
    return SDL_MapRGB(bacASable->format,255,0,0);
  else if (couleur==\"vert\")
    return SDL_MapRGB(bacASable->format,0,255,0);
  else if (coul==\"bleu\")
    return SDL_MapRGB(bacASable->format,0,0,255);
  else if (coul==\"blanc\")
    return SDL_MapRGB(bacASable->format,255,255,255);
  else if (coul==\"noir\")
    return SDL_MapRGB(bacASable->format,0,0,0);

  return SDL_MapRGB(bacASable->format,255,255,255);

}



/*!
 * Permet d'initialiser la tortue ainsi que la fenêtre graphique :
 * - la taille de la fenetre graphique est de 600 pixels (DIM_X) en largeur
 * et 600 pixels (DIM_Y) en hauteur
 * - la tortue est positionnée au milieu de son bac à sable
 * - la tortue regarde vers le haut
 */

void initTortue(){

    /**
      * Initialisation de la video
      */
      SDL_Init(SDL_INIT_VIDEO);


     /**
      * Allocation de la surface de travail avec une profondeur de 32 bits pour 
      * les couleurs
      * SDL_SWSURFACE : l'espace mémoire est alloué dans la mémoire vide de l'ordinateur
      */
     bacASable = SDL_SetVideoMode(DIM_X, DIM_Y, 32, SDL_SWSURFACE);
   

     if (bacASable == NULL) {
         exit(EXIT_FAILURE);
     }

    /**
     * stringation de la surface de travail en en noir
     */
     SDL_FillRect(bacASable, NULL, convertCouleur(\"blanc\"));



    /**
     * Mise à jour de l'ecran
     */
     SDL_Flip(bacASable);




    /**
     * A l'initialisation, la tortue se situe au milieu de sa surface de dessin
         *
     */
     old_x = DIM_X/2;
         old_y=DIM_Y/2;
     new_x = old_x;
         new_y = old_y;

    /**
     * Elle regarde en haut
     */
         dir=90;

    /**
     * Son crayon est levé
     */
         crayon = true;

    
    /**
     * La couleur de tracé par défaut est noir
     */
     couleur = \"noir\";


         SDL_WM_SetCaption(\"Farida attend vos ordres !\", NULL);
    }




/*!
 * Fermeture de la tortue
 */
void fermerTortue(){
    SDL_Quit();
}




/*!
 * Permet de lever le crayon, la tortue ne dessine pas pendant son déplacement
 */
void leverCrayon(){
    crayon = false;
}

/*!
 * Permet de baisser le crayon, la tortue dessine pendant son déplacement
 */
void baisserCrayon(){
    crayon = true;
}

/*!
 * Change la couleur de tracé de la tortue.
 * Les couleurs possibles (de type string) sont rouge, vert, bleu, blanc et noir
 * \param coul : (string) couleur pour les futurs tracés
 */
void changerCouleur(string coul)
    {
        couleur = coul;
    }





/*!
 *  \fn void setPixel(int x, int y, string coul)
 *
 *  Permet de tracer un point sur l'écran avec une couleur donné
 *
 *  \param x : int contenant l'abscisse du point
 *  \param y : int contenant l'ordonné du point
 *  \param coul : string contenant la couleur de tracé du point
 */
void setPixel(int x, int y, string coul)
{
    if(x>=0 && y>=0)
  *((Uint32*)(bacASable->pixels) + x + y * bacASable->w) = convertCouleur(coul);
  SDL_Flip(bacASable);
}





/*!
 *  \fn void drawLines(int x1,int y1,int x2,int y2)
 *
 *  Permet de tracer un segment entre les points de coordonnées (x1,y1) et (x2,y2)
 *  \param x1 : int abscisse du point de départ
 *  \param y1 : int ordonnée du point de départ
 *  \param x2 : int abscisse du point d'arrivée
 *  \param y2 : int ordonnée du point d'arrivée
 */
void drawLines(int x1,int y1,int x2,int y2)
{
  double x = x2 - x1;
  double y = y2 - y1;
  double length = sqrt( x*x + y*y );

  double addx = x / length;
  double addy = y / length;

  x = x1;
  y = y1;

  for(double i = 0; i < length; i += 1)
  {
    setPixel((int)x, (int)y, couleur);
    x += addx;
    y += addy;
  }
  SDL_Flip(bacASable);
}



/*!
 *  \fn void avancer(int dist)
 *
 *  Permet de faire avancer la tortue de dist pixel(s) dans la direction courante
 *  \param dist : (int) distance en pixel à parcourir par la tortue
 */
void avancer(int dist)
{
  new_x = (int) round(old_x+dist*cos(convDegGrad*(dir+180)));
  new_y = (int) round(old_y+dist*sin(convDegGrad*(dir+180)));

  if (new_x<0)
    new_x = 0;
  if (new_x>DIM_X)
    new_x = DIM_X;

 if (new_y<0)
    new_y = 0;
  if (new_y>DIM_Y)
    new_y = DIM_Y;

  if (crayon){
    drawLines(old_x, old_y, new_x,new_y);
  }

  old_x = new_x;
  old_y = new_y;
}


/*!
 *  \fn void droite(int ang)
 *  Permet de faire tourner la tortue dans le sens des aiguille d'une montre de
 *  ang degrés
 *  \param ang : angle de rotation en degres
 */
 void droite(int ang)
 {
  dir = (dir + ang) % 360;
 }

/*!
 *  \fn void gauche(int ang)
 *  Permet de faire tourner la tortue dans le sens inverse des aiguille d'une montre de
 *  ang degrés
 *  \param ang : angle de rotation en degres
 */ 
void gauche(int ang)
{   
  dir = (dir - ang) % 360;
}




/*!
 *  \fn void positionnerTortue(int x, int y)
 *
 *  Permet de déplacer la tortue à la position de coordonnées (x,y).
 *  \param x : int abscisse du point où doit se trouver la tortue
 *  \param y : int ordonnée du point où doit se trouver la tortue
 */
void positionnerTortue(int x, int y)
{
  if (x<0 || x>DIM_X)
    return;

  if (y<0 || y>DIM_Y)
    return;

  // leverCrayon();
  old_x = x;
  old_y= y;
  new_x=old_x;
  new_y = old_y;
  dir = 90;
}

" >> tmp.cpp
fi


cat $1 >> tmp.cpp



if  [ "$CompilationAvecSDL" == "true" ] 
then




#On compile le fichier tmp.cpp (On stocke les messages d'erreurs pour pouvoir les afficher au bon moment)
#Liste des options : 
#   -Wfatal-errors : la compilation s'arrête à la première erreur
#   -Wconversion : Warnings pour les erreurs de conversion (double to int)
#   -Wunused-parameter : warning si un paramètre de fonction n'est pas utilise
g++ -Wall -Wfatal-errors -Wconversion -Wunused-parameter -std=c++11 tmp.cpp -lSDL 2>err.log 

#Si le programme n'a pas pu être compile
if [ $? -ne 0 ]; then
        # On affiche les erreurs et on quitte le script
        echo -e "\n\n============================"
        echo "=== ERREURS DANS LE CODE ==="
        echo "============================"
        #cat err.log
        awk -F ":" '{
    if(NF != 5)
    {
        $1 = "";
        print $0;
    }
    else
    {
        if($4==" error")
            $1 = "Erreur ligne";
        else
            $1 = "Warning ligne";
        $2 = $2 - 764;
        if($2 >= 0)
        {
            $3 = ":";
            $4 = "";
            print $0;
        }
    }
}' err.log
        echo -e "\n\n"
        rm err.log
        #On supprime le fichier tmp.cpp que l'on vient de creer
        rm tmp.cpp
        exit 3
fi


#Si on a au moins un warning
if [ -s err.log ]; then
        # On affiche les erreurs et on quitte le script
        echo -e "\n\n============================="
        echo "=== WARNINGS DANS LE CODE ==="
        echo "============================="
        #cat err.log
        awk -F ":" '{
    if(NF != 5)
    {
        $1 = "";
        print $0;
    }
    else
    {
        if($4==" error")
            $1 = "Erreur ligne";
        else
            $1 = "Warning ligne";
        $2 = $2 - 764;
        if($2 >= 0)
        {
            $3 = ":";
            print $0;
        }
    }
}' err.log
        echo -e "\n\n"  
    rm a.out
    rm err.log
    rm tmp.cpp
    exit 4
fi

#Fin de la compilation avec SDL
else
	

#On compile le fichier tmp.cpp (On stocke les messages d'erreurs pour pouvoir les afficher au bon moment)
#Liste des options : 
#   -Wfatal-errors : la compilation s'arrête à la première erreur
#   -Wconversion : Warnings pour les erreurs de conversion (double to int)
#   -Wunused-parameter : warning si un paramètre de fonction n'est pas utilise
g++ -Wall -Wfatal-errors -Wconversion -Wunused-parameter -std=c++11 tmp.cpp  2>err.log 

#Si le programme n'a pas pu être compile
if [ $? -ne 0 ]; then
        # On affiche les erreurs et on quitte le script
        echo -e "\n\n============================"
        echo "=== ERREURS DANS LE CODE ==="
        echo "============================"
        #cat err.log
        awk -F ":" '{
    if(NF != 5)
    {
        $1 = "";
        print $0;
    }
    else
    {
        if($4==" error")
            $1 = "Erreur ligne";
        else
            $1 = "Warning ligne";
        $2 = $2 - 416;
        if($2 >= 0)
        {
            $3 = ":";
            $4 = "";
            print $0;
        }
    }
}' err.log
        echo -e "\n\n"
        rm err.log
        #On supprime le fichier tmp.cpp que l'on vient de creer
        rm tmp.cpp
        exit 3
fi


#Si on a au moins un warning
if [ -s err.log ]; then
        # On affiche les erreurs et on quitte le script
        echo -e "\n\n============================="
        echo "=== WARNINGS DANS LE CODE ==="
        echo "============================="
        #cat err.log
        awk -F ":" '{
    if(NF != 5)
    {
        $1 = "";
        print $0;
    }
    else
    {
        if($4==" error")
            $1 = "Erreur ligne";
        else
            $1 = "Warning ligne";
        $2 = $2 - 416;
        if($2 >= 0)
        {
            $3 = ":";
            print $0;
        }
    }
}' err.log
        echo -e "\n\n"  
    rm a.out
    rm err.log
    rm tmp.cpp
    exit 4
fi

fi #Fin de la compilation sans la SDL


#On supprime le fichier tmp.cpp que l'on vient de creer
rm err.log
rm tmp.cpp

# Execution et suppression des fichiers temporaires
#rm err.log
#./a.out 
#rm ./a.out
{ ./a.out; } 2>errExecution.log
if [ -s errExecution.log ]; then
    awk  '{$1=""; $2=""; $3=""; $4=""; $NF=""; print $0;}' errExecution.log
fi
rm errExecution.log
rm ./a.out