import operator
cipher = """fasdfasdf ggbjmqqdef fdfwewef xvpoqwer sd sadff 
wewerr fasdf poyqqqqqert fgjwe asdf dfsdfqqqqqqjk qwervv jkqwert pqwer asdfn qwer
fasdf qwerfop lsdflk asdfjkddqweqqqqd qqqqqqqqqqqqqqqq
"""


class Attack:
    def __init__(self):
        self.alphabet = "abcdefghijklmnopqrstuvwxyz"
        self.plain_chars_left = "abcdefghijklmnopqrstuvwxyz"
        self.cipher_chars_left = "abcdefghijklmnopqrstuvwxyz"
        self.freq = {}
        self.freq_eng = {
            'a': 0.0817, 'b': 0.0150, 'c': 0.0278, 'd': 0.0425, 'e': 0.1270,
            'f': 0.0223, 'g': 0.0202, 'h': 0.0609, 'i': 0.0697, 'j': 0.0015,
            'k': 0.0077, 'l': 0.0403, 'm': 0.0241, 'n': 0.0675, 'o': 0.0751,
            'p': 0.0193, 'q': 0.0010, 'r': 0.0599, 's': 0.0633, 't': 0.0906,
            'u': 0.0276, 'v': 0.0098, 'w': 0.0236, 'x': 0.0015, 'y': 0.0197,
            'z': 0.0007
        }
        self.mappings = {}

    def calculate_freq(self, cipher):
        for c in self.alphabet:
            self.freq[c] = 0

        letter_count = 0
        for c in cipher:
            if c in self.freq:
                self.freq[c] += 1
                letter_count += 1

        for c in self.freq:
            self.freq[c] = round(self.freq[c]/letter_count, 4)

    def print_freq(self):
        for c in self.freq:
            print(c, ':', self.freq[c], end="\n")

    def calculate_matches(self):
        for cipher_char in self.alphabet:
            map = {}
            for plain_char in self.alphabet:
                map[plain_char] = round(
                    abs(self.freq[cipher_char] - self.freq_eng[plain_char]), 4)
            self.mappings[cipher_char] = sorted(
                map.items(), key=operator.itemgetter(1))

    def guess_key(self):
        key = {}
        for cipher_char in self.cipher_chars_left:
            for plain_char, diff in self.mappings[cipher_char]:
                if plain_char in self.plain_chars_left:
                    key[cipher_char] = plain_char
                    self.plain_chars_left = self.plain_chars_left.replace(
                        plain_char, "")
                    break

        return key


def decrypt(key, cipher):
    message = ""
    for c in cipher:
        if c in key:
            message += key[c]
        else:
            message += c
    return message


attack = Attack()
attack.calculate_freq(cipher)
attack.print_freq()
attack.calculate_matches()
key = attack.guess_key()

print()
print(key)
message = decrypt(key, cipher)
print(message)
