
from pymongo import MongoClient
import pymongo
import json
from flask import Flask, request, jsonify
#from flask_mongoengine import MongoEngine
import json
from bson import ObjectId
import re
import numpy as np
import ela_index_bdd_classes as ela_index
import logging
from datetime import datetime
import prj_common as mycommon
import secrets
from pymongo import ReturnDocument
import inspect
import sys, os
import csv
import pandas as pd
from unidecode import unidecode
import GlobalVariable as MYSY_GV



class JSONEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, ObjectId):
            return str(o)
        print(self)
        print(o)
        return json.JSONEncoder.default(self, o)



def get_recherche_gle_class(sentence):
    try:
        if not sentence:
            return False

        #mycommon.myprint(" On recehrche la phrase +'"+sentence+"'")

        tab_training = []
        tab_training = ela_index.ela_recherche_tokens(sentence)

        '''
        pour analyser la recherche, decommenter les 2 lignes ci-dessous
        '''
        #mycommon.myprint(" pour phrase : #"+sentence+"#, voici la liste des formations")
        #mycommon.myprint(tab_training)


        coll_name = MYSY_GV.dbname['myclass']

        insertObject = []



        for x in coll_name.find({"external_code": {"$in": tab_training}, 'published':'1'}, {"_id": 0, "indexed": 0, "indexed_desc": 0, "indexed_obj": 0, "indexed_title": 0, "valide": 0,
                                                                           "locked": 0, }):
            mycommon.myprint(x)
            user = x
            insertObject.append(JSONEncoder().encode(user))

        # mycommon.myprint(" insertObject = ", insertObject)
        return insertObject

    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



def get_class_by_list_attr(attribut, list_values):
    try:
        ela_array = []
        ela_array = list_values.split(",")
        mycommon.myprint(" attribut"+ attribut+"  ==> list_values = "+ela_array)

        coll_name = MYSY_GV.dbname['myclass']

        insertObject = []
        for x in coll_name.find({attribut:{ "$in":ela_array}, 'published':'1'},{"_id": 0, "indexed": 0, "indexed_desc": 0, "indexed_obj": 0, "indexed_title": 0,
                                                               "valide": 0, "locked": 0, }):
            mycommon.myprint(x)
            user = x
            insertObject.append(JSONEncoder().encode(user))

        #mycommon.myprint(" insertObject = ", insertObject)
        return insertObject

    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



def update_class_by_attribut(objId, attribut, value):
    try:
        mycommon.myprint("objId = "+objId+" attribut "+attribut+" value = "+value)

        coll_name = MYSY_GV.dbname['myclass']

        insertObject = []
        for x in coll_name.find({attribut: value, 'published':'1'}, {"_id": 0, "indexed": 0, "indexed_desc": 0, "indexed_obj": 0,
                                                    "indexed_title": 0, "valide": 0, "locked": 0, }):
            mycommon.myprint(x)
            user = x
            insertObject.append(JSONEncoder().encode(user))

        mycommon.myprint(" insertObject = "+ insertObject)
        return insertObject


    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


import random
def get_all_class(diction):
    try:

        # Dictionnaire des champs utilisables
        field_list = ['token', 'user_ip', 'user_country_code', 'user_country_name', 'user_city',
		'user_postal', 'user_latitude', 'user_longitude', 'user_state', 'search_text', 'certif',
                      'support', 'type', 'lang', 'price', 'distance', 'duration']

        incom_keys = diction.keys()

        '''
        # Verification que les champs reçus dans l'API sont bien dans la liste des champs autorisés
        # Cela evite le cas ou une entité tierce ajouter les valeurs inconnu dans l'API
        # Ici on doit mettre tous les champs possible (obligatoire ou non) de la BDD dans la liste
        # field_list.
        '''
        for val in incom_keys:
            if str(val).lower() not in str(field_list).lower():
                mycommon.myprint(str(inspect.stack()[0][3]) + " Le champ  '" + val + "' n'est pas autorisé")
                return False, " Recherche impossible"


        # Recuperation des parametres
        mydata = {}
        if ("user_ip" in diction.keys()):
            if diction['user_ip']:
                mydata['user_ip'] = diction['user_ip']

        if ("user_country_code" in diction.keys()):
            if diction['user_country_code']:
                mydata['user_country_code'] = diction['user_country_code']

        if ("user_country_name" in diction.keys()):
            if diction['user_country_name']:
                mydata['user_country_name'] = diction['user_country_name']

        if ("user_city" in diction.keys()):
            if diction['user_city']:
                mydata['user_city'] = diction['user_city']

        if ("user_postal" in diction.keys()):
            if diction['user_postal']:
                mydata['user_postal'] = diction['user_postal']

        if ("user_latitude" in diction.keys()):
            if diction['user_latitude']:
                mydata['user_latitude'] = diction['user_latitude']

        if ("user_longitude" in diction.keys()):
            if diction['user_longitude']:
                mydata['user_longitude'] = diction['user_longitude']

        if ("user_state" in diction.keys()):
            if diction['user_state']:
                mydata['user_state'] = diction['user_state']

        #print(" My Data ="+str(mydata))

        status, tab_training_inzone = get_training_in_user_zone(diction)

        nb_formation_a_jouter = MYSY_GV.MAINPAGE_QUERY_LIMIT_ROW - len(tab_training_inzone)


        coll_name = MYSY_GV.dbname['myclass']

        val_tmp = len(tab_training_inzone)
        insertObject = []

        for x in coll_name.find({ "$or": [ {'valide':'1', 'locked':'0', 'isalaune':'1', 'published':'1'}, { 'coeur': 1, 'published':'1' } ]  },
                                {"_id": 0, "indexed": 0, "indexed_desc": 0, "indexed_obj": 0, "indexed_title": 0,
                                                               "valide": 0, "locked": 0,  }).\
                limit(nb_formation_a_jouter).\
                sort(
            [("display_rank", pymongo.DESCENDING), ("price", pymongo.ASCENDING), ("date_update", pymongo.DESCENDING)  ]):



            #print("AVANT ==> "+str(x['description']))
            val = x['description']
            if( len(x['description']) > MYSY_GV.MAX_CARACT ):
                x['description'] = val[:MYSY_GV.MAX_CARACT]+" ..."

            else:
                x['description'] = val[:MYSY_GV.MAX_CARACT]

            #mycommon.myprint("APRES ==> " + str(x['description']))

            user = x
            user['id'] = str(val_tmp)
            insertObject.append(JSONEncoder().encode(user))

            #print(" 1111111 ")
            mycommon.InsertStatistic(x, "summary",mydata)

            tab_training_inzone.append(JSONEncoder().encode(user))
            val_tmp = val_tmp + 1

        #print(" insertObject = ", str(tab_training_inzone))
        #return True, insertObject
        return True, tab_training_inzone
    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 de recuperer les formations"


