// Copyright 2025 Don MacAskill. Licensed under MIT or Apache-2.0.

//! Utility to generate pre-computed 16-lane lookup tables for all CRC algorithms.
//!
//! This generates Rust source code that can be used to create the `src/tables.rs` module.
//! Run with: `cargo run --bin generate_tables > src/tables.rs`

use crc_fast::arch::software::{generate_table_u16, generate_table_u32, generate_table_u64};

fn main() {
    println!("// Copyright 2025 Don MacAskill. Licensed under MIT or Apache-2.0.");
    println!();
    println!("//! Pre-generated 16-lane lookup tables for CRC calculations.");
    println!("//!");
    println!("//! This file is auto-generated by `cargo run --bin generate_tables`.");
    println!("//! Do not edit manually.");
    println!();
    println!("#![allow(dead_code)]");
    println!();

    generate_crc16_tables();
    generate_crc32_tables();
    generate_crc64_tables();
}

fn generate_crc16_tables() {
    println!("pub mod crc16 {{");
    println!("    //! CRC-16 lookup tables");
    println!();

    // CRC-16 algorithms with their parameters: (name, poly, reflect)
    let algorithms: &[(&str, u16, bool)] = &[
        ("ARC", 0x8005, true),
        ("CDMA2000", 0xc867, false),
        ("CMS", 0x8005, false),
        ("DDS_110", 0x8005, false),
        ("DECT_R", 0x0589, false),
        ("DECT_X", 0x0589, false),
        ("DNP", 0x3d65, true),
        ("EN_13757", 0x3d65, false),
        ("GENIBUS", 0x1021, false),
        ("GSM", 0x1021, false),
        ("IBM_3740", 0x1021, false),
        ("IBM_SDLC", 0x1021, true),
        ("ISO_IEC_14443_3_A", 0x1021, true),
        ("KERMIT", 0x1021, true),
        ("LJ1200", 0x6f63, false),
        ("M17", 0x5935, false),
        ("MAXIM_DOW", 0x8005, true),
        ("MCRF4XX", 0x1021, true),
        ("MODBUS", 0x8005, true),
        ("NRSC_5", 0x080b, true),
        ("OPENSAFETY_A", 0x5935, false),
        ("OPENSAFETY_B", 0x755b, false),
        ("PROFIBUS", 0x1dcf, false),
        ("RIELLO", 0x1021, true),
        ("SPI_FUJITSU", 0x1021, false),
        ("T10_DIF", 0x8bb7, false),
        ("TELEDISK", 0xa097, false),
        ("TMS37157", 0x1021, true),
        ("UMTS", 0x8005, false),
        ("USB", 0x8005, true),
        ("XMODEM", 0x1021, false),
    ];

    for (name, poly, reflect) in algorithms {
        print_table_u16(name, 16, *poly, *reflect);
    }

    println!("}}");
    println!();
}

fn generate_crc32_tables() {
    println!("pub mod crc32 {{");
    println!("    //! CRC-32 lookup tables");
    println!();

    // CRC-32 algorithms with their parameters: (name, poly, reflect)
    let algorithms: &[(&str, u32, bool)] = &[
        ("AIXM", 0x814141ab, false),
        ("AUTOSAR", 0xf4acfb13, true),
        ("BASE91_D", 0xa833982b, true),
        ("BZIP2", 0x04c11db7, false),
        ("CD_ROM_EDC", 0x8001801b, true),
        ("CKSUM", 0x04c11db7, false),
        ("ISCSI", 0x1edc6f41, true),
        ("ISO_HDLC", 0x04c11db7, true),
        ("JAMCRC", 0x04c11db7, true),
        ("MEF", 0x741b8cd7, true),
        ("MPEG_2", 0x04c11db7, false),
        ("XFER", 0x000000af, false),
    ];

    for (name, poly, reflect) in algorithms {
        print_table_u32(name, 32, *poly, *reflect);
    }

    println!("}}");
    println!();
}

fn generate_crc64_tables() {
    println!("pub mod crc64 {{");
    println!("    //! CRC-64 lookup tables");
    println!();

    // CRC-64 algorithms with their parameters: (name, poly, reflect)
    let algorithms: &[(&str, u64, bool)] = &[
        ("ECMA_182", 0x42f0e1eba9ea3693, false),
        ("GO_ISO", 0x000000000000001b, true),
        ("MS", 0x259c84cba6426349, true),
        ("NVME", 0xad93d23594c93659, true),
        ("REDIS", 0xad93d23594c935a9, true),
        ("WE", 0x42f0e1eba9ea3693, false),
        ("XZ", 0x42f0e1eba9ea3693, true),
    ];

    for (name, poly, reflect) in algorithms {
        print_table_u64(name, 64, *poly, *reflect);
    }

    println!("}}");
}

fn print_table_u16(name: &str, width: u8, poly: u16, reflect: bool) {
    let table = generate_table_u16(width, poly, reflect);

    println!("    pub static CRC16_{}_TABLE: [[u16; 256]; 16] = [", name);
    for lane in &table {
        println!("        [");
        for chunk in lane.chunks(8) {
            print!("            ");
            for (i, val) in chunk.iter().enumerate() {
                print!("0x{:04x}", val);
                if i < chunk.len() - 1 {
                    print!(", ");
                }
            }
            println!(",");
        }
        println!("        ],");
    }
    println!("    ];");
    println!();
}

fn print_table_u32(name: &str, width: u8, poly: u32, reflect: bool) {
    let table = generate_table_u32(width, poly, reflect);

    println!("    pub static CRC32_{}_TABLE: [[u32; 256]; 16] = [", name);
    for lane in &table {
        println!("        [");
        for chunk in lane.chunks(4) {
            print!("            ");
            for (i, val) in chunk.iter().enumerate() {
                print!("0x{:08x}", val);
                if i < chunk.len() - 1 {
                    print!(", ");
                }
            }
            println!(",");
        }
        println!("        ],");
    }
    println!("    ];");
    println!();
}

fn print_table_u64(name: &str, width: u8, poly: u64, reflect: bool) {
    let table = generate_table_u64(width, poly, reflect);

    println!("    pub static CRC64_{}_TABLE: [[u64; 256]; 16] = [", name);
    for lane in &table {
        println!("        [");
        for chunk in lane.chunks(2) {
            print!("            ");
            for (i, val) in chunk.iter().enumerate() {
                print!("0x{:016x}", val);
                if i < chunk.len() - 1 {
                    print!(", ");
                }
            }
            println!(",");
        }
        println!("        ],");
    }
    println!("    ];");
    println!();
}
