use std::fmt;

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum CurrencyCode {
    Sek,
}

impl CurrencyCode {

    pub fn as_str(&self) -> &'static str {
	match self {
	    Self::Sek => "SEK",
	}
    }
}

impl Default for CurrencyCode {
    fn default() -> Self {
	Self::Sek
    }
}


impl std::str::FromStr for CurrencyCode {

    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
	match s {
	    s if s.eq_ignore_ascii_case("sek") => Ok(Self::Sek),
	    s => Err(format!("Invalid currency `{}`. Supported currencies: [SEK]", s))
	}
    }
}

impl std::fmt::Display for CurrencyCode {

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
	match self {
	    Self::Sek => write!(f, "SEK")
	}
    }
}


impl serde::Serialize for CurrencyCode {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
{
	serializer.serialize_str(self.as_str())
    }
}


struct Visitor;

impl<'de> serde::de::Visitor<'de> for Visitor {
    type Value = CurrencyCode;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str(r#"a datetime string on the form: "2013-12-30 20:59:59+01:00""#)
    }

    fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
	use std::str::FromStr;

	CurrencyCode::from_str(s)
	    .map_err(|err| E::custom(err))
    }
}

impl<'de> serde::Deserialize<'de> for CurrencyCode {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::de::Deserializer<'de>,
    {
        deserializer.deserialize_str(Visitor)
    }
}



#[cfg(test)]
mod tests {

    use super::*;
    use serde_json as js;

    #[test]
    fn serialize_currency() {
	assert_eq!(r#""SEK""#, js::to_string(&CurrencyCode::Sek).expect("Serializing"));
    }

    #[test]
    fn deserialize_currency() {
	assert_eq!(CurrencyCode::Sek, js::from_str(r#""SEK""#).expect("Deserializing"));
	assert_eq!(CurrencyCode::Sek, js::from_str(r#""sek""#).expect("Deserializing"));
	assert_eq!(CurrencyCode::Sek, js::from_str(r#""Sek""#).expect("Deserializing"));
	assert_eq!(CurrencyCode::Sek, js::from_str(r#""sEk""#).expect("Deserializing"));
	assert_eq!(CurrencyCode::Sek, js::from_str(r#""seK""#).expect("Deserializing"));
    }

    
}