# %%
import csv
import sqlite3
import pandas as pd
import dtale
import unicodedata
import sys
import random
# %%

# encoding/decoding functions for db
# %% funzione decodifica
def db_decode(string):
    res = ""
    with open("vettSpec.csv", 'r') as file1:
        reader = csv.DictReader(file1)
        vettSpec = [row for row in reader]
    for c in string:
        char_code = int.from_bytes(c.encode("utf-32-le"), 'little', signed=False)
        found = next((el['unicode'] for el in vettSpec if int(el['intcode']) == char_code), "")

        res += chr(int(found, 16))

    return res

#%% funzione codifica
def db_encode(string):
    encoded_string = ""
    with open("vettSpec.csv", 'r') as file1:
        reader = csv.DictReader(file1)
        vettSpec = [row for row in reader]
    for char in string:
        post = next((el['intcode'] for el in vettSpec if el['unicode'] == char.encode("utf-32-be").hex().lstrip('0').upper()), None)
        byteini = int.to_bytes(int(post), 4, byteorder='little')
        encoded_string += byteini.decode('utf-32-le')
    return encoded_string

#%% funzione combinazioni (gestione <>)
def combinations(s):
  result = []
  start = s.find("˴")
  end = s.find("˶")
  if start == -1 or end == -1:
    return [s]
  items = s[start + 1:end].split("Ñ")
  for item in items:
    result.extend([s[:start] + item + rest for rest in combinations(s[end + 1:])])
  return result

#%% funzione interprete (chiama le funzioni precedenti e sostituisce i caratteri jolly non standard)
def interpreter (data):
    encoded_data = db_encode(data)
    clean_data= "'"+encoded_data.replace("˯", "%").replace("Ò", "_")+"'"
    return combinations(clean_data)    

#%% raddoppia l'iniziale della stringa in ingresso (se non è un carattere jolly)     
def inizialeraddoppiata (data):
    doubleddata=[]
    for el in data:
        if el[1] != "%" and "_":
            doubleddata = doubleddata + ["'"+ el[1] + el[1:]]
    return doubleddata

#%% normalizza la stringa di testo togliendo i diacritici
def str_normalize(string):
    normalized_string = ""
    with open("atab.csv", 'r') as file1:
        reader = csv.DictReader(file1)
        atab = [row for row in reader]
    for c in string:
        char_code = int.from_bytes(c.encode("utf-32-le"), 'little', signed=False)
        found = next((el['norm'] for el in atab if int(el['spec']) == char_code), None)
        pre = found if found else ""
        byteini = int.to_bytes(int(pre), 4, byteorder='little')
        normalized_string += byteini.decode('utf-32-le')
    return normalized_string

#%% applica la normalizzazione a una lista di stringhe
def list_normalize(lista):
    return ["'" + str_normalize(stringa.strip("'")) + "'" for stringa in lista]

def db_results_decode (df):
    columns = ['forma', 'lemma', 'cat_gr', 'disambiguatore']
    for col in df.columns:
        if col in columns or col.startswith('highlight'):
            df[col] = df[col].apply(db_decode)
    #df = df.applymap(lambda x: db_decode(x) if type(x) == str else x)
    return df

#%% funzione lista tabelle occorrenziario   
def get_tables_occ(path):
    conn = sqlite3.connect(f"file:{path}/corpus.db?mode=ro", uri=True)
    cursor = conn.cursor()
    cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
    table_names = cursor.fetchall()
    occ_tables = [table[0] for table in table_names if table[0].startswith('Occ')]
    cursor.close()
    conn.close()
    return occ_tables

#funzione contatore risultati
def counter (results):
    if not results.empty:
        trovati= len(results.index)
        occorrenze= results['occ'].sum()
        return ("Trovati=" + str(trovati) + " Occorrenze=" + str(occorrenze))   
    
