
from pymongo import MongoClient
import Ela_Spacy as ls
import prj_common as mycommon
from pymongo import ReturnDocument
import inspect
import sys, os
from operator import itemgetter, attrgetter
import GlobalVariable as MYSY_GV

'''
Cette fonction indexe une formation
Par defaut sont pris en compte : 
- le titre et
- la description

'''
def ela_index_class(external_code="", source_field = ""):
    try:

        collection = MYSY_GV.dbname["myclass"]

        if( len(str(source_field)) == 0):
            source_field = 'default'

        for doc in collection.find({"external_code":external_code}):

            # Indexation par defaut : champs TITRE + DESCRIPTION
            if ( str(source_field) == "default" ):
                chaine = doc["title"]+" - "+doc["description"]
                #mycommon.myprint(" external_code = "+str(doc["external_code"])+" ==> "+str(chaine))
                retval = ls.ela_index_record_field(chaine, str(doc["external_code"]), source_field)

                '''
                # Apres indexation, on met a jour la formation pour 
                # mettre le champ "indexe" a 1.
                '''
                if( retval ):
                    # mise à jour du champ "indexed"
                    myobjectif = {}
                    myobjectif['indexed'] = '1'

                    ret_val2 = collection.find_and_modify(query={"external_code":external_code},
                                                        update={"$set": myobjectif}
                                                        )

                    if (ret_val2 and ret_val2['_id']):
                        mycommon.myprint("La formation indexée (champs par defaut) =" + str(ret_val2['_id']))
                        return True
                    else:
                        return False

            # Indexation du champ : title
            elif ( str(source_field) == "title" ):
                    chaine = doc["title"]
                    # mycommon.myprint(" external_code = "+str(doc["external_code"])+" ==> "+str(chaine))
                    retval = ls.ela_index_record_field(chaine, str(doc["external_code"]), source_field)

                    '''
                    # Apres indexation, on met a jour la formation pour 
                    # mettre le champ "indexe" a 1.
                    '''
                    if (retval):
                        # mise à jour du champ "indexed"
                        myobjectif = {}
                        myobjectif['indexed_title'] = '1'

                        ret_val2 = collection.find_and_modify(query={"external_code": external_code},
                                                              update={"$set": myobjectif}
                                                              )

                        if (ret_val2 and ret_val2['_id']):
                            mycommon.myprint("La formation indexée (champ title) =" + str(ret_val2['_id']))
                            return True
                        else:
                            return False

            # Indexation du champ : description
            elif ( str(source_field) == "description" ):
                    chaine = doc["description"]
                    # mycommon.myprint(" external_code = "+str(doc["external_code"])+" ==> "+str(chaine))
                    retval = ls.ela_index_record_field(chaine, str(doc["external_code"]), source_field)

                    '''
                    # Apres indexation, on met a jour la formation pour 
                    # mettre le champ "indexe" a 1.
                    '''
                    if (retval):
                        # mise à jour du champ "indexed"
                        myobjectif = {}
                        myobjectif['indexed_desc'] = '1'

                        ret_val2 = collection.find_and_modify(query={"external_code": external_code},
                                                              update={"$set": myobjectif}
                                                              )

                        if (ret_val2 and ret_val2['_id']):
                            mycommon.myprint("La formation indexée (champ description) =" + str(ret_val2['_id']))
                            return True
                        else:
                            return False


            # Indexation du champ : Objectif
            elif ( str(source_field) == "objectif" ):
                    chaine = doc["objectif"]
                    # mycommon.myprint(" external_code = "+str(doc["external_code"])+" ==> "+str(chaine))
                    retval = ls.ela_index_record_field(chaine, str(doc["external_code"]), source_field)

                    '''
                    # Apres indexation, on met a jour la formation pour 
                    # mettre le champ "indexe" a 1.
                    '''
                    if (retval):
                        # mise à jour du champ "indexed"
                        myobjectif = {}
                        myobjectif['indexed_obj'] = '1'

                        ret_val2 = collection.find_and_modify(query={"external_code": external_code},
                                                              update={"$set": myobjectif}
                                                              )

                        if (ret_val2 and ret_val2['_id']):
                            mycommon.myprint("La formation indexée (champs objectif) =" + str(ret_val2['_id']))
                            return True
                        else:
                            return False


            # Indexation du champ : mot_cle
            elif (str(source_field) == "keyword"):
                chaine = doc["mots_cle"]
                # mycommon.myprint(" external_code = "+str(doc["external_code"])+" ==> "+str(chaine))
                retval = ls.ela_index_record_field(chaine, str(doc["external_code"]), source_field)

                '''
                # Apres indexation, on met a jour la formation pour 
                # mettre le champ "indexe" a 1.
                '''
                if (retval):
                    # mise à jour du champ "indexed"
                    myobjectif = {}
                    myobjectif['indexed_keyword'] = '1'

                    ret_val2 = collection.find_and_modify(query={"external_code": external_code},
                                                          update={"$set": myobjectif}
                                                          )

                    if (ret_val2 and ret_val2['_id']):
                        mycommon.myprint("La formation indexée (champs objectif) =" + str(ret_val2['_id']))
                        return True
                    else:
                        return False

            # Indexation du champ : video_text , donc la transcription d'une video
            elif (str(source_field) == "video_text"):
                chaine = doc["video_text"]
                # mycommon.myprint(" external_code = "+str(doc["external_code"])+" ==> "+str(chaine))
                retval = ls.ela_index_record_field(chaine, str(doc["external_code"]), source_field)

                '''
                # Apres indexation, on met a jour la formation pour 
                # mettre le champ "indexe" a 1.
                '''
                if (retval):
                    # mise à jour du champ "indexed"
                    myobjectif = {}
                    myobjectif['indexed_video_text'] = '1'

                    ret_val2 = collection.find_and_modify(query={"external_code": external_code},
                                                          update={"$set": myobjectif}
                                                          )

                    if (ret_val2 and ret_val2['_id']):
                        mycommon.myprint("La formation indexée (champs video_text) =" + str(ret_val2['_id']))
                        return True
                    else:
                        return False

        return True
    except Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False


