#!/usr/bin/env python3
# -*- coding: utf-8 -*-

#To feedback please contact me!
#Hill Cipher Check usable and encryption,decryption

import numpy as np
import string
from scipy import linalg
from random import randint
import sys


def check_usuable_matrix(key):
    #key =np.matrix(key)
    #print("Random key is: \n{}\n".format(key))
    msg= input("Enter the message [you can use also [space(\" \")||comma(\",\") ]: ").lower()
    msg=msg.replace(" ","")
    msg=msg.replace(",","")
    msg=msg.replace("'","")
    
    len_chk = 0
        
    if len(msg)%2 !=0:
        msg +="a"
        len_chk=1

    alpha = ['a','b','c','d','e','f','g','h','i','j','k','l',
            'm','n','o','p','q','r','s','t','u','v','w','x','y','z']
    matrix_key_array = list()

    x= list()
    y= list()
    for n in msg:
        if (n.isalpha())==False:
            print("\nYour input cannot use for encryption key[cause was showed with X]")
            x.append("X")
            intrp_program(x)
            
        if (n.isalpha())==True:
            for i in alpha:
                if n==i:
                    x.append(int(string.ascii_lowercase.index(n)))
       
    

            
    return msg,key,x

def intrp_program(x):
    print(x)
    sys.exit(0)

def resultMod(get_crypt):
    #print(get_crypt) #metin şifrelenmiş hali
    #mod26 almak
    #result=get_crypt 
    resultMod=np.mod(get_crypt,26)
    #print(get_crypt)
    #mod alınmış hali
    
    return resultMod

    
def convert2msg(msg,key,x): 

    row = 2
    col = int(len(msg)/2) #3 integer
    msgToMatrix = np.zeros((row, col), dtype=int)
        
    iteration1 = 0
    iteration2 = 0
    
    
         # te st A0
    #print(np.matrix(x))
    #print(msg)
    for i in range(len(msg)): # 6 integer
        if i % 2 == 0:
            msgToMatrix[0][iteration1]=int(ord(msg[i])-97)
            if msgToMatrix[0][iteration1]>26 or msgToMatrix[0][iteration1]<0:
                print("\nYour input cannot use for encryption key")
                sys.exit(0)
            iteration1 +=1
            
        else:
            msgToMatrix[1][iteration2] = int(ord(msg[i])-97)
            if msgToMatrix[1][iteration2]>26 or msgToMatrix[1][iteration2]<0:
                print("\nYour input cannot use for encryption key")
                sys.exit(0)
            iteration2 +=1
            
    msgToMatrix =np.matrix(msgToMatrix)
    print("\nMessage on matrix base : \n{}\n".format(msgToMatrix))
    #print(type(msgToMatrix))
    get_crypt=key*msgToMatrix; #ŞİFRELENMİŞ METİN
        #x=int(get_multi[0])
        #y=int(get_multi[1])
    #print(key)
    
    key =np.matrix(key)
    print("Random key is: \n{}\n".format(key))
    
    print("\nEncryption Text:\n {} \n ".format(get_crypt))  #şifrelenmiş mesaj
    
    resultModx=resultMod(get_crypt)
    print("\nMod26 for encryption text:\n {} \n ".format(resultModx))  
    
    return get_crypt
        
print("\n")
#def random_limit_generator():
#    limit=randint(1,50) 
#    return limit

def inverseMatris(keyx):
    #print("Key is: \n{}\n".format(keyx))
    np.set_printoptions(suppress=True)
    invMatris=np.linalg.inv(keyx)
   
    return invMatris
        
def key_generator():
        
    key_generator=np.random.randint(26,size=(2, 2)) #english alphabet.
    return key_generator


def decryptionMessage(decryption,x):
    #print("HEYYYYYY \n\n{} \n {}".format(type(decryption),decryption)) #matrix
    alpha = ['a','b','c','d','e','f','g','h','i','j','k','l',
            'm','n','o','p','q','r','s','t','u','v','w','x','y','z']
    
    decMessage=""
    for i in x:
        for a in alpha:
            if i==alpha.index(a):
                #print(type(i)) #int
                decMessage +=a[0]
  
    
    return decMessage
        
    

if __name__=="__main__":
    #print("Check key that usuable for Hill \n")
    #limit=random_limit_generator()
    keyx=key_generator()
    msg,key,x=check_usuable_matrix(keyx)#
    get_crypt=convert2msg(msg,key,x)
    resultMod(get_crypt)
    invMatris=inverseMatris(keyx)
    result=invMatris*get_crypt
    decMsg=decryptionMessage(result,x)
    
  
    print("\nDecryption key(inverse_matrix): \n {} \n".format(invMatris))
    print("\nVerification for first orginal text on matrix base:\n {} \n".format(result))
    print("\nGet Orginal Message text:\n {} \n".format(decMsg))
    
