use {
    crate::{package_info::PackageInfo, PkgResult},
    cpio_archive::ChainedCpioReader,
    std::io::{Cursor, Read},
};
const GZIP_HEADER: [u8; 3] = [0x1f, 0x8b, 0x08];
fn decode_archive(data: Vec<u8>) -> PkgResult<Box<dyn Read>> {
    if data.len() > 3 && data[0..3] == GZIP_HEADER {
        Ok(Box::new(flate2::read::GzDecoder::new(Cursor::new(data))) as Box<dyn Read>)
    } else {
        Ok(Box::new(Cursor::new(data)) as Box<dyn Read>)
    }
}
pub type CpioReader = Box<ChainedCpioReader<Box<dyn Read>>>;
fn cpio_reader(data: &[u8]) -> PkgResult<CpioReader> {
    let decoder = decode_archive(data.to_vec())?;
    Ok(cpio_archive::reader(decoder)?)
}
pub struct ComponentPackageReader {
    bom: Option<Vec<u8>>,
    package_info: Option<PackageInfo>,
    payload: Option<Vec<u8>>,
    scripts: Option<Vec<u8>>,
}
impl ComponentPackageReader {
    pub fn from_file_data(
        bom: Option<Vec<u8>>,
        package_info: Option<Vec<u8>>,
        payload: Option<Vec<u8>>,
        scripts: Option<Vec<u8>>,
    ) -> PkgResult<Self> {
        let package_info = if let Some(data) = package_info {
            Some(PackageInfo::from_reader(Cursor::new(data))?)
        } else {
            None
        };
        Ok(Self {
            bom,
            package_info,
            payload,
            scripts,
        })
    }
    pub fn bom(&self) -> Option<&[u8]> {
        self.bom.as_ref().map(|x| x.as_ref())
    }
    pub fn package_info(&self) -> Option<&PackageInfo> {
        self.package_info.as_ref()
    }
    pub fn payload_reader(&self) -> PkgResult<Option<CpioReader>> {
        if let Some(payload) = &self.payload {
            Ok(Some(cpio_reader(payload)?))
        } else {
            Ok(None)
        }
    }
    pub fn scripts_reader(&self) -> PkgResult<Option<CpioReader>> {
        if let Some(data) = &self.scripts {
            Ok(Some(cpio_reader(data)?))
        } else {
            Ok(None)
        }
    }
}