'''
La fonction "ela_index_all_classes" va aller chercher chaque cours dans la BDD
et créer les mots clées qui sont ensuite enregister dans la table "elaindex" 
'''
def ela_index_all_classes():
# Making a Connection with MongoClient
    try:
        # collection
        collection = MYSY_GV.dbname["myclass"]
        '''
        ATTENTION ATTENTION 
        /!\ : avant l'indexation, on vide la table des indexes.
        cette logique est tres gourmande.
        ce quil faudrait faire :
        - si une formation est indexée, mettre un fag pour dire : indexé => OK
        - si on met à jour une formation ==> Mettre le flag à KO
        - si on ajoute une formation, mettre le flag à KO
        
        Pour mutualiser le process entre l'indexation des tous les champs ou l'indexation de uniquement de certain champs
        ex : indexation du champ 'title' ou du champ 'objectif', je vais introduitre la notion de 'source_fied'
        pour l'indexation title, 'source_fied' = 'title'
        pour l'indexation objectif, 'source_fied' = 'objectif'
        
        apres pour l'indexation, il ne faudra indexer que les formation dont le flag est KO.
        aussi, avant d'indexer une formation, supprimer tous les index de la dite formation pour remplacer tous les anciens et eviter un doublon
        '''

        nb_class_indexed = 0
        for doc in collection.find({'indexed':'0'}):
            if ("title" in doc.keys() and "description" in doc.keys() ):
                chaine = doc["title"]+" - "+doc["description"]
                mycommon.myprint(" external_code = "+str(doc["external_code"])+" ==> "+str(chaine))
                retval = ela_index_class(str(doc["external_code"]))
                print(" apres : ela_index_class retval =  "+str(retval))

                if( retval is False):
                    mycommon.myprint("IMPOSSIBLE d'indexer la formation = " + str(doc["external_code"]))
                else:
                    nb_class_indexed = nb_class_indexed+1


                #retval = ls.ela_index_record_field(chaine, str(doc["external_code"]))

        mycommon.myprint(str(nb_class_indexed)+" ont été indexes")
        return True, str(nb_class_indexed)+" ont été indexes "

    except Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible d'indexer la BDD des formations ==> KO"