#%% funzioni test
def ricercaforme (entries, path, espansa, raddoppiata):
    if espansa == 0: 
        data=" OR spec LIKE ".join(entries)
        doubleddata=" OR spec LIKE ".join(inizialeraddoppiata(entries))
        
        if raddoppiata == 1: 
            theSimpleQuery = f"SELECT spec AS forma, nocc AS occ, cod FROM form WHERE spec LIKE {data} OR spec LIKE {doubleddata} ORDER BY idfor"
        else:
            theSimpleQuery = f"SELECT spec AS forma, nocc AS occ, cod FROM form WHERE spec LIKE {data} ORDER BY idfor"

        con = sqlite3.connect(f"file:{path}/corpus.db?mode=ro", uri=True)
        answer_table = pd.read_sql(theSimpleQuery, con)
        if answer_table.empty:
            print ("Nessun risultato")
            sys.exit(1)
        else:
            return answer_table

    else:

        data=" OR spec LIKE ".join(entries)
        data_norm=" OR norm LIKE ".join(list_normalize(entries))
        doubleddata_norm=" OR norm LIKE ".join(list_normalize(inizialeraddoppiata(entries)))
        doubleddata=" OR spec LIKE ".join(inizialeraddoppiata(entries))

        if raddoppiata == 1:
            theSimpleQuery = f"SELECT DISTINCT spec AS forma, nocc AS occ, cod FROM form WHERE (spec LIKE {data}) OR (norm LIKE {data_norm}) OR (spec LIKE {doubleddata}) OR (norm LIKE {doubleddata_norm}) ORDER BY idfor"
        else:
            theSimpleQuery = f"SELECT DISTINCT spec AS forma, nocc AS occ, cod FROM form WHERE (spec LIKE {data}) OR (norm LIKE {data_norm}) ORDER BY idfor"

        con = sqlite3.connect(f"file:{path}/corpus.db?mode=ro", uri=True)
        answer_table = pd.read_sql(theSimpleQuery, con)
        if answer_table.empty:
            print ("Nessun risultato")
            sys.exit(1)
        else:
            return answer_table

def findtexts(type, df, listOcc, path, index=None):
    if index is None:
        df = pd.DataFrame(df)
    else:
        if isinstance(index, range):
            index = list(index)
        elif not isinstance(index, list):
            index = [index]
        df = pd.DataFrame(df.loc[index])
    textlist = pd.DataFrame()
    codlist = list(df["cod"])
    con = sqlite3.connect(f"file:{path}/corpus.db?mode=ro", uri=True)
    for table in listOcc:
        strlist = ",".join(str(c) for c in codlist)
        if type == 0:
            Query = f"SELECT tab.cod, tab.ntx, tab.pitxt, tab.elemlen, tab.mappa, tab.numperiod, tab.links, tab.numorg, intbib.sigla, tab.vol, tab.pag, tab.riga, tab.col, tab.tipostanza, tab.stanza, tab.verso, tab.numbrano, lem.spec AS lemma, lem.cat AS cat_gr, lem.omo AS disambiguatore FROM {table} AS tab INNER JOIN intbib ON tab.ntx = intbib.ntx INNER JOIN lem ON tab.indlem = lem.cod WHERE tab.cod IN ({strlist})"
            extendequeryReponse = pd.read_sql(Query, con)
            textlist = pd.concat([textlist, extendequeryReponse])
        elif type == 1:
            Query = f"SELECT tab.cod, tab.ntx, tab.pitxt, tab.elemlen, tab.mappa, tab.numperiod, tab.links, tab.numorg, intbib.sigla, tab.vol, tab.pag, tab.riga, tab.col, tab.tipostanza, tab.stanza, tab.verso, tab.numbrano, lem.spec AS lemma, lem.cat AS cat_gr, lem.omo AS disambiguatore FROM {table} AS tab INNER JOIN intbib ON tab.ntx = intbib.ntx INNER JOIN lem ON tab.indlem = lem.cod WHERE tab.indlem IN ({strlist})"
            extendequeryReponse = pd.read_sql(Query, con)
            textlist = pd.concat([textlist, extendequeryReponse])
        elif type == 2:
            subquery = f"SELECT DISTINCT lemma, forma FROM pfl WHERE lemma IN ({strlist})"
            subdf = pd.read_sql(subquery, con)
            formcodlist = list(subdf["forma"])
            strform = ",".join(str(c) for c in formcodlist)
            Query = f"SELECT tab.cod, tab.ntx, tab.pitxt, tab.elemlen, tab.mappa, tab.numperiod, tab.links, tab.numorg, intbib.sigla, tab.vol, tab.pag, tab.riga, tab.col, tab.tipostanza, tab.stanza, tab.verso, tab.numbrano, lem.spec AS lemma, lem.cat AS cat_gr, lem.omo AS disambiguatore FROM {table} AS tab INNER JOIN intbib ON tab.ntx = intbib.ntx INNER JOIN lem ON tab.indlem = lem.cod WHERE tab.indlem IN ({strlist}) OR (tab.indlem = 0 AND tab.cod IN ({strform}))"
            extendequeryReponse = pd.read_sql(Query, con)
            textlist = pd.concat([textlist, extendequeryReponse])
    return textlist