'''
Cette Fonction recuperer les formation dans la zone de l'utilisateur.
Par zone utilisateur j'entends : ville or pays

/!\ IMPORTANT : 
Si on veut UNIQUEMENT diffuser une formation dans une ville, alors il faut : 
- reseigner le champs : zone_diffusion.city
- Laisser le champs : zone_diffusion.country à VIDE.

/!\ IMPORTANT2 : La formation doit etre à la une :
donc le paramttrafe "isalaune" = 1

Par defaut, le système cherche les diffuser dans un pays ou dans une ville.
le champs pays est renseigner, alors la formation a est diffuser dans tous le pays.

Si le la collection "zone_diffusion" est vide ou n'existe pas, alors les formations sont diffusées partout dans le monde.
'''
def get_training_in_user_zone(diction):
    try:
        insertObject = []
        # Dictionnaire des champs utilisables
        field_list = ['token', 'user_ip', 'user_country_code', 'user_country_name', 'user_city',
                      'user_postal', 'user_latitude', 'user_longitude', 'user_state', 'search_text', 'certif',
                      'support', 'type', 'lang', 'price', 'distance', 'duration']

        incom_keys = diction.keys()

        '''
        # Verification que les champs reçus dans l'API sont bien dans la liste des champs autorisés
        # Cela evite le cas ou une entité tierce ajouter les valeurs inconnu dans l'API
        # Ici on doit mettre tous les champs possible (obligatoire ou non) de la BDD dans la liste
        # field_list.
        '''
        for val in incom_keys:
            if str(val).lower() not in str(field_list).lower():
                mycommon.myprint(str(inspect.stack()[0][3]) + " Le champ  '" + val + "' n'est pas autorisé")
                return False, " Recherche impossible"

        # Recuperation des parametres
        mydata = {}
        if ("user_ip" in diction.keys()):
            if diction['user_ip']:
                mydata['user_ip'] = diction['user_ip']

        if ("user_country_code" in diction.keys()):
            if diction['user_country_code']:
                mydata['user_country_code'] = diction['user_country_code']

        if ("user_country_name" in diction.keys()):
            if diction['user_country_name']:
                mydata['user_country_name'] = diction['user_country_name']

        if ("user_city" in diction.keys()):
            if diction['user_city']:
                mydata['user_city'] = diction['user_city']

        if ("user_postal" in diction.keys()):
            if diction['user_postal']:
                mydata['user_postal'] = diction['user_postal']

        if ("user_latitude" in diction.keys()):
            if diction['user_latitude']:
                mydata['user_latitude'] = diction['user_latitude']

        if ("user_longitude" in diction.keys()):
            if diction['user_longitude']:
                mydata['user_longitude'] = diction['user_longitude']

        if ("user_state" in diction.keys()):
            if diction['user_state']:
                mydata['user_state'] = diction['user_state']

        # print(" My Data ="+str(mydata))

        coll_name = MYSY_GV.dbname['myclass']
        val_tmp = 1
        insertObject = []
        print(" critère de recherche : user_country_code = "+str(mydata['user_country_code']).lower()+" ---- user_city = "+str(mydata['user_city']).lower())
        for x in coll_name.find({ "$or": [ {'valide':'1', 'locked':'0', 'isalaune':'1','published':'1', "zone_diffusion.country":str(mydata['user_country_code']).lower()},
                                           {'valide':'1', 'locked':'0',  'isalaune':'1', 'published':'1', "zone_diffusion.city":str(mydata['user_city']).lower()} ]  },
                                {"_id": 0, "indexed": 0, "indexed_desc": 0, "indexed_obj": 0, "indexed_title": 0,
                                                               "valide": 0, "locked": 0, }).\
                limit(MYSY_GV.MAINPAGE_QUERY_LIMIT_ROW).\
                sort(
            [ ("display_rank", pymongo.DESCENDING), ("price", pymongo.ASCENDING), ("date_update", pymongo.DESCENDING),]):



            #print("AVANT ==> "+str(x['description']))
            val = x['description']
            if( len(x['description']) > MYSY_GV.MAX_CARACT ):
                x['description'] = val[:MYSY_GV.MAX_CARACT]+" ..."

            else:
                x['description'] = val[:MYSY_GV.MAX_CARACT]

            #mycommon.myprint("APRES ==> " + str(x['description']))

            user = x
            user['id'] = str(val_tmp)
            insertObject.append(JSONEncoder().encode(user))
            val_tmp = val_tmp + 1


        return True, insertObject
    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 de recuperer les formations dans la zone de l'utilisateur"






