use std::collections::{HashMap, HashSet};
use std::fmt;
use serde::de::{self, Deserialize, Visitor};
use super::super::Stash;
use super::super::util::Json;
use super::util::deserialize;
const EXPECTING_MSG: &str = "map with item stash data";
impl<'de> Deserialize<'de> for Stash {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: de::Deserializer<'de>
{
deserializer.deserialize_map(StashVisitor)
}
}
struct StashVisitor;
impl<'de> Visitor<'de> for StashVisitor {
type Value = Stash;
fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", EXPECTING_MSG)
}
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
where V: de::MapAccess<'de>
{
let mut id = None;
let mut league = None;
let mut label: Option<Option<_>> = None;
let mut type_ = None;
let mut account: Option<Option<_>> = None;
let mut last_character = None;
let mut items = None;
while let Some(key) = map.next_key::<String>()? {
let key = key.trim();
match key {
"id" => {
check_duplicate!(id);
id = Some(map.next_value()?);
}
"stash" => {
check_duplicate!("stash" => label);
label = Some(map.next_value()?);
}
"stashType" => {
check_duplicate!("stashType" => type_);
type_ = Some(map.next_value()?);
}
"accountName" => {
check_duplicate!("accountName" => account);
account = Some(map.next_value()?);
}
"lastCharacterName" => {
check_duplicate!("lastCharacterName" => last_character);
last_character = Some(map.next_value()?);
}
"items" => {
let items_json: Vec<HashMap<String, Json>> = map.next_value()?;
league = Some({
let leagues: HashSet<_> = items_json.iter()
.filter_map(|i| i.get("league").and_then(|l| l.as_str()))
.collect();
if leagues.len() > 1 {
return Err(de::Error::custom(format!(
"items from multiple ({}) leagues in a single stash tab?!", leagues.len())));
}
deserialize(leagues.into_iter().next().unwrap_or("Standard"))?
});
items = Some(deserialize(items_json).map_err(|e| {
de::Error::custom(format!("cannot deserialize stashed items: {}", e))
})?);
}
"public" => {
map.next_value::<bool>()?;
},
key => {
warn!("Unrecognized key in stash JSON: `{}`", key);
map.next_value::<Json>()?; }
}
}
let id = id.ok_or_else(|| de::Error::missing_field("id"))?;
let label = label.ok_or_else(|| de::Error::missing_field("stash"))?;
let league = league.unwrap_or_default();
let type_ = type_.ok_or_else(|| de::Error::missing_field("stashType"))?;
let account = account.ok_or_else(|| de::Error::missing_field("accountName"))?;
let last_character = last_character.unwrap_or_default();
let items = items.unwrap_or_default();
Ok(Stash{
id, league, type_, last_character, items,
label: label.unwrap_or_default(),
account: account.unwrap_or_default(),
})
}
}