# %%
encode_table=[0, 15, 19, 28, 37, 42, 54, 57, 70, 73, 85, 90, 99, 108, 112, 127]
decode_table=[0, 0, 0, 2, 0, 4, 8, 1, 0, 9, 5, 1, 3, 1, 1, 1, 0, 2, 2, 2, 3, 10, 6, 2, 3, 7, 11, 2, 3, 3, 3, 1, 0, 4, 5, 12, 4, 4, 6, 4, 5, 7, 5, 5, 13, 4, 5, 1, 14, 7, 6, 2, 6, 4, 6, 6, 7, 7, 5, 7, 3, 7, 6, 15, 0, 9, 8, 12, 8, 10, 8, 8, 9, 9, 11, 9, 13, 9, 8, 1, 14, 10, 11, 2, 10, 10, 8, 10, 11, 9, 11, 11, 3, 10, 11, 15, 14, 12, 12, 12, 13, 4, 8, 12, 13, 9, 5, 12, 13, 13, 13, 15, 14, 14, 14, 12, 14, 10, 6, 15, 14, 7, 11, 15, 13, 15, 15, 15]

# %%
import numpy as np

import socket

HOST = '192.168.137.20'
PORT = 5000
server_addr = (HOST, PORT)

# %% [markdown]
# Encode with table

# %%
def hamming_encode_table_method(plaintext):
    return_list=list()
    for s in range(len(plaintext)):
        ### for debug check 
        # print(s) 
        # codeword1 = encode_table[int(plaintext[s]/16)]
        # print(codeword1)
        return_list.append(encode_table[int(plaintext[s]/16)])
        # codeword2 = encode_table[int(plaintext[s]%16)]
        # print(codeword2)
        return_list.append(encode_table[int(plaintext[s]%16)])
        # print(return_bytes)
    return bytes(return_list)

# %% [markdown]
# Decode with table

# %%
def hamming_decode_table_method(encryptext):
    return_list=list()
    for s in range(len(encryptext)):
        if s % 2 ==0:
            high_nibble=decode_table[int(encryptext[s])]
            low_nibble=decode_table[int(encryptext[s+1])]
            c_append=high_nibble*16+low_nibble
            # print(high_nibble)
            # print(low_nibble)
            # print(c_append)
            return_list.append(c_append)
        
    return bytes(return_list)

# %% [markdown]
# random add 1 bit error 

# %%
import random
def add_1bit_error(input_message):
    for s in range(len(input_message)):
        input_message[s] = (int(input_message[s]) ^ (1<< random.randint(0, 6)))
    return input_message

# %%
trans_count=0
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
client_socket.settimeout(5)
message = b'https://maker.wiznet.io/momososo'
while True:
    hamming_encoded_data = hamming_encode_table_method(message)

    # random add 1 bit error 
    hamming_encoded_data = add_1bit_error(bytearray(hamming_encoded_data))

    client_socket.sendto(bytes(hamming_encoded_data), server_addr)
    print(f'Send:{hamming_encoded_data}')
    try:
        data, server = client_socket.recvfrom(2048)
        hamming_decoded_data = hamming_decode_table_method(data)
        
        print(f'Decode:{hamming_decoded_data}')
        if hamming_decoded_data != message:
            print('Recive error')
            print(f'already trans:{trans_count}')
            break
        else:
            trans_count+=1

        # print(len(hamming_decoded_data))
        # message += hamming_decoded_data # lenth test stop at 2048 bytes

    except socket.timeout:
        print('REQUEST TIMED OUT')
        break
client_socket.close()
    


