use std::borrow::Cow; use std::collections::HashMap; use sestring::SeString; use serde::{Deserialize, Deserializer}; use crate::ffxiv::Language; use crate::listing::{DutyCategory, DutyType}; #[derive(Debug, Clone, Deserialize)] pub struct CachedStatistics { pub all_time: Statistics, pub seven_days: Statistics, } #[derive(Debug, Clone, Deserialize)] pub struct Aliases { #[serde(deserialize_with = "alias_de")] pub aliases: HashMap, } #[derive(Debug, Clone, Deserialize)] pub struct Statistics { pub count: Vec, #[serde(default)] pub aliases: HashMap, pub duties: Vec, pub hosts: Vec, pub hours: Vec, pub days: Vec, } fn alias_de<'de, D>(de: D) -> std::result::Result, D::Error> where D: Deserializer<'de> { let aliases: Vec = Deserialize::deserialize(de)?; let map = aliases .into_iter() .map(|info| (info.content_id, info.alias)) .collect(); Ok(map) } impl Statistics { pub fn num_listings(&self) -> usize { if self.count.is_empty() { return 0; } self.count[0].count } pub fn player_name(&self, cid: &u32) -> Cow { let alias = match self.aliases.get(cid) { Some(a) => a, None => return "".into(), }; let world = match crate::ffxiv::WORLDS.get(&alias.home_world) { Some(world) => world.name(), None => "", }; format!("{} @ {}", alias.name.text(), world).into() } } #[derive(Debug, Clone, Deserialize)] pub struct Count { pub count: usize, } #[derive(Debug, Clone, Deserialize)] pub struct AliasInfo { #[serde(rename = "_id")] pub content_id: u32, pub alias: Alias, } #[derive(Debug, Clone, Deserialize)] pub struct Alias { #[serde(with = "crate::base64_sestring")] pub name: SeString, pub home_world: u32, } #[derive(Debug, Clone, Deserialize)] pub struct DutyInfo { #[serde(rename = "_id")] pub info: (u8, u32, u16), pub count: usize, } impl DutyInfo { pub fn name(&self, lang: &Language) -> Cow { let kind = match DutyType::from_u8(self.info.0) { Some(k) => k, None => return Cow::from(""), }; let category = match DutyCategory::from_u32(self.info.1) { Some(c) => c, None => return Cow::from(""), }; crate::ffxiv::duty_name(kind, category, self.info.2, *lang) } } #[derive(Debug, Clone, Deserialize)] pub struct HostInfo { #[serde(rename = "_id")] pub created_world: u32, pub count: usize, pub content_ids: Vec, } impl HostInfo { pub fn num_other(&self) -> usize { let top15: usize = self.content_ids.iter().map(|info| info.count).sum(); self.count - top15 } pub fn world_name(&self) -> &'static str { match crate::ffxiv::WORLDS.get(&self.created_world) { Some(world) => world.name(), None => "", } } } #[derive(Debug, Clone, Deserialize)] pub struct HostInfoInfo { pub content_id: u32, pub count: usize, } #[derive(Debug, Clone, Deserialize)] pub struct HourInfo { #[serde(rename = "_id")] pub hour: u8, pub count: usize, } #[derive(Debug, Clone, Deserialize)] pub struct DayInfo { #[serde(rename = "_id")] pub day: u8, pub count: usize, } impl DayInfo { pub fn name(&self) -> &'static str { match self.day { 1 => "Sunday", 2 => "Monday", 3 => "Tuesday", 4 => "Wednesday", 5 => "Thursday", 6 => "Friday", 7 => "Saturday", _ => "", } } }