use failure::{Backtrace, Context, Error, Fail};
use std::fmt;

#[derive(Debug)]
pub struct NewsFlashError {
    inner: Context<NewsFlashErrorKind>,
}

#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)]
pub enum NewsFlashErrorKind {
    #[fail(display = "Database Error")]
    Database,
    #[fail(display = "Feed API Error")]
    API,
    #[fail(display = "IO Error")]
    IO,
    #[fail(display = "Failed to login to Feed API")]
    Login,
    #[fail(display = "This operation requires the api to be logged in")]
    NotLoggedIn,
    #[fail(display = "Failed to load Feed API")]
    LoadBackend,
    #[fail(display = "Failed to create portal")]
    Portal,
    #[fail(display = "Error reading/writing config")]
    Config,
    #[fail(display = "Error laoding favicon")]
    Icon,
    #[fail(display = "Parsing OPML file failed")]
    OPML,
    #[fail(display = "Failed to download images for article")]
    ImageDownload,
    #[fail(display = "Failed to download download full content for article")]
    GrabContent,
    #[fail(display = "Operation not possible during sync")]
    Syncing,
    #[fail(display = "Unknown Error")]
    Unknown,
}

impl Fail for NewsFlashError {
    fn cause(&self) -> Option<&dyn Fail> {
        self.inner.cause()
    }

    fn backtrace(&self) -> Option<&Backtrace> {
        self.inner.backtrace()
    }
}

impl fmt::Display for NewsFlashError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.inner, f)
    }
}

impl NewsFlashError {
    pub fn kind(&self) -> NewsFlashErrorKind {
        *self.inner.get_context()
    }
}

impl From<NewsFlashErrorKind> for NewsFlashError {
    fn from(kind: NewsFlashErrorKind) -> NewsFlashError {
        NewsFlashError { inner: Context::new(kind) }
    }
}

impl From<Context<NewsFlashErrorKind>> for NewsFlashError {
    fn from(inner: Context<NewsFlashErrorKind>) -> NewsFlashError {
        NewsFlashError { inner }
    }
}

impl From<Error> for NewsFlashError {
    fn from(_: Error) -> NewsFlashError {
        NewsFlashError {
            inner: Context::new(NewsFlashErrorKind::Unknown),
        }
    }
}
