mod analysis;
mod code;
mod construction;
mod decoder;
mod encoder;
mod matrix;
mod tanner;

use code::LdpcCode;
use construction::random::generate_random_h;
use encoder::dense::DenseEncoder;

fn main() {
    // TODO : Changer la logique pour trouver k => calculer n selon la longueur du message k (en
    // rapport des poids) n = (k * w_r) / (w_r - w_c)
    println!("LDPC\n");

    let n = 12;
    let m = 6;
    let wc = 2;
    let wr = 4;

    let mut h_matrix = generate_random_h(m, n, wc, wr);
    println!("H aléatoire {m}x{n} :");
    h_matrix.print();

    let ldpc = LdpcCode::new(h_matrix.clone());
    println!("\nLDPC instancié");

    println!("Extraction de G");
    let encoder = DenseEncoder::new(&ldpc);

    println!("\n    -> Matrcie H après Gauss-Jordan avec inversion de colonne de la forme [I | A]");
    encoder.h_reduced.print();

    println!("G {}x{}", encoder.k, encoder.n);
    encoder.g_matrix.print();

    let message = vec![1; encoder.k];
    let codeword = encoder.encode(&message);

    println!("\nMessage u : {:?}", message);
    println!("\n Codeword s : {:?}", codeword);

    // let mut is_valid = true;
    // for r in 0..m {
    //     let mut sum = 0;
    //     for c in 0..n {
    //         sum ^= codeword[c] & h_matrix.get(r, c);
    //     }
    //     if sum != 0 {
    //         is_valid = false;
    //         break;
    //     }
    // }

    let is_valid = (0..m).all(|r| {
        let sum = codeword
            .iter()
            .enumerate()
            .fold(0, |acc, (c, &bit)| acc ^ (bit & h_matrix.get(r, c)));
        sum == 0
    });

    println!("\n{}", if is_valid { "Vrai" } else { "Faux" });

    // println!("\nGauss-Jordan sur H :");
    // h_matrix.gauss_jordan();
    // h_matrix.print();
}
