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

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

#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)]
pub enum MercuryParserErrorKind {
    #[fail(display = "Mercury parser returned an error")]
    ServiceError,
    #[fail(display = "Failed (de)serialize json model")]
    Json,
    #[fail(display = "Failed parse URL")]
    Url,
    #[fail(display = "Failed to access file or resource")]
    IO,
    #[fail(display = "Failed to generate HMAC Sha1 Hash")]
    HmacSha1,
    #[fail(display = "Failed to GET generated url")]
    Http,
    #[fail(display = "Scraping succeeded, but no content.")]
    NoContent,
    #[fail(display = "No valid API secret available")]
    InvalidApiSecret,
    #[fail(display = "Unknown Error")]
    Unknown,
}

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

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

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

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

impl From<Context<MercuryParserErrorKind>> for MercuryParserError {
    fn from(inner: Context<MercuryParserErrorKind>) -> MercuryParserError {
        MercuryParserError { inner }
    }
}

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