
#pragma once
#ifndef saisieMR_deja
#define saisieMR_deja
#include <iostream>
#include <limits>
#include <string>
//#include <fstream>

using namespace std;

//const int maxInt = numeric_limits<int>::max();

#define bulle "\n______  _______________________________\n      |/\n"
#define lapin " (\\_/)\n( . .)\nc(\")(\")\n"

/*       (\_/)   fonction
        ( . . ) /
###########################################*/


/*       (\_/)   classe
        ( . . ) /
###########################################*/
//petit exemple pour surcharger les streams << >>
//class strstr
//{
//  string buffer;
//public:
//    friend ostream& operator<< (ostream &out, string &ligne)
//  {
//      out << ligne;
//      return out;
//  }
//    friend istream& operator>> (istream &in, string &ligne)
//  {
//      in >> ligne;
//      return in;
//  }
//  strstr & operator << (string & ligne)
//  {
//      return *this;
//  }
//  strstr & operator >> (string & ligne)
//  {
//      return *this;
//  }
//};



/*  (\_/) saisie
___( . . )_/________________
la saisie du clavier avec
validation et message.
Ici je fait usage de:
-Classe avec inheritance
-Template et polymorphisme
-surcharge d'operateur
on peut facilement les comparers
au foncteur a quelque différence
pres.
__________________________*/

/*  classe de base
 _______________________
 c'est la class mere de
 toute celle qui suivront
 dans la saisie
 _____________________*/
template <class T>
class entree{
public:
    string msg;             //message utilisateur
    entree() {}             //constructeur
    entree(string message);     //constructeur , donné lui le message à la saisie
    entree& operator >> (T& sortie);        //surcharge d'operateur stream sortie
    T operator () ();                   //surcharge d'operateur fonctionnel
    void vider();            //vider le buffer de cin
    virtual T fonction();    //polymorphisme, elle est là que pour être surchargé
};

template <class T>
entree<T>::entree(string message)  //constructeur , donné lui le message à la saisie
{
    msg = message;
}

template <class T>
entree<T>& entree<T>::operator >> (T& sortie)     //surcharge d'operateur stream sortie
{
    sortie = fonction();            //permet l'usage telque saisie >> variable
    return *this;
}

template <class T>
T entree<T>::operator () ()                    //surcharge d'operateur fonctionnel
{
    return fonction();              //permet l'usage telque variable = saisie
}

template <class T>
void entree<T>::vider()            //vider le buffer de cin
{
    cin.clear();                    //vider les flags
    cin.seekg(0,ios_base::end);     //traverse tout le buffer
    if (!cin.fail())
        cin.ignore(numeric_limits<int>::max());         //vider le buffer
    else
        cin.clear();                //vider les flags
}

template <class T>
T entree<T>::fonction()    //polymorphisme, elle est là que pour être surchargé
{
    return 0;
}

/*  foncteur de saisie d'un nombre float ou int
 _______________________
 avec les templates, je
 peux avoir un seul code
 pour plusieurs type de
 donnée semblable.
 A chaque initialisation
 je doit fournire le <type>
 et le compilateur creera
 une classe en fonction
 _____________________*/

template <class nombre>                         //avec les templates, une seule classe et toute sorte de type
class saisie: public entree <nombre>                //elle dérive d'entree et lui donne le meme type
{
public:
    saisie(string message):entree<nombre>(message) { }   //constructeur , appel le constructeur parent
    nombre fonction();                          //polymorphisme, ici que l'objet change
};

template <class nombre>
nombre saisie<nombre>::fonction()                           //polymorphisme, ici que l'objet change
{
    nombre entier;              //variable temporaire du <type> demandé pour la saisie
    do
    {
        entree<nombre>::vider();                //vider le buffer
        cout << entree<nombre>::msg;    //afficher le message
        cin >> entier;          //saisie d'un nombre
    }while (cin.fail());        //tanque ce n'est pas reussie
    return entier;
}

/*  foncteur de saisie d'entier positif
 _______________________*/
template <>                                                 //template spécialisé unsigned int, une exception avec un type spécifique
class saisie<unsigned int>:public entree<unsigned int>      //meme classe mais avec des modifications
{
public:
    saisie(string message):entree<unsigned int>(message) { }                //constructeur, appel le constructeur parent
    unsigned int fonction();                                    //polymorphisme
};

unsigned int saisie<unsigned int>::fonction()                                 //polymorphisme
{
    int entierPositif;                  //entier temporaire pour la saisie
    do
    {
        entree<unsigned int>::vider();                        //vider le buffer
        cout << entree<unsigned int>::msg;            //afficher le message
        cin >> entierPositif;           //saisie d'un nombre
    }while (cin.fail() ||
            (signed int)entierPositif <= 0);    //tanque ce n'est pas reussie, ou que le nombre n'est pas positif
    return (unsigned int)entierPositif; //retyper en nombre non signer
}
/*  foncteur de saisie de string
 _______________________*/
