#include "fonction.hpp"
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <map>

bool lecture_Grammaire(map<string, vector< vector<string> > > &grammaire, vector<string> &terminaux, vector<string> &non_terminaux, string &name)
{
    map<string, bool> existanceNT;
    map<string, bool> existanceT;
    vector<string> vide;
    ifstream fichier(name.c_str(), ios::in);
    ifstream fichier2(name.c_str(), ios::in);
    if(!fichier) return false;

    string contenu;
    string a, b;
    vector <string> tmp;
    unsigned i;

    while(getline(fichier,contenu) && contenu.size()>0)
    {
        a.erase();
        b.erase();
        for(i=0 ; contenu[i]!= ' ' && i<contenu.size() ; i++)
        {
            a = a + contenu[i];
        }
        //cout << a << " : " ;
        for(i=i+1 ; i<contenu.size() ; i++)
        {
            if(contenu[i] == ' ')
            {
                //cout << b << " " ;
                if(b.size() > 0)
                {
                    if (existanceT[b]){}
                    else
                    {
                        existanceNT[b] = true;
                        terminaux.push_back(b);
                    }
                }
                tmp.push_back(b);
                b.clear();
            }
            else
            {
                b = b + contenu[i];
            }
        }
        if(a.size()>0)
        {
            if(b.size() > 0)
                {
                    if (existanceT[b]){}
                    else
                    {
                        existanceNT[b] = true;
                        terminaux.push_back(b);
                    }
                }

            if (existanceT[a]){}
            else
            {
                existanceT[a] = true;
                non_terminaux.push_back(a);
            }
            //cout << b << endl;
            if(b.size() == 0) b = " ";
            tmp.push_back(b);
            if( !is_in_b(tmp, grammaire[a]))
            {
                grammaire[a].push_back(tmp);
            }
        }
        a.erase();
        b.erase();
        tmp.clear();
        //cout << endl;
    }
    for(int i=terminaux.size()-1 ; i>=0 ; i--)
    {
        if(is_in_b(terminaux[i], non_terminaux)) terminaux.erase(terminaux.begin()+i);
    }
    return true;

}

void print_grammaire(map<string, vector< vector<string> > > &grammaire, vector<string> &terminaux, vector<string> &non_terminaux)
{
    unsigned i,j,k;
    cout << "Les terminaux sont :" << endl << "{";
    for( i=0 ; i<terminaux.size() ; i++)
    {
        if (i != terminaux.size()-1) cout << terminaux[i] << ", ";
        else cout << terminaux[i];
    }
    cout << "}" << endl;
    cout << "Les non-terminaux sont :" << endl << "{";
    for( i=0 ; i<non_terminaux.size() ; i++)
    {
        if (i != non_terminaux.size()-1) cout << non_terminaux[i] << ", ";
        else cout << non_terminaux[i];
    }
    cout  << "}" << endl;
    cout << "La grammaire : " << endl;
    for( i=0 ; i<non_terminaux.size() ; i++)
    {
        cout << non_terminaux[i] << " : ";
        for( j=0 ; j<grammaire[non_terminaux[i]].size() ; j++)
        {

            for ( k=0 ; k<grammaire[non_terminaux[i]][j].size() && grammaire[non_terminaux[i]][j].size() != 0; k++)
            {
                if(grammaire[non_terminaux[i]][j][k]!= " ") cout << grammaire[non_terminaux[i]][j][k] << " " ;
                else cout << "!" << " ";
            }
            if(j != grammaire[non_terminaux[i]].size()-1) cout << " | ";
        }
        cout << endl;
    }
    cout << endl;
}

bool is_in_b(string &a, vector<string> &b)
{
    for(unsigned i=0 ; i<b.size() ; i++)
    {
        if(a==b[i]) return true;
    }
    return false;
}
bool is_in_b(vector<string> &a, vector <vector<string> > &b)
{
    bool test=true;
    for(unsigned i=0 ; i<b.size() ; i++)
    {
        if(a.size() == b[i].size())
        {
            test = true;
            for(unsigned j=0 ; j< a.size() ; j++)
            {
                if(a[j] != b[i][j]) test = false;
            }
            if(test) return true;
        }
    }
    return false;
}
bool is_in_b(vector<string> &a, vector<string> &b)
{
    bool test=true;
    if(a.size() == b.size())
        {
            test = true;
            for(unsigned j=0 ; j< a.size() ; j++)
            {
                if(a[j] != b[j]) test = false;
            }
            if(test) return true;
        }
        return false;
}

