/*
    Copyright: 2020 Rasmus Thomsen <oss@cogitri.dev>
    SPDX-License-Identifier: GPL-3.0-or-later
*/

use crate::i18n::ni18n;
use log::error;
use std::convert::TryFrom;
use std::error::Error as stdError;
use std::fmt;

#[derive(Debug)]
pub enum Error {
    Add(String),
    DatabaseOpen(String),
    Delete(String),
    DeleteRequiredPackage(String),
    Details(String),
    Dependency(String),
    GetRepositories(String),
    IntegerOverflow(String),
    ListUpgradable(String),
    NoSuchPackage(String),
    SetRepositories(String),
    Upgrade(String),
    Update(String),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Error::Add(e)
            | Error::DatabaseOpen(e)
            | Error::Delete(e)
            | Error::DeleteRequiredPackage(e)
            | Error::Details(e)
            | Error::Dependency(e)
            | Error::GetRepositories(e)
            | Error::IntegerOverflow(e)
            | Error::NoSuchPackage(e)
            | Error::ListUpgradable(e)
            | Error::SetRepositories(e)
            | Error::Upgrade(e)
            | Error::Update(e) => write!(f, "{}", e),
        }
    }
}

pub struct Errors(pub Vec<Error>);

impl fmt::Display for Errors {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{}",
            ni18n(
                "An error occured:",
                "Multiple errors occured:",
                u32::try_from(self.0.len()).unwrap_or(1),
            )
        )?;
        for (i, x) in self.0.iter().enumerate() {
            if i == 0 {
                write!(f, " {}", x)?
            } else {
                write!(f, ", {}", x)?
            }
        }
        Ok(())
    }
}

impl stdError for Error {}

impl From<Error> for zbus::fdo::Error {
    fn from(e: Error) -> Self {
        error!("{}", e);
        zbus::fdo::Error::Failed(e.to_string())
    }
}

impl From<Errors> for zbus::fdo::Error {
    fn from(e: Errors) -> Self {
        error!("{}", e);
        zbus::fdo::Error::Failed(e.to_string())
    }
}

impl From<std::num::TryFromIntError> for Error {
    fn from(e: std::num::TryFromIntError) -> Self {
        Self::IntegerOverflow(e.to_string())
    }
}
