use std::{error::Error, fmt::{Debug, Display, Formatter}};
use nix::errno::Errno;
use toml;
pub type Result<T> = std::result::Result<T, RockerError>;


#[derive(Debug)]
pub enum RockerError {
    IoError(std::io::Error),
    OtherError(String),
    ErrnoError(Errno),
    TomlSerError(toml::ser::Error),
    TomlDeError(toml::de::Error)
}



impl Display for RockerError {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::IoError(e) => write!(f, "{}", e),
            Self::OtherError(s) => write!(f, "{}", s),
            Self::ErrnoError(e) => write!(f, "{}", e),
            Self::TomlSerError(e) => write!(f, "{}", e),
            Self::TomlDeError(e) => write!(f, "{}", e)
        }
    }
}

impl Error for RockerError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match self {
            Self::IoError(e) => Some(e),
            Self::OtherError(_) => None,
            Self::ErrnoError(e) => Some(e),
            Self::TomlSerError(e) => Some(e),
            Self::TomlDeError(e) => Some(e)
        }
    }
}

impl From<std::io::Error> for RockerError {
    fn from(value: std::io::Error) -> Self {
        Self::IoError(value)
    }
}

impl From<Errno> for RockerError {
    fn from(err: Errno) -> Self {
        Self::OtherError(format!("errno: {err}"))
    }
}


impl From<toml::ser::Error> for RockerError {
    fn from(err: toml::ser::Error) -> Self {
        Self::TomlSerError(err)
    }
}

impl From<toml::de::Error> for RockerError {
    fn from(err: toml::de::Error) -> Self {
        Self::TomlDeError(err)
    }
}