def findcontexts(textlist, listOcc, path):
    contexts = []
    ampiezzacontesto = 31
    con = sqlite3.connect(f"file:{path}/corpus.db?mode=ro", uri=True)
    for ind, row in textlist.iterrows():
        pitxtLocal = row["pitxt"]
        sigla = row["sigla"]
        periodlocal = row["numperiod"]
        ntxlocal = row["ntx"]
        mappalocal = row["mappa"]
        pointerlist = pd.DataFrame()
        for table in listOcc:
            query = f"SELECT tab.pitxt, tab.elemlen FROM {table} AS tab WHERE tab.ntx = {ntxlocal} AND tab.mappa <= {mappalocal+int(ampiezzacontesto/2)} AND tab.mappa >= {mappalocal-int(ampiezzacontesto/2)}"
            queryresponse = pd.read_sql(query, con)
            pointerlist = pd.concat([pointerlist, queryresponse])
        with open(f"{path}/itxt/{sigla}", 'r', encoding="utf-32-le") as file1:
            file1.seek(4*pointerlist["pitxt"].min())
            cont = file1.read(pointerlist["pitxt"].max()-pointerlist["pitxt"].min())
            contexts.append(cont)
    textlist['contesto'] = contexts
    return (textlist.reset_index())

def findbib(contexts, path):
    infobib = pd.DataFrame()
    rif_org = pd.DataFrame()
    for ind, row in contexts.iterrows():
        con = sqlite3.connect(f"file:{path}/bibliografia/BiblioTLIO.db", uri=True)
        Query = f"SELECT [Anno iniziale], [Anno finale], [Data codificata], [Titolo Abbreviato], [Autore], [Titolo], [Curatore], [Data descrittiva], [Area generica], [Area specifica], [Genere], [Forma], [Tipo], IQ FROM datibib WHERE Sigla='{row['sigla']}'"
        bib = pd.read_sql(Query, con)
        infobib = pd.concat([infobib, bib])
        con2 = sqlite3.connect(f"file:{path}/corpus.db?mode=ro", uri=True)
        Query2 = f"SELECT head AS Rif_organico, full AS Rif_completo FROM org WHERE (indice='{row['numorg']}' AND ntx='{row['ntx']}')"
        rif = pd.read_sql(Query2, con2)
        rif_org = pd.concat([rif_org, rif])
    annoiniz = list(infobib['Anno iniziale'])
    annofin = list(infobib['Anno finale'])
    datacod = list(infobib['Data codificata'])
    datadesc = list(infobib['Data descrittiva'])
    titoloabb = list(infobib['Titolo Abbreviato'])
    autore = list(infobib['Autore'])
    titolo = list(infobib['Titolo'])
    curatore = list(infobib['Curatore'])
    areagen = list(infobib['Area generica'])
    areaspec = list(infobib['Area specifica'])
    genere = list(infobib['Genere'])
    forma = list(infobib['Forma'])
    tipo = list(infobib['Tipo'])
    iq = list(infobib['IQ'])
    rif1 = list(rif_org['Rif_organico'])
    rif2 = list(rif_org['Rif_completo'])
    contexts['Anno iniziale'] = annoiniz
    contexts['Anno finale'] = annofin
    contexts['Data codificata'] = datacod
    contexts['Data descrittiva'] = datadesc
    contexts['Autore'] = autore
    contexts['Titolo Abbreviato'] = titoloabb
    contexts['Titolo'] = titolo
    contexts['Curatore'] = curatore
    contexts['Area generica'] = areagen
    contexts['Area specifica'] = areaspec
    contexts['Genere'] = genere
    contexts['Forma'] = forma
    contexts['Tipo'] = tipo
    contexts ['IQ'] = iq
    contexts['Rif_organico'] = rif1
    contexts['Rig_completo'] = rif2
    contexts.pag = contexts.pag.astype(int)
    chrono = contexts.sort_values(by=['Anno iniziale', 'Rif_organico', 'pag'])   
    cols = ['links','Titolo Abbreviato', 'Rif_organico', 'tipostanza', 'stanza', 'verso', 'pag', 'riga', 'IQ', 'lemma', 'cat_gr', 'disambiguatore', 'contesto', 'Autore', 'Titolo',  'Anno iniziale', 'Anno finale', 'Data codificata', 'Data descrittiva', 'Area generica', 'Area specifica', 'Genere', 'Forma', 'Tipo', 'Curatore',  'cod', 'ntx', 'pitxt', 'elemlen', 'mappa', 'numperiod', 'numorg', 'sigla', 'vol', 'col', 'numbrano', 'Rig_completo']
    clean_df = chrono[cols].reset_index()
    return clean_df

