//! Split data into chunks.

use std::io::Read;

use clap::ValueEnum;

/// Split data into chunks.
#[derive(Debug)]
pub struct ChunkSplitter<T: Read> {
    method: SplitMethod,
    input: T,
}

impl<T: Read> ChunkSplitter<T> {
    /// Create a new [`ChunkSplitter`] that splits the given input stream.
    pub fn new(method: SplitMethod, input: T) -> Self {
        Self { method, input }
    }

    /// Read next chunk from input stream.
    pub fn read(&mut self) -> Result<Option<Vec<u8>>, SplitterError> {
        match self.method {
            SplitMethod::Single => {
                let mut buf = vec![];
                let n = self
                    .input
                    .read_to_end(&mut buf)
                    .map_err(SplitterError::Read)?;
                if n == 0 { Ok(None) } else { Ok(Some(buf)) }
            }
        }
    }
}

impl<T: Read> Iterator for ChunkSplitter<T> {
    type Item = Result<Vec<u8>, SplitterError>;

    fn next(&mut self) -> Option<Self::Item> {
        let result = self.read();
        match result {
            Ok(None) => None,
            Ok(Some(data)) => Some(Ok(data)),
            Err(err) => Some(Err(err)),
        }
    }
}

/// How should data be split into chunks?
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum SplitMethod {
    /// Put all data into one chunk. FIXME: Drop this variant once a better one exists.
    Single,
}

/// Errors from [`ChunkSplitter`].
#[derive(Debug, thiserror::Error)]
pub enum SplitterError {
    /// Can't read.
    #[error("failed to read chunk from file")]
    Read(#[source] std::io::Error),
}
