%matplotlib inline

# Importing standard Qiskit libraries
import random
from qiskit import execute, Aer, IBMQ
from qiskit.tools.jupyter import *
from qiskit.visualization import *
from may4_challenge.ex3 import alice_prepare_qubit, check_bits, check_key, check_decrypted, show_message

# Configuring account
provider = IBMQ.load_account()
backend = provider.get_backend('ibmq_qasm_simulator')  # with this simulator it wouldn't work \

# Initial setup
random.seed(84) # do not change this seed, otherwise you will get a different key

# This is your 'random' bit string that determines your bases
numqubits = 100
bob_bases = str('{0:0100b}'.format(random.getrandbits(numqubits)))

def bb84():
    print('Bob\'s bases:', bob_bases)

    # Now Alice will send her bits one by one...
    all_qubit_circuits = []
    for qubit_index in range(numqubits):

        # This is Alice creating the qubit
        thisqubit_circuit = alice_prepare_qubit(qubit_index)

        # This is Bob finishing the protocol below
        bob_measure_qubit(bob_bases, qubit_index, thisqubit_circuit)

        # We collect all these circuits and put them in an array
        all_qubit_circuits.append(thisqubit_circuit)
    
    # Now execute all the circuits for each qubit
    results = execute(all_qubit_circuits, backend=backend, shots=1).result()

    # And combine the results
    bits = ''
    for qubit_index in range(numqubits):
        bits += [measurement for measurement in results.get_counts(qubit_index)][0]
        
    return bits

# Here is your task
def bob_measure_qubit(bob_bases, qubit_index, qubit_circuit):
    #
    #
    if bob_bases[qubit_index] == '0':
        qubit_circuit.measure(0, 0)
        
    elif bob_bases[qubit_index] == '1':
        qubit_circuit.h(0)
        qubit_circuit.measure(0, 0)
    #
    #
    ...

bits = bb84()        
print('Bob\'s bits: ', bits)
check_bits(bits)

alice_bases = '10000000000100011111110011011001010001111101001101111110001100000110000010011000111'\
              '00111010010000110' # Alice's bases bits
#
#
key = ''
for bit, alice_basis, bob_basis in zip(bits, alice_bases, bob_bases):
    if alice_basis == bob_basis: key += bit
#
#
check_key(key)

m = '0011011010100011101000001100010000001000011000101110110111100111111110001111100011100101011010111010111010001'\
    '1101010010111111100101000011010011011011011101111010111000101111111001010101001100101111011' # encrypted message
#
#
all_key_bits = key * 4
decrypted = ''
for key_bit, message_bit in zip(all_key_bits, m):
    decrypted += str(  (int(key_bit) + int(message_bit)) % 2)
#
#
check_decrypted(decrypted)

MORSE_CODE_DICT = { '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':'--..', 
                    '1':'.----', '2':'..---', '3':'...--', 
                    '4':'....-', '5':'.....', '6':'-....', 
                    '7':'--...', '8':'---..', '9':'----.', 
                    '0':'-----', ', ':'--..--', '.':'.-.-.-', 
                    '?':'..--..', '/':'-..-.', '-':'-....-', 
                    '(':'-.--.', ')':'-.--.-'} 
#
#
words_decoded = []
words_encoded = decrypted.split('000')
for word_encoded in words_encoded:
    letters_encoded = word_encoded.split('00')
    letters_decoded = ''
    for letter_encoded in letters_encoded:
        dotordashes = letter_encoded.split('0')
        letter_morse = ''
        for dotordash in dotordashes:
            if dotordash == '11':
                letter_morse += '-'
            elif dotordash == '1':
                letter_morse += '.'
        letters_decoded += next(key for key, value in MORSE_CODE_DICT.items() if value == letter_morse)
    words_decoded.append(letters_decoded)

solution = ' '.join(words_decoded)
#
#
show_message(solution)