use bitset::BitArray;
#[derive(Debug)]
pub(crate) struct LSTypeArray {
    bitmap: BitArray,
    is_lms: BitArray,
}
impl LSTypeArray {
    pub fn with_shift<T: PartialEq<T> + PartialOrd<T>>(
        array: &[T],
        shift: usize,
    ) -> Self {
        let count = array.len();
        let mut bitmap = BitArray::new(count);
        let start = if shift == 0 { count } else { shift };
        
        
        
        for i in (1..start).rev() {
            let b = bitmap.get(i);
            bitmap.set(
                i - 1,
                if array[i] == array[i - 1] {
                    b
                } else {
                    array[i - 1] < array[i]
                },
            )
        }
        if shift != 0 {
            let b = bitmap.get(0);
            bitmap.set(
                count - 1,
                if array[0] == array[count - 1] {
                    b
                } else {
                    array[count - 1] < array[0]
                },
            );
            for i in ((shift + 1)..count).rev() {
                let b = bitmap.get(i);
                bitmap.set(
                    i - 1,
                    if array[i] == array[i - 1] {
                        b
                    } else {
                        array[i - 1] < array[i]
                    },
                )
            }
        }
        let is_lms = if shift == 0 {
            bitmap
                .iter()
                .scan(true, |old, b| {
                    let ret = Some(b && !*old);
                    *old = b;
                    ret
                })
                .collect::<BitArray>()
        } else {
            let last = bitmap.get(count - 1);
            bitmap
                .iter()
                .enumerate()
                .scan(last, |old, (i, b)| {
                    let ret = Some(i != shift && b && !*old);
                    *old = b;
                    ret
                })
                .collect::<BitArray>()
        };
        Self { bitmap, is_lms }
    }
    pub fn get(&self, idx: usize) -> bool {
        self.bitmap.get(idx)
    }
    pub fn is_lms(&self, idx: usize) -> bool {
        self.is_lms.get(idx)
    }
    pub fn len(&self) -> usize {
        self.bitmap.len()
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn is_lms() {
        
        let test_str = b"mmiissiissiippii";
        let type_arr = LSTypeArray::with_shift(test_str, 0);
        assert!(!type_arr.get(0));
        assert!(!type_arr.get(1));
        assert!(type_arr.get(2));
        assert!(type_arr.get(3));
        assert!(!type_arr.get(4));
        assert!(!type_arr.get(5));
        assert!(type_arr.get(6));
        assert!(type_arr.get(7));
        assert!(!type_arr.get(8));
        assert!(!type_arr.get(9));
        assert!(type_arr.get(10));
        assert!(type_arr.get(11));
        assert!(!type_arr.get(12));
        assert!(!type_arr.get(13));
        assert!(!type_arr.get(14));
        assert!(!type_arr.get(15));
        assert!(!type_arr.is_lms(0));
        assert!(!type_arr.is_lms(1));
        assert!(type_arr.is_lms(2));
        assert!(!type_arr.is_lms(3));
        assert!(!type_arr.is_lms(4));
        assert!(!type_arr.is_lms(5));
        assert!(type_arr.is_lms(6));
        assert!(!type_arr.is_lms(7));
        assert!(!type_arr.is_lms(8));
        assert!(!type_arr.is_lms(9));
        assert!(type_arr.is_lms(10));
        assert!(!type_arr.is_lms(11));
        assert!(!type_arr.is_lms(12));
        assert!(!type_arr.is_lms(13));
        assert!(!type_arr.is_lms(14));
        assert!(!type_arr.is_lms(15));
    }
    #[test]
    fn is_lms2() {
        let test_str = b"The quick brown fox jumps over the black lazy dog";
        
        
        
        let type_arr = LSTypeArray::with_shift(test_str, 0);
        let ls_value = &[
            
            true, false, false, true, true, false, false, true, false, true,
            true, false, true, false, false, true, true, true, false, true,
            true, false, true, true, false, true, true, false, true, false,
            true, false, false, false, true, true, false, true, true, false,
            true, false, true, false, false, true, true, false, false,
        ];
        let lms_value = &[
            
            false, false, false, true, false, false, false, true, false, true,
            false, false, true, false, false, true, false, false, false, true,
            false, false, true, false, false, true, false, false, true, false,
            true, false, false, false, true, false, false, true, false, false,
            true, false, true, false, false, true, false, false, false,
        ];
        for i in 0..type_arr.len() {
            assert_eq!(type_arr.get(i), ls_value[i]);
            assert_eq!(type_arr.is_lms(i), lms_value[i]);
        }
    }
}