'''
Cette fonction recherche les formations correspondant à un text
IMPORTANT : Dans la recherche par tips, on fait du && et non du ou.
exemple : 
pour la recherche "description:"fichier" title:"Niveau 1""
le système va chercher toutes les formation qui on : 
- "description:"fichier" ET ET ET ET ET 
- title:"Niveau 1"

En gros, on fait une intersection entre les 2 listes.

'''

def recherche_text_simple(diction):
    try:
        '''
        # Verification que les champs reçus dans l'API sont bien dans la liste des champs autorisés
        # Cela evite le cas ou une entité tierce ajouter les valeurs inconnu dans l'API
        # Ici on doit mettre tous les champs possible (obligatoire ou non) de la BDD dans la liste
        # field_list.
        '''
        field_list = ['token', 'user_ip', 'user_country_code', 'user_country_name', 'user_city',
		'user_postal', 'user_latitude', 'user_longitude', 'user_state', 'search_text', 'certif',
                      'support', 'type', 'lang', 'price', 'distance', 'duration']
        incom_keys = diction.keys()
        for val in incom_keys:
            if val not in field_list:
                mycommon.myprint(str(inspect.stack()[0][3])+" - :  Le champ  '" + val + "' n'existe pas, recherche annuléee")
                return False, "  Le champ  '" + val + "' n'existe pas, recherche annulée"

        '''
        Une fois qu'on a controlé que toutes les clés mise dans l'API sont correcte. etape precedente,
        On controle que les champs obligatoires sont presents dans la liste 
        '''
        field_list_obligatoire = ['search_text', 'token']

        for val in field_list_obligatoire:
            if val not in diction:
                mycommon.myprint(str(inspect.stack()[0][3])+" - La valeur '" + val + "' n'est pas presente dans liste ")
                return False, " : La valeur '" + val + "' n'est pas presente dans liste "

        # recuperation des paramettre
        search_text = ""
        user_recid = ""
        token = ""
        critere_date = {}
        critere_string = ""
        new_diction = {}
        new_diction['token'] = ""

        if ("search_text" in diction.keys()):
            if diction['search_text']:
                search_text = diction['search_text']


        if ("token" in diction.keys()):
            if diction['token']:
                token = diction['token']
                new_diction['token'] =  diction['token']

        '''
        /!\ Important : si le token est vide, alors c'est une recherche faite en mode non-connecté.
        on doit l'accepter.
        
        le controle de la validé du token est faite que ce dernier n'est pas vide.
        '''

        user_recid = "None"
        coll_search_result = MYSY_GV.dbname['user_recherche_result']

        # Verification de la validité du token/mail dans le cas des user en mode connecté
        if ( len(str(token)) > 0 ):
            retval = mycommon.check_token_validity("", token)

            if retval is False :
                mycommon.myprint(str(inspect.stack()[0][3])+" - Le token n'est pas valide")
                return False, "Le token n'est pas valide"

            # Recuperation du recid de l'utilisateur
            user_recid = mycommon.get_user_recid_from_token(token)
            if user_recid is False:
                mycommon.myprint(str(inspect.stack()[0][3])+" - Impossible de recuperer le token de l'utilisateur")
                return False, " Impossible de desactiver l'objectif utilisateur"


        #mycommon.myprint(" On recehrche la phrase +'" + search_text + "' + user_recid = "+user_recid)

        # Enregistrerment de la recherche
        retval, message, store_recherche_Id = store_recherche(diction, user_recid)
        if (retval is False):
            return retval, message

        '''
        Verification si le texte de recherche contient un pattern de tips,
        c'est a dire une chaine de type : title:"titre"
        
        Si c'est le cas, nous sommes dans le cadre d'un recherche par type
        
        '''

        cleaned_search_text = mycommon.Parse_Clean_Search_Text(search_text)

        print(" NOT CLEANED search_text = " + str(search_text))
        print(" CLEANED search_text = "+str(cleaned_search_text))


        regexp = r"[\w\.-]+:\"[\w\s]*\""
        tips = re.findall(regexp, str(cleaned_search_text), re.MULTILINE)
        nb_tips = len(tips)
        final_message3 = {}

        if( nb_tips > 0 ):
            mycommon.myprint(" Une recherche par tips a été identifiée")
            new_diction['token'] = token

            # Traitement pour chaque recherche par tips
            final_retval = False
            final_message = []
            insertObject = []

            is_first_tip = True
            for val in tips :
                val2 = val.replace('"', '')
                new_diction['search_text'] = val2
                print(" On va recherche : #####"+str(new_diction['search_text'] ))
                retval, message =  recherche_tips_ret_ref(new_diction)

                print(" pour la recherche de : "+str(new_diction)+"  -- Voici le resultat "+str(message))
                if (retval == True ):
                    final_retval = True
                    #print(" contact de message "+str(message)+  "  # final_message "+str(final_message))

                    if( is_first_tip is True) :
                        final_message3 = message
                    else:
                        final_message3 = [x for x in message if x in final_message3]

                    print(" final_message3 = "+str(final_message3))
                    final_message.append(message)
                    is_first_tip = False

            final_message = final_message3
            #print(" liste defitive des ref "+str(final_message))
            final_message2 = []

            for t in final_message:
                if( t is not False):
                    #print( " unique = "+str(t))
                    final_message2.append(t)

            coll_name = MYSY_GV.dbname['myclass']

            '''
            A present mise à jour de la table "user_recherche" avec les resultats trouvés
            '''
            #store_recherche_Id
            find_result = {'find_result':str(final_message2)}

            tab_user_recherche = MYSY_GV.dbname['user_recherche']
            # seules les formation avec locked = 0 et valide=1 sont modifiables
            #print(str(inspect.stack()[0][3]) + " ENREG DES RESULT :"+str(store_recherche_Id)+"  --- "+str(final_message2))


            ret_val_user_rech = coll_name.find_one_and_update(
                {'_id': ObjectId(store_recherche_Id)},
                {"$set": find_result},
                return_document=ReturnDocument.AFTER
                )

            if  (ret_val_user_rech is False ):
                mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible de mettre à jour la table des resultat"
                                                              " d'une recherche de formation. Voir _id = "+ str( store_recherche_Id))
                return False, "La recheche est impossible "

            '''
            la valeur nb_result permettra de savoir si la requete a donnée un resultat.
            si ce n'est pas le cas, il faudra à la fin enregistrer la requete avec un result a vide'''
            nb_result = 0

            for x in coll_name.find({"external_code": {"$in": final_message2}, 'published':'1'},
                                    {"_id": 0, "indexed": 0, "indexed_desc": 0, "indexed_obj": 0,
                                     "indexed_title": 0, "valide": 0, "locked": 0, }).\
                sort([("display_rank", pymongo.DESCENDING), ("price", pymongo.ASCENDING), ("date_update", pymongo.DESCENDING), ]):

                nb_result = nb_result +1
                my_recid = {}
                my_recid['user_rec_id'] = str(user_recid)
                mydict_combined = {**diction, **x, **my_recid}
                mydict_combined['date_update'] = str(datetime.now())
                mydict_combined['type_view'] = "summary"

                if ("_id" in mydict_combined.keys()):
                    mydict_combined['class_id'] = mydict_combined.pop('_id')

                #mycommon.myprint("COMBINED = " + str(mydict_combined))

                '''
                Statistique : Insertion du recherche - resultat '''
                ret_val_tmp = coll_search_result.insert_one(mydict_combined)
                if (ret_val_tmp is False):
                    mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible de mettre à jour la table des resultat"
                                                                  " d'une recherche de formation. Voir _id = ")
                    return False, "La recheche est impossible "

                user = x
                val = x['description']
                if (len(x['description']) > MYSY_GV.MAX_CARACT):
                    x['description'] = val[:MYSY_GV.MAX_CARACT] + " ..."
                else:
                    x['description'] = val[:MYSY_GV.MAX_CARACT]

                insertObject.append(JSONEncoder().encode(user))

            # mycommon.myprint(" insertObject = ", insertObject)

            ''' en cas de resultat vide, enregsitrement de la requete de recherche avec les filtres associé'''
            if( nb_result == 0):
                my_recid = {}
                my_recid['user_rec_id'] = str(user_recid)
                mydict_combined = {**diction, **my_recid}
                mydict_combined['date_update'] = str(datetime.now())
                mydict_combined['type_view'] = "summary"


                '''
                Statistique : Insertion du recherche - resultat '''
                ret_val_tmp = coll_search_result.insert_one(mydict_combined)
                if (ret_val_tmp is False):
                    mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible de mettre à jour la table des resultat"
                                                                  " d'une recherche de formation. Voir _id = ")
                    return False, "La recheche est impossible "

            return True, insertObject
            # Fin de la recherche par tips.


        tab_training = []
        tab_training = ela_index.ela_recherche_tokens(search_text)

        '''
        pour analyser la recherche, decommenter les 2 lignes ci-dessous
        '''
        mycommon.myprint(" pour phrase : #" + search_text + "#, voici la liste des formations")
        mycommon.myprint(tab_training)


        coll_name = MYSY_GV.dbname['myclass']
        '''
        la valeur nb_result permettra de savoir si la requete a donnée un resultat.
        si ce n'est pas le cas, il faudra à la fin enregistrer la requete avec un result a vide'''
        nb_result = 0
        insertObject = []

        for x in coll_name.find({"external_code":{"$in":tab_training}, 'published':'1'},
                                {"_id": 0, "indexed": 0, "indexed_desc": 0,
                                 "indexed_obj": 0, "indexed_title": 0, "valide": 0,
                                 "locked": 0 }).sort([("display_rank", pymongo.DESCENDING), ("price", pymongo.ASCENDING), ("date_update", pymongo.DESCENDING), ]):

            nb_result = nb_result + 1
            my_recid = {}
            my_recid['user_rec_id'] = str(user_recid)
            #print(" XXXXXXXXXX = "+str(x))
            mydict_combined = {**diction, **x, **my_recid}
            mydict_combined['date_update'] = str(datetime.now())
            mydict_combined['type_view'] = "summary"
            #print( "mydict_combined YYYYYYYYY = "+str(mydict_combined))

            if ("_id" in mydict_combined.keys()):
                mydict_combined['class_id'] = mydict_combined.pop('_id')


            '''
            Statistique : Insertion du recherche - resultat '''
            ret_val_tmp = coll_search_result.insert_one(mydict_combined)
            if (ret_val_tmp is False):
                mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible de mettre à jour la table des resultat"
                                                              " d'une recherche de formation. Voir _id = ")
                return False, "La recheche est impossible "

            user = x

            val = mycommon.clean_emoji(str(x['description']))

            if (len(x['description']) > MYSY_GV.MAX_CARACT):
                x['description'] = val[:MYSY_GV.MAX_CARACT] + " ..."
            else:
                x['description'] = val[:MYSY_GV.MAX_CARACT]
            insertObject.append(JSONEncoder().encode(user))

        '''
        /!\ Important : Recuperation des elements de la recherche etendue
        c'est a dire l'utilisation d'API externe
        
        /!\ update du 20/05/22 : Cette approche relentie bcp le systeme avec l'appel externe.
        donc on annule
        
        # aller chercher la recherche etendue et la rajouter ici.
        ext_status, external_code_prefixe = mycommon.Get_Extended_Result(search_text)



        if(ext_status is True):
            exten_coll = MYSY_GV.YTUBES_dbname['mysyserpapi']
            for x in exten_coll.find({'external_code': {'$regex': re.compile(r".*" + str(external_code_prefixe) + ".*")}},
                                     {"_id": 0, "valide": 0, }):

                nb_result = nb_result + 1
                my_recid = {}
                my_recid['user_rec_id'] = str(user_recid)
                user = x
                val = x['description']
                if (len(x['description']) > MYSY_GV.MAX_CARACT):
                    x['description'] = val[:MYSY_GV.MAX_CARACT] + " ..."
                else:
                    x['description'] = val[:MYSY_GV.MAX_CARACT]

                x['extented_search'] = "1"


                if str(x['url']) not in str(insertObject):
                    insertObject.append(JSONEncoder().encode(user))
                else:
                    print(str(x['url'])+" existe deja, pas d'ajout à faire ")

        '''
        #print(insertObject)
        #print(" result ok ")
        ''' en cas de resultat vide, enregsitrement de la requete de recherche avec les filtres associé'''
        if (nb_result == 0):
            my_recid = {}
            my_recid['user_rec_id'] = str(user_recid)
            mydict_combined = {**diction, **my_recid}
            mydict_combined['date_update'] = str(datetime.now())
            mydict_combined['type_view'] = "summary"

            '''
            Statistique : Insertion du recherche - resultat '''
            ret_val_tmp = coll_search_result.insert_one(mydict_combined)
            if (ret_val_tmp is False):
                mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible de mettre à jour la table des resultat"
                                                              " d'une recherche de formation. Voir _id = ")
                return False, "La recheche est impossible "


        return True, insertObject

    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 de lancer la recherche"