'''
Cette fonction va indexer les mots clés ajoutés à une formation.
Par defaut, seul 3 mots clés sont acceptés par formation.
les mots clés sont separés par des ";".
ex : mot1;mot2;mot3
'''
def ela_index_all_classes_keywords():
    try:
        collection = MYSY_GV.dbname["myclass"]
        nb_class_indexed = 0
        for doc in collection.find({'indexed_keyword': '0'}):
            if ("mots_cle" in doc.keys()):
                chaine = doc["mots_cle"]
                mycommon.myprint(" external_code = " + str(doc["external_code"]) + " ==> " + str(chaine))
                retval = ela_index_class(str(doc["external_code"]), "keyword")
                print(" apres : ela_index_all_classes_title retval =  " + str(retval))

                if (retval is False):
                    mycommon.myprint(
                        str(inspect.stack()[0][3]) + "IMPOSSIBLE d'indexer la formation = " + str(doc["external_code"]))
                else:
                    nb_class_indexed = nb_class_indexed + 1

                # retval = ls.ela_index_record_field(chaine, str(doc["external_code"]))

        mycommon.myprint(str(nb_class_indexed) + " ont été indexes")
        return True, str(nb_class_indexed) + " ont été indexes "

        return True
    except Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible d'indexer la BDD des formations ==> KO"

'''
La fonction "ela_index_all_classes_title" va aller chercher chaque cours dans la BDD
et créer les mots clées  des title qui sont ensuite enregister dans la table "elaindex" 
'''
def ela_index_all_classes_title():
    # Making a Connection with MongoClient
    try:

        collection = MYSY_GV.dbname["myclass"]
        '''
        ATTENTION ATTENTION 
        /!\ : avant l'indexation, on vide la table des indexes.
        cette logique est tres gourmande.
        ce quil faudrait faire :
        - si une formation est indexée, mettre un fag pour dire : indexé => OK
        - si on met à jour une formation ==> Mettre le flag à KO
        - si on ajoute une formation, mettre le flag à KO

        
        ex : indexation du champ 'title' ou du champ 'objectif', je vais introduitre la notion de 'source_fied'
        pour l'indexation title, 'source_fied' = 'title'
        pour l'indexation objectif, 'source_fied' = 'objectif'

        apres pour l'indexation, il ne faudra indexer que les formation dont le flag est KO.
        aussi, avant d'indexer une formation, supprimer tous les index de la dite formation pour remplacer tous les anciens et eviter un doublon
        '''

        nb_class_indexed = 0
        for doc in collection.find({'indexed_title': '0'}):
            if ("title" in doc.keys()):
                chaine = doc["title"]
                mycommon.myprint(" external_code = " + str(doc["external_code"]) + " ==> " + str(chaine))
                retval = ela_index_class(str(doc["external_code"]), "title")
                print(" apres : ela_index_all_classes_title retval =  " + str(retval))

                if (retval is False):
                    mycommon.myprint(str(inspect.stack()[0][3]) + "IMPOSSIBLE d'indexer la formation = " + str(doc["external_code"]))
                else:
                    nb_class_indexed = nb_class_indexed + 1

                # retval = ls.ela_index_record_field(chaine, str(doc["external_code"]))

        mycommon.myprint(str(nb_class_indexed) + " ont été indexes")
        return True, str(nb_class_indexed) + " ont été indexes "

    except Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible d'indexer la BDD des formations ==> KO"


'''
La fonction "ela_index_all_classes_desc" va aller chercher chaque cours dans la BDD
et créer les mots clées  des "description" qui sont ensuite enregister dans la table "elaindex" 
'''