def highlight (bibliocontexts, path):
    index = 0
    con = sqlite3.connect(f"file:{path}/corpus.db?mode=ro", uri=True)
    for col in bibliocontexts.columns:
        forme = []
        if col.startswith('cod'):
            for ind, row in bibliocontexts.iterrows():
                Query = f"SELECT spec FROM form WHERE cod={row[col]}"
                query_answer = pd.read_sql(Query, con)
                forme += list(query_answer['spec'])
            if index == 0:
                bibliocontexts['highlight'] = forme
            else:
                bibliocontexts['highlight'+str(index)] = forme
            index += 1
    return bibliocontexts

def contestimultipli (tipo_ricerca, ricerca, listOcc, path):
    textlist = findtexts(tipo_ricerca, ricerca, listOcc, path)
    contexts = findcontexts (textlist,listOcc, path)
    bibliocontexts = findbib (contexts, path)
    highlights = highlight(bibliocontexts, path)
    return highlights

def singlecontexts(textlist, index, parole, periodi, brani, listOcc, path):
    context = textlist.iloc[index]
    contexts = []
    formats = []
    con = sqlite3.connect(f"file:{path}/corpus.db?mode=ro", uri=True)
    sigla = textlist.loc[index, "sigla"]
    periodlocal = textlist.loc[index, "numperiod"]
    ntxlocal = textlist.loc[index, "ntx"]
    mappalocal = textlist.loc[index, "mappa"]
    linkslocal = textlist.loc[index, "links"]
    if parole != 0:
        pointerlist = pd.DataFrame()
        for table in listOcc:
            query = f"SELECT tab.pitxt, tab.elemlen FROM {table} AS tab WHERE tab.ntx = {ntxlocal} AND tab.mappa <= {mappalocal+int(parole/2)} AND tab.mappa >= {mappalocal-int(parole/2)}"
            queryresponse = pd.read_sql(query, con)
            pointerlist = pd.concat([pointerlist, queryresponse])
        with open(f"{path}/itxt/{sigla}", 'r', encoding="utf-32-le") as file1:
            file1.seek(4*pointerlist["pitxt"].min())
            cont = file1.read(pointerlist["pitxt"].max()-pointerlist["pitxt"].min())
            contexts.append(cont)
        with open(f"{path}/ftxt/{sigla}", 'rb') as file1:
            file1.seek(pointerlist["pitxt"].min()-1)
            formBytes = file1.read(pointerlist["pitxt"].max()-pointerlist["pitxt"].min())
            form = [byte for byte in formBytes]
            formats.append(form)
            context ['piniz'] = pointerlist["pitxt"].min()
            context ['pfin'] = pointerlist["pitxt"].max()
    elif periodi != 0:
        query = f"SELECT piniz, pfin FROM periodi WHERE ntx = {ntxlocal} AND numperiod <= {periodlocal+int(periodi/2)} AND numperiod >= {periodlocal-int(periodi/2)}"
        queryresponse = pd.read_sql(query, con)
        with open(f"{path}/itxt/{sigla}", 'r', encoding="utf-32-le") as file1:
            file1.seek(4*queryresponse["piniz"].min())
            cont = file1.read(queryresponse["pfin"].max()-queryresponse["piniz"].min())
            contexts.append(cont)
            context ['piniz'] = queryresponse["piniz"].min()
            context ['pfin'] = queryresponse["pfin"].max()
    elif brani != 0:
        if linkslocal == 0 or linkslocal == 1:
            return "Nessun brano associato a questo contesto"
        else:
            numbranolocal = textlist.loc[index, "numbrano"]
            query = f"SELECT piniz, pfin FROM linkbase WHERE {ntxlocal} = ntx AND tipo = 2 AND id BETWEEN {numbranolocal-int(brani/2)} AND {numbranolocal+int(brani/2)}"
            queryresponse = pd.read_sql(query, con)
            with open(f"{path}/itxt/{sigla}", 'r', encoding="utf-32-le") as file1:
                file1.seek(4*queryresponse["piniz"].min())
                cont = file1.read(queryresponse["pfin"].max()-queryresponse["piniz"].min())
                contexts.append(cont)
                context ['piniz'] = queryresponse["piniz"].min()
                context ['pfin'] = queryresponse["pfin"].max() 
    context['contesto'] = contexts [0]
    context['formattazione'] = formats
    return pd.DataFrame(context).T.reset_index(drop=True)


