'''
Cipher
======

Chiffre et déchiffre un message entrée par l'utilisateur en utilisant les
méthodes de César et de Vigenère.

La méthode de chiffrement de César consiste en substituer chaque caractère
d'un message par un autre caractère de l'alphabet. L'autre caractère est
obtenu en décalant l'alphabet de n positions. Ce décalage est donné par la
clé entrée par l'utilisateur.

Par exemple, soit le message :
« help me obi wan kanobi you're my only hope. »
et soit la clé secrète égal à 3. Nous avons le message chiffré :
« khos ph rel zdq kdqrel brx'uh pb rqob krsh. »
Chaque caractère du message est décalé de 3. Seul l'utilisateur connaît
la clé secrète pour pouvoir déchiffrer le message.

La méthode de chiffrement de Vigenère est une méthode plus sûre que celle
du César. Elle demande à l'utilisateur d'entrer un mot-clé de plusieurs
lettres. Chaque lettre est, en effet, une clé de la méthode de César. Pour
chaque caractère du message, la méthode de Vigenère utilise une des clés
données par le mot-clé. Ceci lui confère donc un peu plus de sécurité. 
'''


#ALPHABET_COMPLET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,.!?:; àáäâãèéêëçìíîïòóôöõùúüûÀÁÄÂÃÈÉÊËÇÌÍÎÏÒÓÖÕÙÚÜÛ'
#ALPHABET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'

from string import ascii_letters, digits
ACCENTS = 'àáâäèéêëìíîïòóôöùúûüç' 
ALPHABET = ascii_letters + ACCENTS + ACCENTS.upper() + digits

def input_mode():
    ''' Demande à l'utilisateur d'entrer le mode d'exécution :
    chiffrement ou déchiffrement.
    Arguments:
        None.
    Retour:
        str -- 'c' pour chiffrer.
               'd' pour déchiffrer.
    '''
    valide = False
    while not valide:
        ch = input('Voulez-vous chiffrer ou déchiffrer un message (c/d) ? ')
        ch = ch.lower()
        if ch != 'c' and ch != 'd':
            print('Option invalide !')
        else:
            valide = True
    return ch


def input_methode():
    ''' Demande à l'utilisateur d'entrer la méthode de chiffrement :
    César ou Vigenère.
    Arguments:
        None.
    Retour:
        str -- 'cesar' pour César.
               'vigenere' pour Vigenère.
    '''
    valide = False
    while not valide:
        ch = input('Quelle méthode voulez-vous utiliser (cesar / vigenere) ? ')
        ch = ch.lower()
        if ch != 'cesar' and ch != 'vigenere':
            print('Option invalide !')
        else:
            valide = True
    return ch


def input_cle():
    ''' Demande à l'utilisateur d'enter une clé de chiffrement.
    Arguments:
        None.
    Retour:
        str -- la clé.
    '''
    valide = False
    while not valide:
        cle = int(input('Entrez la clé de chiffrement (1-' + \
                        str(len(ALPHABET)) + ') : '))
        if 1 <= cle <= len(ALPHABET):
            valide = True
    return cle


def pos(c):
    ''' Retourne la position du caractère dans l'alphabet.
    Arguments:
        c : str -- un caractère.
    Retour:
        int -- la position ou -1 si ce n'est pas dans l'alphabet.
    '''
    for i in range(len(ALPHABET)):
        if c == ALPHABET[i]:
            return i
    return -1


def car(n):
    ''' Retourne le caractère correspondant à la position dans l'alphabet.
    Arguments:
        n : int -- un nombre.
    Retour:
        str -- le caractère correspondant.
    '''
    return ALPHABET[n]
        

def decale(c, dec):
    ''' Décale le caractère.
    Arguments:
        c : str -- un caractère.
        dec : int -- un décalage
    Retour:
        str -- le caractère décalée.
    '''
    p = pos(c)
    if p == -1:
        return c
    else:
        return car((p + dec) % len(ALPHABET))


def cesar(message, mode, cle):
    ''' Traduit le message en utilisant la méthode de César.
    Arguments:
        message : str -- un message.
        mode : int -- 'c' pour chiffrer et 'd' pour déchiffrer
        cle : int -- la clé.
    Retour:
        str -- le message traduit.
    '''
    # Si mode est déchiffrement, inverse la clé.
    if mode == 'd':
       cle = -cle 

    traduction = ''
    # Pour chaque caractère du message:
    for c in message:
        # Effectue le décalage.
        traduction += decale(c, cle)
    return traduction


def vigenere(message, mode, mot_cle):
    ''' Traduit le message en utilisant la méthode de Vigenère.
    Arguments:
        message : str -- un message.
        mode : int -- 'c' pour chiffrer et 'd' pour déchiffrer.
        mot_cle : str -- le mot-clé.
    Retour:
        str -- le message traduit.
    '''
    i = 0
    traduction = ''
    # Pour chaque caractère du message:
    for c in message:
        
        # Cherche la clé dans le mot-clé.
        cle = pos(mot_cle[i])

        # Si mode est déchiffrement, inverse la clé.
        if mode == 'd':
           cle = -cle

        # Effectue le décalage.
        traduction += decale(c, cle)

        # Change de clé.
        i = (i + 1) % len(mot_cle)

    return traduction


def _main():
    ''' Fonction principale.
    Arguments:
        None.
    Retour:
        None.
    '''
    message = input('Entrez votre message :\n')
    mode = input_mode()
    methode = input_methode()
    if methode == 'cesar':
        cle = input_cle()
        print('Résultat :')
        print(cesar(message, mode, cle))
    else:
        mot_cle = input('Entrez le mot-clé : ')
        print('Résultat :')
        print(vigenere(message, mode, mot_cle))


if __name__ == '__main__':
    _main()