def ela_index_all_classes_desc():
    # Making a Connection with MongoClient
    try:
        client = MongoClient("mongodb://localhost:27017/")
        # database
        db = client["cherifdb"]
        # collection
        collection = MYSY_GV.dbname["myclass"]
        '''
        ATTENTION ATTENTION 
        /!\ : avant l'indexation, on vide la table des indexes.
        cette logique est tres gourmande.
        ce quil faudrait faire :
        - si une formation est indexée, mettre un fag pour dire : indexé => OK
        - si on met à jour une formation ==> Mettre le flag à KO
        - si on ajoute une formation, mettre le flag à KO


        ex : indexation du champ 'title' ou du champ 'objectif', je vais introduitre la notion de 'source_fied'
        pour l'indexation title, 'source_fied' = 'title'
        pour l'indexation objectif, 'source_fied' = 'objectif'

        apres pour l'indexation, il ne faudra indexer que les formation dont le flag est KO.
        aussi, avant d'indexer une formation, supprimer tous les index de la dite formation pour remplacer tous les anciens et eviter un doublon
        '''

        nb_class_indexed = 0
        for doc in collection.find({'indexed_desc': '0'}):
            if ("description" in doc.keys()):
                chaine = doc["description"]
                mycommon.myprint(" external_code = " + str(doc["external_code"]) + " ==> " + str(chaine))
                retval = ela_index_class(str(doc["external_code"]), "description")
                print(" apres : ela_index_all_classes_title retval =  " + str(retval))

                if (retval is False):
                    mycommon.myprint("IMPOSSIBLE d'indexer la formation = " + str(doc["external_code"]))
                else:
                    nb_class_indexed = nb_class_indexed + 1

                # retval = ls.ela_index_record_field(chaine, str(doc["external_code"]))

        mycommon.myprint(str(nb_class_indexed) + " ont été indexes - champ description")
        return True, str(nb_class_indexed) + " ont été indexes - champ description "

    except Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible d'indexer la BDD des formations ==> KO"


'''
La fonction "ela_index_all_classes_desc" va aller chercher chaque cours dans la BDD
et créer les mots clées  des "objectif" qui sont ensuite enregister dans la table "elaindex" 
'''

def ela_index_all_classes_obj():
    # Making a Connection with MongoClient
    try:
        # collection
        collection = MYSY_GV.dbname["myclass"]
        '''
        ATTENTION ATTENTION 
        /!\ : avant l'indexation, on vide la table des indexes.
        cette logique est tres gourmande.
        ce quil faudrait faire :
        - si une formation est indexée, mettre un fag pour dire : indexé => OK
        - si on met à jour une formation ==> Mettre le flag à KO
        - si on ajoute une formation, mettre le flag à KO


        ex : indexation du champ 'title' ou du champ 'objectif', je vais introduitre la notion de 'source_fied'
        pour l'indexation title, 'source_fied' = 'title'
        pour l'indexation objectif, 'source_fied' = 'objectif'

        apres pour l'indexation, il ne faudra indexer que les formation dont le flag est KO.
        aussi, avant d'indexer une formation, supprimer tous les index de la dite formation pour remplacer tous les anciens et eviter un doublon
        '''

        nb_class_indexed = 0
        for doc in collection.find({'indexed_obj': '0'}):
            if ("objectif" in doc.keys()):
                chaine = doc["objectif"]
                mycommon.myprint(" external_code = " + str(doc["external_code"]) + " ==> " + str(chaine))
                retval = ela_index_class(str(doc["external_code"]), "objectif")
                print(" apres : ela_index_all_classes_title retval =  " + str(retval))

                if (retval is False):
                    mycommon.myprint("IMPOSSIBLE d'indexer la formation = " + str(doc["external_code"]))
                else:
                    nb_class_indexed = nb_class_indexed + 1

                # retval = ls.ela_index_record_field(chaine, str(doc["external_code"]))

        mycommon.myprint(str(nb_class_indexed) + " ont été indexes - champ objectif")
        return True, str(nb_class_indexed) + " ont été indexes - champ objectif "

    except Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible d'indexer la BDD des formations ==> KO"