'''
Cette fonction enregistre les recherches faites par les user
dans la base de données.
L'idée principale est de stocker toutes les recherche, que soit en mode connecté ou en mode non connecté.
le difference se fera au niveau du mail de la personne.
structure du document dans la BDD (id, uer_mail, text_recherche, critere_recherce(JSON), valide)
la fontion prend en entrée un dictionnaire : 
- le texte
- la liste des critères; dont les valeurs exacts sont : 
    •	type 
    •	lang
    •	level
    •	dist  (distance) 
    •	price
    •	certif
    •	source 

Dans le cas ou le user a donnée un nom à la recherche, on ajoute le champ "name", ou s'il d'agit d'une mise à jour
le champ "id"
    •	name 
    •	id 
    
'''

def store_recherche(diction, user_recid=""):
    try:
        '''
        # Verification que les champs reçus dans l'API sont bien dans la liste des champs autorisés
        # Cela evite le cas ou une entité tierce ajouter les valeurs inconnu dans l'API
        # Ici on doit mettre tous les champs possible (obligatoire ou non) de la BDD dans la liste
        # field_list.
        '''

        if (  len(str(user_recid)) <= 0 ):
            user_recid = 'None'  # by default



        field_list = ['token', 'user_ip', 'user_country_code', 'user_country_name', 'user_city',
         'user_postal', 'user_latitude', 'user_longitude', 'user_state', 'search_text', 'certif',
         'support', 'type', 'lang', 'price', 'distance', 'duration']
        incom_keys = diction.keys()
        for val in incom_keys:
            if val not in field_list:
                mycommon.myprint(str(inspect.stack()[0][3]) + "  Le champ  '" + val + "' n'existe pas, recherche annulée")
                return False, "  Le champ  '" + val + "' n'existe pas, recherche annulée", None

        '''
        Une fois qu'on a controlé que toutes les clés mise dans l'API sont correcte. etape precedente,
        On controle que les champs obligatoires sont presents dans la liste 
        '''
        field_list_obligatoire = ['search_text', 'token']

        for val in field_list_obligatoire:
            if val not in diction:
                mycommon.myprint(" : La valeur '" + val + "' n'est pas presente dans liste ")
                return False, " : La valeur '" + val + "' n'est pas presente dans liste ", None


        # recuperation des paramettre
        mydata = {}
        mydata_id = ""
        my_token = ""

        if ("search_text" in diction.keys()):
            if diction['search_text']:
                mydata['search_text'] = diction['search_text']


        if ("user_mail" in diction.keys()):
            if diction['user_recid']:
                mydata['user_recid'] = diction['user_recid']

        if ("token" in diction.keys()):
            if diction['token']:
                my_token = diction['token']

        '''# Recuperation du recid de l'utilisateur
        user_recid = mycommon.get_user_recid_from_token(my_token)
        if user_recid is False:
            mycommon.myprint(" Impossible d'enregistrer la recherche de utilisateur")
            return False, " Impossible d'enregistrer la recherche de utilisateur"
        '''
        mydata['user_recid'] = user_recid
        mydata['document_recherche'] = "formation"

        if ("type" in diction.keys()):
            if diction['type']:
                mydata['type'] = diction['type']

        if ("lang" in diction.keys()):
            if diction['lang']:
                mydata['lang'] = diction['lang']

        if ("level" in diction.keys()):
            if diction['level']:
                mydata['level'] = diction['level']

        if ("dist" in diction.keys()):
            if diction['dist']:
                mydata['dist'] = diction['dist']

        if ("price" in diction.keys()):
            if diction['price']:
                mydata['price'] = diction['price']

        if ("certif" in diction.keys()):
            if diction['certif']:
                mydata['certif'] = diction['certif']

        if ("source" in diction.keys()):
            if diction['source']:
                mydata['source'] = diction['source']

        if ("name" in diction.keys()):
            if diction['name']:
                mydata['name'] = diction['name']


        if ("id" in diction.keys()):
            if diction['id']:
                mydata_id = diction['id']

        mydata['date_update'] = str(datetime.now())

        mydata['valide'] = "1" # By default
        if ("valide" in diction.keys()):
            if diction['valide']:
                mydata['valide'] = diction['valide']


        coll_name = MYSY_GV.dbname['user_recherche']

        # Si le champ "id" est renseigné, il s'agit d'une mis jour
        #mycommon.myprint(str(inspect.stack()[0][3]) + " on va stocker "+str(mydata)+"  id = "+str(mydata_id))

        if( len(str(mydata_id)) > 0 ):
            ret_val = coll_name.find_one_and_update({'_id': ObjectId(str(mydata_id)), 'valide': '1'},
                                                {"$set": mydata},
                                                    return_document=ReturnDocument.AFTER
                                                )

            if (ret_val and ret_val['_id']):
                nb_doc = str(ret_val['_id'])
                mycommon.myprint(str(inspect.stack()[0][3]) + " La recherche a bien été mise à jour . Le Doc Id    = "+str(nb_doc))
                return True, "La recherche a bien été mise à jour", ret_val['_id']

            else:
                return False, "Impossible de mettre à jour a la recherche", None

        else:
            ret_val = coll_name.insert_one(mydata)

            if ret_val and ret_val.inserted_id:
                nb_doc = ret_val.inserted_id
                #mycommon.myprint(str(inspect.stack()[0][3]) + " La recherche a été bien enregistrée. Id = '" + str(nb_doc)+"' ")
                return True, "La recherche a bien été mise à jour", nb_doc
            else:
                mycommon.myprint(
                    str(inspect.stack()[0][3]) + "Impossible d'enregistrer la recherche")
                return False, "Impossible d'enregistrer la recherche ", None


    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'enregistrer la recherche", None