#%% funzione di ricerca dei brani associati. Ha in input singlecontexts.
def findlinks (context, path):
    con = sqlite3.connect(f"file:{path}/corpus.db?mode=ro", uri=True)
    linkslocal = context.loc[0, "links"]
    siglalocal = context.loc[0, "sigla"]
    ntxlocal = context.loc[0, "ntx"]
    pitxtlocal = context.loc[0, "pitxt"]
    pinizlocal = context.loc[0, "piniz"]
    pfinlocal = context.loc[0, "pfin"]
    if linkslocal == 0:
        return context
    if linkslocal == 1:
        query = f"SELECT ta.ntx, ta.id, ta.piniz, ta.pfin, tb.mappain, tb.mappafin FROM linkbase AS tb INNER JOIN linknoteass AS ta ON tb.ntx = ta.ntx AND tb.id = ta.id WHERE (((tb.tipo= 1) AND (tb.ntx = {ntxlocal})) AND ((tb.piniz BETWEEN {pinizlocal} AND {pfinlocal}) OR ({pitxtlocal} BETWEEN tb.piniz AND tb.pfin)))"
        queryresponse = pd.read_sql(query, con)
        with open(f"{path}/itxt/{siglalocal}", 'r', encoding="utf-32-le") as file1:
                file1.seek(4*queryresponse["piniz"].min())
                cont = file1.read(queryresponse["pfin"].max()-queryresponse["piniz"].min()-2)
        context['nota'] = cont
        return context
    if linkslocal == 2:
        query = f"SELECT ta.ntx, ta.id, ta.piniz, ta.pfin, tb.mappain, tb.mappafin FROM linkbase AS tb INNER JOIN linknoteass AS ta ON tb.ntx = ta.ntx AND tb.id = ta.id WHERE (((tb.tipo= 2) AND (tb.ntx = {ntxlocal})) AND ((tb.piniz BETWEEN {pinizlocal} AND {pfinlocal}) OR ({pitxtlocal} BETWEEN tb.piniz AND tb.pfin)))"
        queryresponse = pd.read_sql(query, con)
        with open(f"{path}/itxt/{siglalocal}", 'r', encoding="utf-32-le") as file1:
                file1.seek(4*queryresponse["piniz"].min())
                cont = file1.read(queryresponse["pfin"].max()-queryresponse["piniz"].min()-2)
        context['testo associato'] = cont
    if linkslocal == 3:
        query = f"SELECT ta.ntx, ta.id, ta.piniz, ta.pfin, tb.piniz AS iniz, tb.pfin AS fin, tb.mappain, tb.mappafin FROM linkbase AS tb INNER JOIN linknoteass AS ta ON tb.ntx = ta.ntx AND tb.id = ta.id WHERE (((tb.tipo= 1) AND (tb.ntx = {ntxlocal})) AND ((tb.piniz BETWEEN {pinizlocal} AND {pfinlocal}) OR ({pitxtlocal} BETWEEN tb.piniz AND tb.pfin)))"
        queryresponse = pd.read_sql(query, con)
        with open(f"{path}/itxt/{siglalocal}", 'r', encoding="utf-32-le") as file1:
                file1.seek(4*queryresponse["piniz"].min())
                cont = file1.read(queryresponse["pfin"].max()-queryresponse["piniz"].min()-2)
        context['nota'] = cont
        query2 = f"SELECT ta.ntx, ta.id, ta.piniz, ta.pfin, tb.piniz AS iniz, tb.pfin AS fin, tb.mappain, tb.mappafin FROM linkbase AS tb INNER JOIN linknoteass AS ta ON tb.ntx = ta.ntx AND tb.id = ta.id WHERE (((tb.tipo= 2) AND (tb.ntx = {ntxlocal})) AND ((tb.piniz BETWEEN {pinizlocal} AND {pfinlocal}) OR ({pitxtlocal} BETWEEN tb.piniz AND tb.pfin)))"
        queryresponse2 = pd.read_sql(query2, con)
        with open(f"{path}/itxt/{siglalocal}", 'r', encoding="utf-32-le") as file2:
                file2.seek(4*queryresponse2["piniz"].min())
                cont2 = file2.read(queryresponse2["pfin"].max()-queryresponse2["piniz"].min()-2)
        context['testo associato'] = cont2
    return context