'''
Cette fonction lire la transcription d'une video et 
l'indexer'''

def ela_index_all_classes_video_text():
    # Making a Connection with MongoClient
    try:
        # collection
        collection = MYSY_GV.dbname["myclass"]
        '''
        ATTENTION ATTENTION 
        /!\ : avant l'indexation, on vide la table des indexes.
        cette logique est tres gourmande.
        ce quil faudrait faire :
        - si une formation est indexée, mettre un fag pour dire : indexé => OK
        - si on met à jour une formation ==> Mettre le flag à KO
        - si on ajoute une formation, mettre le flag à KO


        ex : indexation du champ 'title' ou du champ 'objectif', je vais introduitre la notion de 'source_fied'
        pour l'indexation title, 'source_fied' = 'title'
        pour l'indexation objectif, 'source_fied' = 'objectif'

        apres pour l'indexation, il ne faudra indexer que les formation dont le flag est KO.
        aussi, avant d'indexer une formation, supprimer tous les index de la dite formation pour remplacer tous les anciens et eviter un doublon
        '''

        nb_class_indexed = 0
        for doc in collection.find({'indexed_video_text': '0'}):
            if ("video_text" in doc.keys()):
                chaine = doc["video_text"]
                #mycommon.myprint(" video_texte = " + str(doc["external_code"]) + " ==> " + str(chaine))
                retval = ela_index_class(str(doc["external_code"]), "video_text")
                #print(" apres : ela_index_all_classes_video_texte retval =  " + str(retval))

                if (retval is False):
                    mycommon.myprint("IMPOSSIBLE d'indexer la formation = " + str(doc["external_code"]))
                else:
                    nb_class_indexed = nb_class_indexed + 1

                # retval = ls.ela_index_record_field(chaine, str(doc["external_code"]))

        mycommon.myprint(str(nb_class_indexed) + " ont été indexes - champ video_text")
        return True, str(nb_class_indexed) + " ont été indexes - champ video_text "

    except Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible d'indexer video_text la BDD des formations ==> KO"






'''
Cette fonction recherche une chaine de caractère
dans la base de données.

cette recherche concerne les 'tuple' avec "source_field":"default" ==> l'indexation par defaut.

Elle retourne l'id_externe de la formation
'''
def ela_recherche_tokens(sentence):

    try:
        tab_training_id = []
        status, tab_tokens = ls.Ela_Tokenize(sentence)
        if( status is False):
            return False

        status, tab_tokens2 = ls.Ela_remove_stop_words(tab_tokens)
        if (status is False):
            return False

        status, tab_tokens3 = ls.Ela_remove_pronoun(tab_tokens2)
        if (status is False):
            return False

        '''
        note : 26/03 : Faire evolution la fonction ici pour 
        gerer les mots qui ne doivent pas etre racinisé comme le cas du mot "Responsive"
        
        De manière plus globale, il faudrait exclure certains mot de la racinisation.
        
        '''
        #print(" VERIF : "+str(tab_tokens3))

        status, tab_tokens4 = ls.Ela_stemmize_search(tab_tokens3)
        if( status is False):
            return False

        print(" VERIF APRES STEMISATION : " + str(tab_tokens4))

        tab_tokens4.sort()

        '''
        tab_tokens4 contient la liste des mots à rechercher.
        En suite pour chaque mot de "tab_tokens4" on regarde dans la table  "elaindex"
        a quoi cela pourrait correspondre.
        '''

        # collection
        collection = MYSY_GV.dbname["elaindex"]

        print(" mot recherché tab_tokens4 (initialement) = "+str(tab_tokens4))

        status, new_tab_tokens4 = mysy_recherche_levenshtein(tab_tokens4)
        if( status is False):
            mycommon.myprint(str(inspect.stack()[0][3]) + " Recherche : mysy_recherche_levenshtein return FALSE ")
            return []

        print(" ### les nouveaux mots recherchés new_tab_tokens4 = " + str(new_tab_tokens4))

        pipe2 = [{  '$match': { 'mots': {  '$in': new_tab_tokens4 } }  },
                 {  '$group': {
                        '_id': "$id_formation",
                        'count_class': {'$sum': 1},
                        'sum_occurence': {'$sum': '$occurence'}
                        }
                 },
                 {'$sort': {'count_class': -1, 'sum_occurence': -1}},
                 {'$limit': MYSY_GV.QUERY_LIMIT_ROW}
                 ]

        print(" #### CRITERE DE CHERCHE pipe2 = "+str(pipe2))
        # ici limite à 4
        for result in collection.aggregate(pipe2):
            tab_training_id.append(str(result["_id"]))
            #print(result)

        #print("resultat tab_training_id = "+str(tab_training_id))

        return tab_training_id
    except Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False


