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

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

#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)]
pub enum FeedApiErrorKind {
    #[fail(display = "Error reading config file")]
    Config,
    #[fail(display = "Error parsing Url")]
    Url,
    #[fail(display = "Error logging in")]
    Login,
    #[fail(display = "Error during API call")]
    Api,
    #[fail(display = "IO Error")]
    IO,
    #[fail(display = "Error during portal callback")]
    Portal,
    #[fail(display = "Error parsing feed url")]
    ParseFeed,
    #[fail(display = "Feature unsupported by implementation")]
    Unsupported,
    #[fail(display = "Failed to load API secrets")]
    Secret,
    #[fail(display = "Failed to load embeded resource file")]
    Resource,
    #[fail(display = "No valid CA certificate available")]
    TLSCert,
    #[fail(display = "HTTP Basic Auth required/failed")]
    HTTPAuth,
    #[fail(display = "Error en/decrypting a password")]
    Encryption,
    #[fail(display = "Error parsing Json file")]
    Json,
    #[fail(display = "Unknown Error")]
    Unknown,
}

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

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

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

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

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

impl From<Context<FeedApiErrorKind>> for FeedApiError {
    fn from(inner: Context<FeedApiErrorKind>) -> FeedApiError {
        FeedApiError { inner }
    }
}

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