'''
Cette fonction prend une chaine de recherche en mode tips.
Si la fonction detecte un tips, alors elle retroune un 
1 - Un status = True et 
2 - Un tableau avec qui contient uniquement la reference externe de la formation


Si la fonction ne detecte pas de tips, elle retoure
1 - Un status = False
2 - Un tableau  = False
'''

def recherche_tips_ret_ref(diction):
    try:
        '''
        # Verification que les champs reçus dans l'API sont bien dans la liste des champs autorisés
        # Cela evite le cas ou une entité tierce ajouter les valeurs inconnu dans l'API
        # Ici on doit mettre tous les champs possible (obligatoire ou non) de la BDD dans la liste
        # field_list.
        '''

        #print(" RRRRR "+str(diction))
        field_list =  ['search_text', 'token', 'support', 'id',
                       'type', 'lang', 'level', 'dist', 'price',
                       'certif', 'source', 'name','valide', 'duration', 'distance']
        incom_keys = diction.keys()
        for val in incom_keys:
            if val not in field_list:
                mycommon.myprint(str(inspect.stack()[0][3])+" -  Le champ  '" + val + "' n'est pas autorisé, recherche annulée")
                return False, "  Le champ  '" + val + "' n'est pas autorisé, recherche annulée"

        '''
        Une fois qu'on a controlé que toutes les clés mise dans l'API sont correcte. etape precedente,
        On controle que les champs obligatoires sont presents dans la liste 
        '''
        field_list_obligatoire = ['search_text', 'token']

        for val in field_list_obligatoire:
            if val not in diction:
                mycommon.myprint(str(inspect.stack()[0][3])+" -  La valeur '" + val + "' n'est pas presente dans liste ")
                return False, " : La valeur '" + val + "' n'est pas presente dans liste "

        user_recid = "None"
        # recuperation du recId du user si le token est fourni.
        # si le token est vide, c'est que nous sommes sur une recherche en mode non connecté.
        if (len(str(diction['token'])) > 0):
            user_recid = mycommon.get_user_recid_from_token(str(diction['token']))
            if user_recid is False :
                mycommon.myprint(str(inspect.stack()[0][3])+" - Impossible de recuperer le recid du user")
                return False, "Impossible d'enregistrer la recherche"


        print(" #######  recherche tips, voici mon new diction"+str(diction)+ "  user_recid = "+user_recid)

        # Enregistrerment de la recherche
        retval, message, store_recherche_Id = store_recherche(diction, user_recid)
        if( retval is False):
            return retval, message


        # recuperation des paramettre
        search_text = ""
        user_mail = ""
        token = ""

        if ("search_text" in diction.keys()):
            if diction['search_text']:
                search_text = diction['search_text']


        if( len(str(search_text)) <= 0 ):
            return False, False

        if (":" not in search_text):
            print(" La phrase ne contient pas de ':' ")
            return False, False

        print(" la chaine recu est "+search_text)
        chaine = search_text.split(":")

        val1 = str(chaine[0]).lower()

        print(" chaine[0] = "+val1)

        # Liste des tips acceptés
        tab_tips = ['title', 'description', 'desc',  'objectif', 'obj','trainer']

        min = 100
        my_tips = ""
        for val in tab_tips:
            retval = mycommon.levenshtein(val1, val)
            #print(" la distance entre '"+val1+"' et le mot  "+str(val)+" = "+str(retval))
            if( retval <= min ):
                min = retval
                my_tips = val

        if (min >= len(str(val1)) or min >= len(str(my_tips))  ):
            mycommon.myprint(str(inspect.stack()[0][3])+" -  le mot '"+val1+" ne correspond aucun tips, sorry")
            return False, " le mot '"+val1+" ne correspond aucun tips, sorry"

        if (str(my_tips) == "desc"):
            my_tips = 'description'

        mycommon.myprint(" Le tips recherché est "+my_tips+". Sa distance de Levenshtein ="+str(min))

        tab_ret = {}
        tab_ret['tips'] = str(my_tips)
        tab_ret['search_text'] = str(chaine[1]).lower()

        #return True, " le tips recherché est '"+my_tips+"' "

        tab_training = []
        tab_training = ela_index.ela_recherche_tokens_source_field(str(chaine[1]).lower(), str(my_tips) )

        if( tab_training is False):
            return False, tab_training

        #mycommon.myprint(" pour phrase : #" + str(chaine[1]).lower() + "# , Pour le tips #"+ str(my_tips)+"#, voici la liste des formations")
        #mycommon.myprint(tab_training)

        coll_name = MYSY_GV.dbname['myclass']

        return True, tab_training


        # ici lancer la recherche sur le champs title sss
        #return True, str(tab_ret)

    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, "N/A"




