# Créé par eclermont, le 13/09/2022 en Python 3.7
"""
    TD0 : Déchiffrer un texte avec la méthode de Metropolis
"""

import matplotlib.pyplot as plt
import random

def caractereVersEntier (car : str )-> int :
    """ 1.1
        caractereVersEntier (car : str) -> int
        entree : car chaine reduite a un caractère que l'on veut tranformer en entier
        sortie : la position de car dans l'alphabet (A:1, B:2, ..., Z:26) - 0 si car est un espace
    """
    if car == " " :
        return 0
    else :
        return ord(car) - 64   # 65 correspond au code ASCII de 'A' - 66 : 'B' - .... - 'Z':90
        # ou
        # return ord(car) - ( ord('A') -1)

def entierVersCaractere (position : int) -> str:
    """ 1.2
        caractereVersEntier (position : int) -> str
        entree : position la position de car dans l'alphabet
        sortie : car chaine associe à position " " si position à 0
    """
    if position == 0 :
        return " "
    else :
        return chr(position + 64)
    # Autre écriture possible
    # return " " if i == 0 else chr(position + 64)

def encode(texte: str)-> list:
    """ 1.3
        encode(texte : str) -> list
        entree : texte chaine de caractère que l'on doit transformer en liste d'entiers
        sortie : liste d'entiers qui correspond à l'endodage de texte
    """
    liste=[]
    for car in texte :
        liste.append( caractereVersEntier(car) ) #transformation de chaque caractere de texte en entier que l'on ajoute à liste
    return liste
    # Autre approche : en utilisant des listes par compréhension
    # return [ caractereVersEntier(car) for car in texte ]

def decode( liste : list ) -> str:
    """ 1.4
        decode(liste : list) -> str
        entree : liste, liste d'entiers  que l'on doit transformer en chaine
        sortie : ch, chaine de caracteres correspondant au decodage des entiers de la liste
    """
    ch =""
    for nb in liste :
        ch  += entierVersCaractere (nb) #concaténation de la chaine ch avec l'entier nb converti en caractère
    return ch

from random import shuffle
def genereCode( ) -> list :
    """ 1.5
        genereCode ( ) -> list
        sortie : code, liste d'entiers distribués aléatoirement
    """
    alphabet = list(range(1, 27))  # Generation d'une liste contenant les entiers de 1 à 27
    shuffle(alphabet)  # Mélange l'alphabet (opération en place : agit directement sur alphabet)
    code = [0] + alphabet  # On respecte f(0)=0
    return code

def chiffrer(texte : str, cle : list) -> str:
    """ 1.6
        chiffrer(texte : str, cle: list) -> str
        entrees : texte, chaine de caractères à chiffrer
                : cle, liste d'entiers qui correspond à la cle de chiffrement
        sortie  : texte_chiffre chaine qui correspond au texte chiffré avec cle
    """
    # Etape 1 : encodage de texte sous forme de liste d'entiers
    liste_indices_texte_encode = encode(texte)
    print( "Etape 1 : texte encode", liste_indices_texte_encode )

    # Etape 2 : generation de la liste d'entiers liste_indices_texte_chiffre
    # qui correspond a la correspondance de chaque entier avec la cle
    liste_indices_texte_chiffre = []  # Pour stocker les indices du texte chiffre
    for nb in liste_indices_texte_encode:
        nb_chiffre = cle[nb]  # Chiffre le caractère
        liste_indices_texte_chiffre.append( nb_chiffre )  # On ajoute a la liste des indices chiffrée
    print( "Etape 2 : liste_indices_texte_chiffre ", liste_indices_texte_chiffre )

    # Etape 3 : generation de la chaine de caractères correspondante => Chaine chiffrée
    texte_chiffre = decode( liste_indices_texte_chiffre ) # on transforme la liste de nb en chaine
    print( "Etape 3 : texte_chiffre",texte_chiffre )
    return texte_chiffre

def dechiffrer(texte : str, cle: list) -> str:
    """ 1.7
        dechiffrer(texte : str, cle: list) -> str
        entree  : texte chaine de caractères à dechiffrer
                : cle liste d'entiers qui correspond à la cle de chiffrement
        sortie  : texte_dechiffre chaine qui correspond au texte dechiffré
    """
    #Etape 1 : encodage sous forme de liste d'entiers
    liste_indices_texte_chiffre = encode(texte)

    #Etape 2 : generation de la liste d'entier correspondant au dechiffrement
    liste_indices_texte_dechiffre = []
    for nb in liste_indices_texte_chiffre:
        pos = cle.index(nb)  # On cherche la position de la lettre dans le code
        liste_indices_texte_dechiffre.append(pos)  # Ajoute a la liste d'entiers dechiffrée

    #Etape 3 : generation de la chaine correspondant
    texte_dechiffre = decode(liste_indices_texte_dechiffre)
    return texte_dechiffre

if __name__ == '__main__':

    # Etape 1
    # tests elementaires des fonctions
    print( caractereVersEntier ('C') ) # affiche 3
    print( caractereVersEntier (' ') ) # affiche 0

    print( entierVersCaractere (3) ) # affiche C
    print( entierVersCaractere (0) ) # affiche un espace

    print( 'Encodage' , encode('BONJOUR'))  # affiche [2, 15, 14, 10, 15, 21, 18]
    print( 'Encodage' , encode('BON JOUR')) # affiche [2, 15, 14, 0, 10, 15, 21, 18]

    print( 'Decodage',decode([2, 15, 14, 10, 15, 21, 18])) #affiche BONJOUR
    print( 'Decodage',decode([2, 15, 14, 0, 10, 15, 21, 18])) #affiche BON JOUR

    print ( genereCode () ) # exemple de generation
#[0, 5, 13, 3, 2, 25, 19, 9, 20, 16, 14, 15, 8, 4, 6, 22, 18, 1, 23, 26, 10, 21, 11, 24, 17, 12, 7]

    cle = [0, 5, 13, 3, 2, 25, 19, 9, 20, 16, 14, 15, 8, 4, 6, 22, 18, 1, 23, 26, 10, 21, 11, 24, 17, 12, 7]
    print ( "chiffrer", chiffrer('BONJOUR', cle) ) # affiche MVFNVUW
    print ( dechiffrer('MVFNVUW', cle) ) # affiche BONJOUR

    # Enchainement
    print("Etape 1")
    texte_test = "INFORMATIQUE TRONC COMMUN"
    cle = genereCode ()
    texte_chiffre = chiffrer(texte_test, cle)
    texte_dechiffre = dechiffrer(texte_chiffre, cle)

    print("\ttexte clair : ", texte_test)
    print("\tClé de chiffrement : ", cle)
    print("\ttexte chiffré : ", texte_chiffre)
    print("\ttexte déchiffré : ", texte_dechiffre)