'''
Cette fonction essayer de faire une recherche de leveinstein
elle prend une liste mot :
pr chaque mot,
1 - elle prends les 3 premier caractère
2 - recherche ceux qui correspondent
3 - pour chaque mot trouvé, faire un distance de levein et voir

puis elle retourne la liste des mots trouvé dans la table elaindex

Regles fonctionnelles : 
Si  0 < len(mot) <= 3 ==> Recherche strict à faire
Si  3 < len(mot) <= 5 ==> Recherche avec une distance de 1
Si  5 < len(mot) <= 10 ==> Recherche avec une distance de 2
Si  10 < len(mot) ==> Recherche avec une distance de 3
'''
def mysy_recherche_levenshtein(tab_mot):
    try:

        coll_name = MYSY_GV.dbname['elaindex']
        training_mots = []

        for mot in tab_mot:

            '''
            Si le mot appartient à la collection "word_not_stem", alors il faut faire un recherche strict
            pas de recherche elastique à faire.
            '''
            '''print("### + #### '" + str(mot) + "'   mycommon.Word_Not_Stemmize(str(mot) = '" +
                  str(mycommon.Word_Not_Stemmize(str(mot))))
            '''
            if (mycommon.Word_Not_Stemmize(str(mot)) is True):
                # "recherche strict"
                if (str(mot) not in training_mots):
                    #print(" Le mot " + str(mot) + " est dans la table 'word_not_stem', donc pas de recherche elastique")
                    training_mots.append(str(mot))

            else:

                if( len( mot ) > 2):
                    mot_first_caract = mot[0:3]
                    #print(" Traitement de " + str(mot) + " = 3 first => " + str(mot_first_caract))

                    v = {'$regex': "^" + mot_first_caract}
                    #print("v  = " + str(v))

                    for x in coll_name.find({'mots': v}):
                        cmp_levenshtein = int(mycommon.levenshtein(mot, str(x['mots'])))
                        #print(" check ### ="+str(x['mots']))

                        if( len(mot) <= 5 and cmp_levenshtein <= 0):
                            if( str(x['mots']) not in training_mots):
                                training_mots.append( str(x['mots']) )

                        elif( len(mot) <= 10 and cmp_levenshtein <= 0):
                            if( str(x['mots']) not in training_mots):
                                training_mots.append( str(x['mots']) )

                        elif ( cmp_levenshtein <= 0):
                            if (str(x['mots']) not in training_mots):
                                training_mots.append(str(x['mots']))

                        '''elif (cmp_levenshtein > 3):
                            print(" KOOFF cmp_levenshtein : " + mot + "  CMP  " + str(x['mots']) + " = " + str(cmp_levenshtein) +
                              " ==> id_formation" + str(x['id_formation']) + " ==> occurrence = " + str(x['occurence']))
                        '''

        return True, training_mots

    except Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, None


