#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
#
# File encoder based on an own algorithm in Python3
# by Mario Nachbaur

'''
Usage: kripher (--encode | --decode) [--output --save] KEY FILE...

Encode or decode one or more files with a given numeric key.

Options:
    -e --encode     Encode the file
    -d --decode     Decode the file

    -o --output     Show the result
    -s --save       Save the result to the file

    -h --help       Display this message and quit

Examples:
    kripher -eo 1984 george.txt farm.txt
    kripher 1984 george.txt --decode --save
'''

from docopt import docopt

def saveFile(file, message):
    f = open(file, 'w')
    f.write(message)
    f.close()

def rot(n):
    low = 'abcdefghijklmnopqrstuvwxyz'
    cap = low.upper()
    low_trans = str.maketrans(low, low[n:] + low[:n])
    cap_trans = str.maketrans(cap, cap[n:] + cap[:n])

    return lambda s: str.translate(str.translate(s, low_trans), cap_trans)

def rotMessage(key, message, decoding = False):
    rot_message = ''
    maxlen = len(str(key)) - 1
    neg = -1 if decoding else 1
    i = 0

    for letter in message:
        r = neg * int(str(key)[i])
        rot_message += rot(r)(letter)
        i = i + 1 if i < maxlen else 0

    return rot_message

def encode(key, message):
    final = ''
    message = rotMessage(key, message)
    for y in message:
        y = ord(y) # Transforma cada caracter a su valor ASCII
        y *= key   # Cada caracter se codifica
        y += key
        y *= key
        y -= key
        y -= key
        final = final + str(y) + ' ' # Los caracteres se unen en una cadena

    return final.strip() # Quita el espacio final

def decode(key, message):
    final = ''
    message = message.split() # Separa el contenido en los elementos
    for y in message:
        try: # Si da error el archivo no está cifrado
            y = int(y)
        except ValueError:
            print(' :: File is not encoded with Kripher!')
            quit()
        y += key # Cada caracter se descodifica
        y += key
        y /= key
        y -= key
        y /= key
        y = chr(int(y)) # Transforma el valor ASCII a su caracter
        final += str(y) # Une los caracteres en una cadena

    return rotMessage(key, final, True)

def whatToDo(files):
    for f in set(files):
        try:
            message = open(f).read().strip() # Quita nuevas líneas
        except IOError:
            print(' :: File \'%s\' could not be read.' % f)
            break

        if args['--encode']:
            message = encode(key, message)
        elif args['--decode']:
            message = decode(key, message)

        if args['--save']:
            saveFile(f, message + '\n') # End with newline

        if args['--output']:
            #print('-' * 40)
            print('\n :: %s\n' % f)
            print(message)

if __name__ == '__main__':
    args = docopt(__doc__)

    if len(args['KEY']) < 2:
        print('Key should be 2 digits or more')
        quit()
    else:
        try:
            key = int(args['KEY'])
        except:
            print('The key is not numeric!')
            quit()

    if args['--save'] or args['--output']: # Trabajar solo si sirve para algo
        whatToDo(set(args['FILE'])) # set() devuelve sin duplicados