void recu_indirect(map<string, vector< vector<string> > > &grammaire, vector<string> &terminaux, vector<string> &non_terminaux, string state)
{
    string tmp_string;
    vector <string> tmp_vector;
    vector <string> non_terminaux_modif;
    vector <vector <string> > tmp_rulls;
    vector <int> to_delet;
    tmp_rulls = grammaire[state];
    for(unsigned i=0 ; i<grammaire[state].size() ; i++)
    {
        if(i>0) non_terminaux_modif.push_back(non_terminaux[i-1]);
        if(is_in_b(grammaire[state][i][0], non_terminaux_modif) && grammaire[state][i][0] != state)
        {
            tmp_string.erase();
            tmp_vector.clear();

            to_delet.push_back(i);
            tmp_string = grammaire[state][i][0];
            grammaire[state][i].erase(grammaire[state][i].begin());
            tmp_vector = grammaire[state][i];
            for(unsigned j=0 ; j<grammaire[tmp_string].size() ; j++)
            {
                tmp_rulls.push_back(tmp_vector);
                tmp_rulls[tmp_rulls.size()-1].insert(tmp_rulls[tmp_rulls.size()-1].begin(), grammaire[tmp_string][j].begin(), grammaire[tmp_string][j].end());
            }
        }
    }
    for(int i=(to_delet.size()-1) ; i>=0 ; i=i-1)
    {
        tmp_rulls.erase(tmp_rulls.begin() + to_delet[i]);
    }
    grammaire[state].clear();
    grammaire[state] = tmp_rulls;
}

void recu_direct(map<string, vector< vector<string> > > &grammaire, vector<string> &terminaux, vector<string> &non_terminaux, string state)
{
    string tmp_string;
    vector <string> tmp_vector;
    vector <string> a;
    a.push_back(" ");
    vector <vector <string> > tmp_rulls;
    vector <int> to_delet;
    tmp_rulls = grammaire[state];
    for(unsigned i=0 ; i<grammaire[state].size() ; i++)
    {
        if(grammaire[state][i][0] == state)
        {
            to_delet.push_back(i);
            tmp_rulls.erase(tmp_rulls.begin());
            grammaire[state][i].erase(grammaire[state][i].begin());
        }
    }
    if(to_delet.size()>0)
    {
        tmp_string = state;
        while(grammaire[tmp_string].size() > 0) tmp_string += "'";
        non_terminaux.push_back(tmp_string);
        for(unsigned i=0 ; i<to_delet.size() ; i++)
        {
            grammaire[tmp_string].push_back(grammaire[state][to_delet[i]]);
            grammaire[tmp_string][grammaire[tmp_string].size()-1].insert(grammaire[tmp_string][grammaire[tmp_string].size()-1].end(), 1, tmp_string);
        }


        grammaire[tmp_string].push_back(a);
        for(int i=to_delet.size()-1 ; i>=0 ; i--)
        {
            grammaire[state].erase(grammaire[state].begin() + to_delet[i]);

        }
        for(unsigned i=0 ; i<grammaire[state].size() ; i++)
        {
            grammaire[state][i].insert(grammaire[state][i].end(), 1, tmp_string);
        }
    }
}