'''
Cette fonction recherche une chaine de caractère
dans la base, mais sur indexation bien precise.

par exemple, pour gerer les recherche par tips :'title':'sentense', le système cherchera a identifier
les mots de "sentense" dans les indexation des titre. 
Cela revient a chercher "sentence" dans la table "ela_index", where "source_field" = "title"

Elle retourne l'id_externe de la formation
'''
def ela_recherche_tokens_source_field(sentence, source_fied=""):
    try:
        if( len(str(source_fied)) == 0):
            mycommon.myprint(str(inspect.stack()[0][3])+" - source_fied est vide")
            return False

        # Verification que source_field correspond a la bonne colonne
        field_list = ['default', 'title', 'description','objectif',]
        if source_fied not in field_list:
            mycommon.myprint(str(inspect.stack()[0][3])+" -  Le champ  '" + source_fied + "' n'existe pas, requete annulée")
            return False

        print(" ici: sentence = "+sentence+", -- source_fied ="+source_fied)
        tab_training_id = []
        status, tab_tokens = ls.Ela_Tokenize(sentence)
        if( status is False):
            return False

        status, tab_tokens2 = ls.Ela_remove_stop_words(tab_tokens)
        if (status is False):
            return False

        status, tab_tokens3 = ls.Ela_remove_pronoun(tab_tokens2)
        if (status is False):
            return False

        '''
            note : 26/03 : Faire evolution la fonction ici pour 
            gerer les mots qui ne doivent pas etre racinisé comme le cas du mot "Responsive"

            De manière plus globale, il faudrait exclure certains mot de la racinisation.

            '''
        #print(" VERIF : " + str(tab_tokens3))

        status, tab_tokens4 = ls.Ela_stemmize_search(tab_tokens3)
        if (status is False):
            return False

        #print(" VERIF APRES STEMISATION : " + str(tab_tokens4))

        tab_tokens4.sort()

        '''
        tab_tokens4 contient la liste des mots à rechercher.
        En suite pour chaque mot de "tab_tokens4" on regarde dans la table  "elaindex"
        a quoi cela pourrait correspondre.
        '''

        collection = MYSY_GV.dbname["elaindex"]
        print(" mot recherchéee tab_tokens4 (initialement) = " + str(tab_tokens4))
        status, new_tab_tokens4 = mysy_recherche_levenshtein(tab_tokens4)
        if (status is False):
            mycommon.myprint(str(inspect.stack()[0][3]) + " Recherche : mysy_recherche_levenshtein return FALSE ")
            return []

        #print(" ### les nouveaux mots recherchés new_tab_tokens4 = " + str(new_tab_tokens4))

        for token in new_tab_tokens4:
            #print(" #### Token rechercher dans l'index est : '"+str(token)+"' et le source_field =  '"+str(source_fied)+"' ")
            for doc in collection.find({"mots":token, "source_field":source_fied}):
                #print(" Trouvé dans le cours N° "+str(doc["id_formation"]))
                if str(doc["id_formation"]) not in tab_training_id :
                    tab_training_id.append(str(doc["id_formation"]))

        #print(" Pour la phrase "+str(sentence)+", voici les formations correspondantes")
        #print(tab_training_id)

        return tab_training_id

    except Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Traitement impossible "

''''
Cette fonction indexe les articles et avis.
important : se ra indexé que le titre de la formation.
apres avoir été indexés la champs "indexed" passe à 1
'''
def ela_index_all_articles_avis():
# Making a Connection with MongoClient
    try:
        # collection
        collection = MYSY_GV.dbname["articles_avis"]
        nb_class_indexed = 0
        for doc in collection.find({'indexed': '0'}):
            if ("title_formation" in doc.keys()):
                chaine = doc["title_formation"]
                mycommon.myprint(" Debut indexation de l'article : "+chaine)
                retval = ela_index_articles_avis(str(doc["title_formation"]))
                print(" apres : ela_index_class retval =  " + str(retval))

                if (retval is False):
                    mycommon.myprint("IMPOSSIBLE d'indexer la formation = " + str(doc["external_code"]))
                else:
                    nb_class_indexed = nb_class_indexed + 1

                # retval = ls.ela_index_record_field(chaine, str(doc["external_code"]))

            mycommon.myprint(str(nb_class_indexed) + " ont été indexes")



        return True, str(nb_class_indexed) + " articles ont été indexes "

    except Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False, "Impossible d'indexer les articles et avis ==> KO"