'''
Cette fonction prend une chaine de recherche en mode tips.
Si la fonction detecte un tips, alors elle retroune un 
1 - Un status = True et 
2 - Un tableau avec 
    - Tab[0] : le champ sur lequel s'applique la recherche
    - Tab[0] : la chaine à rechercher

Si la fonction ne detecte pas de tips, elle retoure
1 - Un status = False
2 - Un tableau  = False
'''

def recherche_tips(diction):
    try:
        '''
        # Verification que les champs reçus dans l'API sont bien dans la liste des champs autorisés
        # Cela evite le cas ou une entité tierce ajouter les valeurs inconnu dans l'API
        # Ici on doit mettre tous les champs possible (obligatoire ou non) de la BDD dans la liste
        # field_list.
        '''


        field_list =  ['search_text', 'token', 'support', 'id',
                       'type', 'lang', 'level', 'dist', 'price',
                       'certif', 'source', 'name','valide']

        incom_keys = diction.keys()
        for val in incom_keys:
            if val not in field_list:
                mycommon.myprint(str(inspect.stack()[0][3])+" -  Le champ  '" + val + "' n'existe pas, recherche annulée")
                return False, "  Le champ  '" + val + "' n'existe pas, recherche annulée"

        '''
        Une fois qu'on a controlé que toutes les clés mise dans l'API sont correcte. etape precedente,
        On controle que les champs obligatoires sont presents dans la liste 
        '''
        field_list_obligatoire = ['search_text', 'token']

        for val in field_list_obligatoire:
            if val not in diction:
                mycommon.myprint(str(inspect.stack()[0][3])+" -  La valeur '" + val + "' n'est pas presente dans liste ")
                return False, " : La valeur '" + val + "' n'est pas presente dans liste "

        user_recid = "None"
        # recuperation du recId du user si le token est fourni.
        # si le token est vide, c'est que nous sommes sur une recherche en mode non connecté.
        if (len(str(diction['token'])) > 0):
            user_recid = mycommon.get_user_recid_from_token(str(diction['token']))
            if user_recid is False :
                mycommon.myprint(str(inspect.stack()[0][3])+" - Impossible de recuperer le recid du user")
                return False, "Impossible d'enregistrer la recherche"


        print(" #######  recherche tips, voici mon new diction"+str(diction)+" RRRC ID = "+user_recid)

        # Enregistrerment de la recherche
        retval, message, store_recherche_Id = store_recherche(diction, user_recid)
        if( retval is False):
            return retval, message


        # recuperation des paramettre
        search_text = ""
        user_mail = ""
        token = ""

        if ("search_text" in diction.keys()):
            if diction['search_text']:
                search_text = diction['search_text']


        if( len(str(search_text)) <= 0 ):
            return False, False

        if (":" not in search_text):
            print(" La phrase ne contient pas de ':' ")
            return False, False

        print(" la chaine recu est "+search_text)
        chaine = search_text.split(":")

        val1 = str(chaine[0]).lower()

        print(" chaine[0] = "+val1)

        # Liste des tips acceptés
        tab_tips = ['title', 'description', 'desc',  'objectif', 'obj','trainer']

        min = 100
        my_tips = ""
        for val in tab_tips:
            retval = mycommon.levenshtein(val1, val)
            #print(" la distance entre '"+val1+"' et le mot  "+str(val)+" = "+str(retval))
            if( retval <= min ):
                min = retval
                my_tips = val

        if (min >= len(str(val1)) or min >= len(str(my_tips))  ):
            mycommon.myprint(str(inspect.stack()[0][3])+" -  le mot '"+val1+" ne correspond aucun tips, sorry")
            return False, " le mot '"+val1+" ne correspond aucun tips, sorry"

        '''
        Remplacement de l'abreviation 'desc' par description '''

        if( str(my_tips) == "desc"):
            my_tips = 'description'


        mycommon.myprint(" Le tips recherché est '"+my_tips+"'. Sa distance de Levenshtein ="+str(min))

        tab_ret = {}
        tab_ret['tips'] = str(my_tips)
        tab_ret['search_text'] = str(chaine[1]).lower()

        #return True, " le tips recherché est '"+my_tips+"' "

        tab_training = []
        tab_training = ela_index.ela_recherche_tokens_source_field(str(chaine[1]).lower(), str(my_tips) )

        if (tab_training is False):
            return False, tab_training

        '''
        Pour analyser les recherches, decommenter les 2 lignes ci-dessous
        '''
        #mycommon.myprint(" pour phrase : #" + str(chaine[1]).lower() + "# , Pour le tips #"+ str(my_tips)+"#, voici la liste des formations")
        #mycommon.myprint(tab_training)

        coll_name = MYSY_GV.dbname['myclass']

        insertObject = []
        for x in coll_name.find({"external_code": {"$in": tab_training}, 'published':'1'}, {"_id": 0, "indexed": 0, "indexed_desc": 0, "indexed_obj": 0, "indexed_title": 0,
                                                                           "valide": 0, "locked": 0, }):
            #mycommon.myprint(x)
            user = x
            val = x['description']
            if (len(x['description']) > MYSY_GV.MAX_CARACT):
                x['description'] = val[:MYSY_GV.MAX_CARACT] + " ..."
            else:
                x['description'] = val[:MYSY_GV.MAX_CARACT]
            insertObject.append(JSONEncoder().encode(user))

        # mycommon.myprint(" insertObject = ", insertObject)
        return True, insertObject


        # ici lancer la recherche sur le champs title sss
        #return True, str(tab_ret)

    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, "N/A"



