use std::num::NonZeroU32;

use crate::case_folding_simple;

include!(concat!(env!("OUT_DIR"), "/case_mapping.rs")); // generated by build.rs

const MASK: usize = BLOCK_SIZE - 1;
const SHIFT: usize = MASK.count_ones() as usize;

/// Map the supplied character to its lowercase equivalent.
///
/// The lowercase equivalent may be more than one code point. Unused elements in the returned
/// array are set to 0.
///
/// **Note:** A result of all zeros indicates the codepoint maps to itself.
pub fn to_lowercase(chr: char) -> [u32; 2] {
    lookup(chr as u32).0
}

/// Map the supplied character to its uppercase equivalent.
///
/// The uppercase equivalent may be more than one code point. Unused elements in the returned
/// array are set to 0.
///
/// **Note:** A result of all zeros indicates the codepoint maps to itself.
pub fn to_uppercase(chr: char) -> [u32; 3] {
    lookup(chr as u32).1
}

/// Map the supplied character to its titlecase equivalent.
///
/// The titlecase equivalent may be more than one code point. Unused elements in the returned
/// array are set to 0.
///
/// **Note:** A result of all zeros indicates the codepoint maps to itself.
pub fn to_titlecase(chr: char) -> [u32; 3] {
    lookup(chr as u32).2
}

/// Map the supplied character to its case-folded equivalent.
pub fn case_folded(chr: char) -> Option<NonZeroU32> {
    case_folding_simple::case_folding_simple(chr as u32)
}

fn lookup(u: u32) -> &'static Row {
    if u <= LAST_CODEPOINT {
        let index = CASE_MAPPING_BLOCKS
            [CASE_MAPPING_BLOCK_OFFSETS[u as usize >> SHIFT] as usize + (u as usize & MASK)];
        &CASE_MAPPING_RECORDS[usize::from(index)]
    } else {
        &([0; 2], [0; 3], [0; 3])
    }
}