'''
Cette fonction indexe un article / avis
Par defaut sont pris en compte : 
- le titre de la formation
'''
def ela_index_articles_avis(titre_formation="", source_field = ""):
    try:

        collection = MYSY_GV.dbname["articles_avis"]

        if( len(str(source_field)) == 0):
            source_field = 'default'

        for doc in collection.find({"title_formation":titre_formation, "valide":"1"}):

            # Indexation par defaut : champs TITRE FORMATION
            if ( str(source_field) == "default" ):
                chaine = doc["title_formation"]
                #mycommon.myprint(" external_code = "+str(doc["external_code"])+" ==> "+str(chaine))
                retval = ls.ela_index_article_avis_record_field(chaine, str(doc["title_formation"]), source_field)

                '''
                # Apres indexation, on met a jour la formation pour 
                # mettre le champ "indexe" a 1.
                '''
                if( retval ):
                    # mise à jour du champ "indexed"
                    myobjectif = {}
                    myobjectif['indexed'] = '1'

                    ret_val2 = collection.find_and_modify(query={"title_formation":titre_formation, "valide":"1"},
                                                        update={"$set": myobjectif}
                                                        )

                    if (ret_val2 and ret_val2['_id']):
                        mycommon.myprint("L'article indexé (champs par defaut) =" + str(ret_val2['_id']))
                        return True
                    else:
                        return False


        return True
    except Exception as e:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno))
        return False


'''
Cette fonction recherche une chaine de caractère
dans la table des articles et avis.

Elle retourne le title de la formation
'''


def ela_recherche_article_avis_tokens(sentence):
    tab_training_id = []
    tab_tokens = ls.Ela_Tokenize(sentence)
    tab_tokens2 = ls.Ela_remove_stop_words(tab_tokens)
    tab_tokens3 = ls.Ela_remove_pronoun(tab_tokens2)
    '''
    note : 26/03 : Faire evolution la fonction ici pour 
    gerer les mots qui ne doivent pas etre racinisé comme le cas du mot "Responsive"

    De manière plus globale, il faudrait exclure certains mot de la racinisation.

    '''
    #print(" VERIF : " + str(tab_tokens3))
    tab_corrected_word = []
    for mot in tab_tokens3:
        mycommon.recherche_check_word_in_fr_dict(str(mot))
        val = ls.correct_fr_word(str(mot))
        if (val):
            tab_corrected_word.append(str(val))

    print("corrected word = " + str(tab_corrected_word))

    status, tab_tokens4 = ls.Ela_stemmize(tab_corrected_word)
    if( status is False):
        return False

    print(" VERIF APRES STEMISATION : " + str(tab_tokens4))

    tab_tokens4.sort()

    '''
    tab_tokens4 contient la liste des mots à rechercher.
    En suite pour chaque mot de "tab_tokens4" on regarde dans la table  "elaindex"
    a quoi cela pourrait correspondre.
    '''

    # collection
    collection = MYSY_GV.dbname["elaindex_article_avis"]

    #print(" mot recherché tab_tokens4 = " + str(tab_tokens4))

    pipe2 = [{'$match': {'mots': {'$in': tab_tokens4}}},
             {'$group': {
                 '_id': "$id_article_avis",
                 'count_class': {'$sum': 1},
                 'sum_occurence': {'$sum': '$occurence'}
             }
             },
             {'$sort': {'count_class': -1, 'sum_occurence': -1}},
             {'$limit': MYSY_GV.QUERY_LIMIT_ROW}
             ]

    # ici limit on rows
    for result in collection.aggregate(pipe2):
        tab_training_id.append(str(result["_id"]))
        # print(result)

    #print("resultat tab_training_id = " + str(tab_training_id))

    return tab_training_id

