use super::search::{filter_in, filter_in_if, search_in};

#[allow(non_snake_case)]
pub fn chunkBy_once<'a, T: PartialEq>(input: &'a [T], iden: &[T]) -> Vec<&'a [T]> {
    let mut v = Vec::new();

    {
        let mut o = filter_in(input, iden);
        o.push(input.len());
        o
    }
    .windows(2)
    .for_each(|i| v.push(&input[i[0]..i[1]]));

    v
}

#[allow(non_snake_case)]
pub fn chunkByIf_once<T: PartialEq>(input: &[T], win_size: usize, f: impl Fn(usize, &[T]) -> bool) -> Vec<&[T]> {
    let mut v = Vec::new();

    {
        let mut o = filter_in_if(input, win_size, f);
        o.push(input.len());
        o
    }
    .windows(2)
    .for_each(|i| v.push(&input[i[0]..i[1]]));

    v
}

pub struct ChunkerBy<T> {
    iden: Vec<T>,
    buffer: Vec<T>,
    last_start: Option<usize>,
}

impl<T: PartialEq + Clone> ChunkerBy<T> {
    pub fn new(iden: &[T]) -> Self {
        Self {
            iden: iden.to_vec(),
            buffer: Vec::new(),
            last_start: None,
        }
    }
    pub fn iden(&self) -> &[T] {
        &self.iden
    }
    fn extract_cache(&mut self) {
        if let Some(last_start) = self.last_start.take() {
            self.buffer.drain(..last_start);
        }
    }
    pub fn flush(&mut self) -> &[T] {
        self.extract_cache();
        &self.buffer
    }
    pub fn chunk<'a>(&'a mut self, data_input: &[T]) -> Vec<&'a [T]> {
        if data_input.is_empty() {
            return Vec::new();
        }
        self.extract_cache();

        self.buffer.extend_from_slice(data_input);

        let mut v = Vec::new();

        let mut nalu_start = None;
        loop {
            match nalu_start {
                None => match search_in(&self.buffer, &self.iden) {
                    Some(start) => {
                        nalu_start = Some(start);
                        continue;
                    },
                    None => {
                        break;
                    },
                },
                Some(start) => {
                    let find_offset = start + self.iden.len();

                    let find_next = search_in(&self.buffer[find_offset..], &self.iden);

                    match find_next {
                        None => {
                            self.last_start = Some(start);
                            break;
                        },
                        Some(next_step) => {
                            let next = find_offset + next_step;

                            let s = start;
                            nalu_start = Some(next);
                            v.push(&self.buffer[s..next]);
                        },
                    }
                },
            }
        }
        v
    }
}