#%% Ha in input links, associa i riferimenti bibliografici ad ogni contesto.
def singlefindbib(contexts, path):
    infobib = pd.DataFrame()
    rif_org = pd.DataFrame()
    for ind, row in contexts.iterrows():
        con = sqlite3.connect(f"file:{path}/bibliografia/BiblioTLIO.db?mode=ro", uri=True)
        Query = f"SELECT [Anno iniziale], [Titolo Abbreviato], IQ FROM datibib WHERE Sigla='{row['sigla']}'"
        bib = pd.read_sql(Query, con)
        infobib = pd.concat([infobib, bib])
        con2 = sqlite3.connect(f"file:{path}/corpus.db?mode=ro", uri=True)
        Query2 = f"SELECT head AS Rif_organico, full AS Rif_completo FROM org WHERE (indice='{row['numorg']}' AND ntx='{row['ntx']}')"
        rif = pd.read_sql(Query2, con2)
        rif_org = pd.concat([rif_org, rif])
    anno = list(infobib['Anno iniziale'])
    titolo = list(infobib['Titolo Abbreviato'])
    iq = list(infobib['IQ'])
    rif1 = list(rif_org['Rif_organico'])
    rif2 = list(rif_org['Rif_completo'])
    contexts['Anno iniziale'] = anno
    contexts['Titolo Abbreviato'] = titolo
    contexts ['IQ'] = iq
    contexts['Rif_organico'] = rif1
    contexts['Rig_completo'] = rif2
    contexts.pag = contexts.pag.astype(int)
    chrono = contexts.sort_values(by=['Anno iniziale', 'Rif_organico', 'pag'])   
    if 'nota' in chrono.columns and 'testo associato' in chrono.columns:
        cols = ['links','Titolo Abbreviato', 'Rif_organico', 'tipostanza', 'stanza', 'verso', 'pag', 'riga', 'IQ', 'lemma', 'cat_gr', 'disambiguatore', 'contesto', 'nota', 'testo associato', 'highlight']
    elif 'nota' in chrono.columns:
        cols = ['links','Titolo Abbreviato', 'Rif_organico', 'tipostanza', 'stanza', 'verso', 'pag', 'riga', 'IQ', 'lemma', 'cat_gr', 'disambiguatore', 'contesto', 'nota', 'highlight']
    elif 'testo associato' in chrono.columns:
        cols = ['links','Titolo Abbreviato', 'Rif_organico', 'tipostanza', 'stanza', 'verso', 'pag', 'riga', 'IQ', 'lemma', 'cat_gr', 'disambiguatore', 'contesto', 'testo associato', 'highlight']
    else:
        cols = ['links','Titolo Abbreviato', 'Rif_organico', 'tipostanza', 'stanza', 'verso', 'pag', 'riga', 'IQ', 'lemma', 'cat_gr', 'disambiguatore', 'contesto', 'highlight']
    chrono = chrono.drop(chrono.columns[0], axis=1)
    clean_df = chrono.reindex(columns=cols + list(chrono.columns.difference(cols)))
    return clean_df

# %% funzione contesti singoli

def contestosingolo (contestimultipli, indice, parole, periodi, brani, listOcc, path):
     contestosingolo = singlecontexts(contestimultipli, indice, parole, periodi, brani, listOcc, path)
     braniassociati = findlinks(contestosingolo, path)
     contestosingoloclean = singlefindbib (braniassociati, path)
     return contestosingoloclean