template <>                                 //template spécialisé unsigned int, une exception avec un type spécifique
class saisie<string>:public entree<string>  //cette classe prend en charge les strings
{
public:
    saisie(string message):entree<string>(message) { }  //constructeur
    string fonction();                          //polymorphisme
};

string saisie<string>::fonction()                           //polymorphisme
{
    string ligne;                           //string temporaire pour la saisie
    do
    {
        vider();                        //vider le buffer
        cout << msg;            		//afficher le message
        getline(cin,ligne);             //prendre une ligne dans le cin
    }while(ligne == "");                //recommencer si elle est vide
    return ligne;                       //retourner la ligne
}

/*  foncteur de saisie d'un tableau char[]
 _______________________*/
//template <>                             //template specialisé
//class saisie<char*,_qty>:public entree<char*>  //avec le type char[]
//{
//	char _buffer[_qty];
//public:
//    saisie(string message):entree<char*>(message) { }            //constructeur
//    saisie(string message, char *liste);               //constructeur avec validation
//    char * fonction();
//};
//
//char * saisie<char*,int _qty>::operator()()
//{
//	char choix = 0;
//	int i=0;
//	vider();              //vider le buffer
//	cout << msg;    //afficher le message
//	while (choix != 13 && i<_qty)			//tant que la touche enter n'est pas touché
//		_buffer[i++] = cin.get();      //saisire le charactere
//	return & _buffer;
//}



/*  foncteur de saisie d'un seul charactere
 _______________________*/
template <>                             //template specialisé
class saisie<char>:public entree<char>  //avec le type char
{
    string validation;                  //variable interne privé, liste des charactere autorisé
    bool dansLaListe(char choix);       //vérification de la présence d'un charactere dans la liste (non sensible a la case)
public:
    saisie(string message):entree<char>(message) { }            //constructeur
    saisie(string message, string liste);               //constructeur avec validation
    char fonction();
};

bool saisie<char>::dansLaListe(char choix)        //vérification de la présence d'un charactere dans la liste (non sensible a la case)
{
    for (unsigned int i=0;i<validation.length();i++)        //chaque charactere de la liste
        if (toupper(choix) == toupper(validation[i]))       //s'il sont pareil en majuscule
            return true;                                    //alors c'est vrai
    return false;
}

saisie<char>::saisie(string message, string liste)                //constructeur avec validation
{
    validation = liste;         //stocker la liste
    msg = message;              //et le message
}
char saisie<char>::fonction()
{
    char choix;
    if (validation == "")       //s'il n'y a pas de validation, ne prendre qu'un charactere
    {
        vider();                //vider le buffer
        cout << msg;    //afficher le message
        choix = cin.get();      //saisire le charactere
    }
    else                        //autrement
    {
        do
        {
            vider();                //vider buffer
            cout << msg;    //afficher message
            choix = cin.get();      //saisir le charactere
        }while(!dansLaListe(choix)); //tanque la verification avec la liste authorisé ne donne pas vrai
    }
    return choix;
}

/*  foncteur de saisie d'un seul charactere sur deux avec retour booleen
 _______________________*/
template <>                             //template spécialisé
class saisie<bool>:public entree<bool>  //avec les données booleen
{
    char vrai,          //le charactere qui donnera vrai
         faux;          //le charactere qui donnera faux
public:
    saisie(string message,char v, char f);  //constructeur, prend les deux charactere vrai et faux
    bool fonction();                    //polymorphise
};

saisie<bool>::saisie(string message,char v, char f):entree<bool>(message) //constructeur, prend les deux charactere vrai et faux
{
    vrai=toupper(v);
    faux=toupper(f);
}

bool saisie<bool>::fonction()                 //polymorphise
{
    char choix;                 //character temporaire pour la saisie
    do
    {
        vider();                //vider le buffer à chaque fois
        cout << msg;    //afficher le message
        choix = toupper(cin.get());     //saisire
    }while(choix != vrai && choix != faux); //tanque ce n'est pas un des deux caracteres demandé
    return choix == vrai;       //retourne la valeure booleen du choix
}
/*  foncteur de saisie de clavier NULL
 _______________________*/
template <>                             //template spécialisé
class saisie<void>:public entree<bool>  //si la saisie est de type void, elle héritera d'entree en type bool
{
public:
    saisie(string message):entree<bool>(message) { }    //constructeur
    bool fonction ();                           //polymorphisme
};

bool saisie<void>::fonction ()                            //polymorphisme
{
    cout << msg;                //afficher le message
    vider();                    //vider le buffer
    cin.ignore(numeric_limits<int>::max(),'\n');    //attendre que l'utilisateur appuis sur entrer
    return true;                //retourner true
}


/*       (\_/)   fini
        ( . . ) /
###########################################*/
#endif
