import numpy as np
from PIL import Image

def get_matrix():
    img = Image.open("output2g.png").convert("L")
    P = (np.array(img) < 128).astype(np.uint8)
    return P

def main():
    P = get_matrix() # 16384 x 2048
    # H = [P^T | I]
    
    with open("codeword.bin", "rb") as f:
        c_bytes = f.read()
    
    if len(c_bytes) != 2304:
        print(f"Error: Codeword size {len(c_bytes)} != 2304")
        return
    
    # Convert bytes to bits
    c_bits = []
    for b in c_bytes:
        for i in range(8):
            c_bits.append((b >> i) & 1)
    c_bits = np.array(c_bits, dtype=np.uint8)
    
    # Data is first 16384 bits, parity is next 2048 bits
    d = c_bits[:16384]
    p = c_bits[16384:]
    
    # Calculate syndrome s = d*P + p
    # Vector-matrix mult over GF(2)
    s = np.zeros(2048, dtype=np.uint8)
    for i in range(16384):
        if d[i] == 1:
            s ^= P[i]
    s ^= p
    
    synd_weight = np.sum(s)
    print(f"Syndrome weight: {synd_weight}")
    if synd_weight == 0:
        print("Codeword is VALID.")
    else:
        print(f"Codeword is INVALID. Syndrome weight {synd_weight} bits.")
        
        # Try to find a single bit error
        # Syndrome should match a row of P or a column of I
        s_hex = "".join(map(str, s))
        
        # Check rows of P
        for i in range(16384):
            row_p = "".join(map(str, P[i]))
            if row_p == s_hex:
                print(f"Found single data bit error at bit {i}!")
                return
        
        # Check parity bits
        for i in range(2048):
            if synd_weight == 1 and s[i] == 1:
                print(f"Found single parity bit error at bit {i}!")
                return
        
        print("Not a single bit error.")

if __name__ == "__main__":
    main()