#%% funzioni decodifica contesti

def GeneraKey (sigla=None):
    # Genera i parametri di cifratura di un testo
    valore = [0, 0, 0]
    origine = None
    global LengKey, KeyBody
    con = sqlite3.connect(f"file:{path}/corpus.db?mode=ro", uri=True)
    query = f"SELECT notea,noteb,notec FROM Intbib WHERE lower(sigla)='{sigla}'"
    query_answer = pd.read_sql(query, con)
    valore[0] = int(query_answer['notea'][0])
    valore[1] = int(query_answer['noteb'][0])
    valore[2] = int(query_answer['notec'][0])
    print (valore)
    dato = valore[0] + valore[1]
    LengKey = 50 + (valore[2] % 300)
    if (LengKey // 2) * 2 != LengKey:
        LengKey = LengKey + 1
    KeyBody = [0] * LengKey
    iniziale = dato % (valore[2] + 123)
    random.seed(iniziale)
    for k in range(LengKey):
        KeyBody[k] = int(1000 * random.random())
path = "/Users/leonardocanova/Library/CloudStorage/OneDrive-ConsiglioNazionaledelleRicerche/TIGRO/Ricerche/db/ndg2.gat4"
GeneraKey("d17")

#%% funzione cifratura/decifratura
def CifraS(df, verso):
    # Cifra o decifra una stringa
    # StartInFile = posizione, all'interno del testo cifrato, del primo carattere della stringa da cifrare (base 1)
    # stringa = stringa da cifrare o decifrare
    # verso = 1 => cifra; 2 => decifra
    # FirstInStringa = indice del primo byte considerato all'interno del vettore da decifrare
    # LastInStringa = indice dell'ultimo byte considerato all'interno del vettore da decifrare
    # PosizInKey = indice del primo carattere da utilizzare all'interno della chiave fissa

    global LengKey, KeyBody
    print (KeyBody)
    print(LengKey)
    StartInFile = df['piniz'][0]
    stringa = df['contesto'] [0]
    print(StartInFile, stringa)
    NumCharsToConv = 0
    LastInStringa = 0
    LengKey2 = LengKey // 2
    while LastInStringa < len(stringa):
        StartInFile = StartInFile + NumCharsToConv
        NumKeyAppl = 1 + (StartInFile - 1) // LengKey2
        FirstInStringa = LastInStringa + 1
        PosizInKey = StartInFile % LengKey2
        if PosizInKey == 0:
            PosizInKey = LengKey2
        MaxCharsToConv = LengKey - PosizInKey + 1
        if MaxCharsToConv > LengKey2 - PosizInKey + 1:
            MaxCharsToConv = LengKey2 - PosizInKey + 1
        NumCharsToConv = len(stringa) - FirstInStringa + 1
        if NumCharsToConv > MaxCharsToConv:
            NumCharsToConv = MaxCharsToConv
        LastInStringa = FirstInStringa + NumCharsToConv - 1
        for k in range(FirstInStringa - 1, LastInStringa):
            if verso == 1:
                stringa = stringa[:k] + chr(ord(stringa[k]) + KeyBody[PosizInKey-1]) + stringa[k+1:]
            else:
                stringa = stringa[:k] + chr(ord(stringa[k]) - KeyBody[PosizInKey-1]) + stringa[k+1:]
                print("Stringa: "+stringa)
            PosizInKey += 1
    return stringa

#%% provine
testdec = 'ӗЫГҨғϩҘМϩӲѢҨҘ'
testdec2 = 'ӻ'
testenc = "recomandaţion"
testenc2 = "çà"
testnorm = "fòra"
path = "/Users/leonardocanova/Library/CloudStorage/OneDrive-ConsiglioNazionaledelleRicerche/TIGRO/Ricerche/db/ndg2.gat4"
listOcc = get_tables_occ(path)
ricerca = ricercaforme(interpreter(testenc), path, 1, 0)
#dtale.show(db_results_decode(ricerca))
contesti_multipli = contestimultipli(0, ricerca, listOcc, path)
contesto_singolo = contestosingolo(contesti_multipli, 0, 31, 0, 0, listOcc, path)
#dtale.show(db_results_decode(contesto_singolo))
#CifraS(contesto_singolo, 2)
# %%