'''
Cette fonction retourne les recherche enregistrer d'un user donnée
'''
def get_stored_recherche(diction):
    try:

        '''
        # Verification que les champs reçus dans l'API sont bien dans la liste des champs autorisés
        # Cela evite le cas ou une entité tierce ajouter les valeurs inconnu dans l'API
        # Ici on doit mettre tous les champs possible (obligatoire ou non) de la BDD dans la liste
        # field_list.
        '''
        field_list = ['token']
        incom_keys = diction.keys()
        for val in incom_keys:
            if val not in field_list:
                mycommon.myprint(str(inspect.stack()[0][3])+" -  Le champ  '" + val + "' n'existe pas, recherche annulée")
                return False, "  Le champ  '" + val + "' n'existe pas, recherche annulée"

        '''
        Une fois qu'on a controlé que toutes les clés mise dans l'API sont correcte. etape precedente,
        On controle que les champs obligatoires sont presents dans la liste 
        '''
        field_list_obligatoire = [ 'token']

        for val in field_list_obligatoire:
            if val not in diction:
                mycommon.myprint(str(inspect.stack()[0][3])+" - La valeur '" + val + "' n'est pas presente dans liste ")
                return False, " : La valeur '" + val + "' n'est pas presente dans liste "

        # recuperation des paramettre
        search_text = ""
        user_recid = ""
        token = ""

        if ("search_text" in diction.keys()):
            if diction['search_text']:
                search_text = diction['search_text']

        if ("token" in diction.keys()):
            if diction['token']:
                token = diction['token']


        # Verification de la validité du token/mail dans le cas des user en mode connecté
        if ( len(str(token)) <= 0):
            mycommon.myprint(str(inspect.stack()[0][3])+" -  Le token est vide")
            return False, " Impossible de recuperer historique de recherche"

        retval = mycommon.check_token_validity("", token)

        if retval is False:
            mycommon.myprint(str(inspect.stack()[0][3])+" -  Le token n'est pas valide")
            return False, " Impossible de recuperer l'historique de recherche"

        # Recuperation du recid du user
        user_recid = ""
        user_recid = mycommon.get_user_recid_from_token(token)
        if user_recid is False :
            mycommon.myprint(str(inspect.stack()[0][3])+" -  Impossible de recuperer le recid du user")
            return False, " Impossible de recuperer l'historique de recherche"


        coll_name = MYSY_GV.dbname['user_recherche']

        RetObject = []
        for retVal in coll_name.find({'user_recid': user_recid, 'valide':'1'}):
            #mycommon.myprint(str(retVal))
            user = retVal
            RetObject.append(JSONEncoder().encode(user))

        return True, RetObject

    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 de recuperer les recherches du user "