void fact_gauche(map<string, vector< vector<string> > > &grammaire, vector<string> &terminaux, vector<string> &non_terminaux, string state)
{
    vector<string> a, vide;
    vector<int> resultat_tmp;
    vector<int> resultat;
    vide.push_back(" ");
    unsigned x=0, y=0;
    bool test = true;
    while(y!=grammaire[state].size())
    {
        a.push_back(grammaire[state][y][x]);
        test = true;
        resultat_tmp.clear();
        for(unsigned i=0 ; i<grammaire[state].size() ; i++)
        {
            for(unsigned j=0 ; j<grammaire[state][i].size() && j<=x ; j++)
            {
                /*cout << " x :" << j ;
                cout << " | y :" << i << endl;
                cout << a[j] << " : " << grammaire[state][i][j] << endl;*/
                //system("pause");
                if(a[j] != grammaire[state][i][j]) test = false;
            }
            if(test) resultat_tmp.push_back(i);
            //cout << "test : " << resultat_tmp.size() << endl;
        }
        if(resultat_tmp.size() > 0 && x<grammaire[state][y].size()-1) // on cherche a trouver plus
        {
            x ++;
            if(resultat_tmp.size() > 1) resultat = resultat_tmp;
            //cout << "Je passe : " << resultat_tmp.size() << endl;
        }
        else if(resultat.size() == 0) // on a rien
        {
            x=0;
            y++;
            a.clear();
        }
        else // on a win (mais pas totalement
        {
            if(resultat_tmp.size() > 1) resultat = resultat_tmp;
            string tmp_string;

            tmp_string = state;
            //cout << " III" << endl;
            //cout << "size : " << resultat.size() << endl;
            while(grammaire[tmp_string].size())
            {
                tmp_string += "*";
            }
            for(int i=resultat.size()-1 ; i>=0 ; i--)
            {
                for(unsigned j=0 ; j<x ; j++)
                {
                    grammaire[state][resultat[i]].erase(grammaire[state][resultat[i]].begin());
                }
            }
            for(int i=resultat.size()-1 ; i>=0 ; i--)
            {
                if (grammaire[state][resultat[i]].size()>0) grammaire[tmp_string].push_back(grammaire[state][resultat[i]]);
                else grammaire[tmp_string].push_back(vide);
            }
            for(int i=resultat.size()-1 ; i>=0 ; i--)
            {
                grammaire[state].erase(grammaire[state].begin()+resultat[i]);
            }
            a.pop_back();
            grammaire[state].push_back(a);
            grammaire[state][grammaire[state].size()-1].insert(grammaire[state][grammaire[state].size()-1].end(), 1, tmp_string);
            non_terminaux.push_back(tmp_string);
            x=y=0;
            a.clear();
            resultat.clear();
            tmp_string.erase();

        }
    }
}
void desambigueur(string name)
{
    vector<string> terminaux;
    vector<string> non_terminaux;
    map<string, vector< vector<string> > > grammaire;

    if (!lecture_Grammaire(grammaire, terminaux, non_terminaux, name))
    {
        cerr << "ERREUR LECTURE : ouverture fichier" << endl;
        return ;
    }
    nettoyage_de_primptemp(grammaire, terminaux , non_terminaux);
    print_grammaire(grammaire, terminaux, non_terminaux);

    for(unsigned i=0 ; i<non_terminaux.size() ; i++)
    {
        //cout << " ------------" << endl << endl << endl;
        recu_indirect(grammaire, terminaux , non_terminaux, non_terminaux[i]);
        nettoyage_de_primptemp(grammaire, terminaux , non_terminaux);
        //print_grammaire(grammaire, terminaux, non_terminaux);
        //system("pause");
        recu_direct(grammaire, terminaux , non_terminaux, non_terminaux[i]);
        nettoyage_de_primptemp(grammaire, terminaux , non_terminaux);
        //print_grammaire(grammaire, terminaux, non_terminaux);
        //system("pause");
    }
    fact_gauche(grammaire, terminaux , non_terminaux, non_terminaux[0]);
    nettoyage_de_primptemp(grammaire, terminaux , non_terminaux);
    print_grammaire(grammaire, terminaux, non_terminaux);
}

void nettoyage_de_primptemp(map<string, vector< vector<string> > > &grammaire, vector<string> &terminaux, vector<string> &non_terminaux)
{
    for(unsigned i=0 ; i<non_terminaux.size() ; i++)
    {
        for(unsigned j=0 ; j<grammaire[non_terminaux[i]].size() ; j++)
        {
            for(unsigned k=0 ; k<grammaire[non_terminaux[i]][j].size() ; k++)
            {
                if(grammaire[non_terminaux[i]][j].size()>1 && grammaire[non_terminaux[i]][j][k] == " ") grammaire[non_terminaux[i]][j][k].erase(grammaire[non_terminaux[i]][j][k].begin()+k);
            }
        }
    }
}
