nttb-api 0.1.0

A interface for interacting with the NTTB Api
Documentation
use std::{collections::BTreeMap, str::FromStr};

use serde::Deserialize;
use serde_with::{serde_as,json::JsonString, DeserializeFromStr};

use crate::type_search::Gender;

#[derive(Debug, Deserialize)]
#[serde(untagged)]
pub enum GetInfoContent {
    Event(Event),
    EloPerSeason(BTreeMap<Season,u32>),
}

impl GetInfoContent {
    pub fn event(self)->Option<Event>{
        match self {
            GetInfoContent::Event(e) => Some(e),
            _ => None,
        }
    }
    pub fn elo_per_season(self)->Option<EloPerSeason>{
        match self {
            GetInfoContent::EloPerSeason(e) => {
                Some(EloPerSeason(e))
            },
            _ => None,
        }
    }
}

#[derive(Debug,PartialEq, Eq,Clone, Copy)]
pub enum YearSlot {
    ///Known as voorjaar or q1,2
    Spring,
    ///Known as najaar or q3,4
    Autumn
}

#[derive(Debug,Deserialize)]
pub enum Division {
    Landelijk,
    #[serde(alias = "zuidwest", alias = "Zuidwest")]
    ZuidWest,
    West,
    Noord,
    Oost,
    Midden,
    Limburg,
    #[serde(alias = "NoordHolland", alias = "Holland-Noord")]
    HollandNoord,
    Gelge
}

#[derive(Debug,Deserialize)]
pub enum Selection {
    #[serde(alias="allen")]
    Allen,
    Dames,
    Heren,
    Jeugd,
    Jongens,
    Junioren,
    Meisjes,
    Senioren
}

#[derive(Debug,DeserializeFromStr,PartialEq, Eq)]
pub struct Season {
    pub year:u32,
    pub slot:YearSlot
}
impl PartialOrd for Season {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        match (self.year == other.year, self.slot == other.slot) {
            (true,true) => Some(std::cmp::Ordering::Equal),
            (true,false) => match (self.slot,other.slot)  {
                (YearSlot::Spring,YearSlot::Autumn) => Some(std::cmp::Ordering::Less),
                (YearSlot::Autumn,YearSlot::Spring) => Some(std::cmp::Ordering::Greater),
                (_,_) => Some(std::cmp::Ordering::Equal)
            },
            (_,_) => {
                if self.year < other.year {
                    Some(std::cmp::Ordering::Less)
                }else {
                    Some(std::cmp::Ordering::Greater)
                }
            }
        }
    }
}

impl Ord for Season {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.partial_cmp(other).unwrap_or(std::cmp::Ordering::Equal)
    }
}

impl FromStr for Season {
    type Err = crate::errors::SeasonParseStringError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut parts = s.split("_");
        let Some(Ok(year)) =  parts.next().map(|e|e.parse::<u32>()) else {return Err(Self::Err{the_string:s.to_string()})};
        let Some(slot_string) = parts.next() else {return Err(Self::Err{the_string:s.to_string()})};
        if parts.next().is_some() {
            return Err(Self::Err{the_string:s.to_string()})
        }
        match slot_string {
            "1"=>Ok(Self { year: year, slot: YearSlot::Spring }),
            "2"=>Ok(Self { year: year, slot: YearSlot::Autumn }),
            _=>return Err(Self::Err{the_string:s.to_string()})
        }
    }
}

#[derive(Debug,Deserialize)]
pub struct Event {
    #[serde(rename="comp")]
    ///The timeslot in which this event took place
    pub season:Season,

    #[serde(rename="cname")]
    /// If the event is a competition than it's name will be either empty or the competition name
    pub competition_name:Option<String>,

    #[serde(rename="pID")]
    /// a unique identifier
    pub id:u64,
    
    #[serde(rename="win")]
    /// The amount of games won by the player this event is tied to
    pub games_won:u64,

    #[serde(rename="sum")]
    /// The amount of games played by the player this event is tied to
    pub games_played:u64,

    #[serde(rename="klass")]
    pub class_name:String,

    #[serde(rename="afd")]
    pub division:Division,

    #[serde(rename="wie")]
    pub selection:Selection,

    ///extra information about this event
    pub extra:Option<String>,


    //all if this has been commented out as these types can be either string or int
    // #[serde(rename="prc")]
    // /a string containing the winrate if more than one game got played
    // win_rate:Option<String>,

    // #[serde(rename="alg")]
    // ///currently goes undocumented sometimes equals 10 other times it's just zero
    // undocumented_alg:u32,
    // #[serde(rename="BG")]
    // ///currently goes undocumented, but has probably been deprecated since 2017
    // deprecated_bg:u32,
    // #[serde(rename="SG")]
    // ///currently goes undocumented, but has probably been deprecated since 2017
    // deprecated_sg:u32,
    // #[serde(rename="wpw")]
    // ///currently goes undocumented, reflect the amount of games played unless the Event hasn't been internally registered aka id=0
    // undocumented_wpw:Option<String>

}


// pub enum AgeCategory{
//     #[serde(rename="")]
//     Unassigned,
//     Onder
// }

#[derive(Debug,Deserialize)]
pub struct PlayerInfo {
    #[serde(rename="BNo")]
    bondsnumber:u64,
    #[serde(rename="f_naam")]
    name:String,
    #[serde(rename="geslacht")]
    gender:Gender,
    #[serde(rename="cat")]
    age_category:String,
    #[serde(rename="LJ")]
    jeugd_licentie:Option<String>,
    #[serde(rename="SJ")]
    senior_licentie:Option<String>,
}

#[serde_as]
#[derive(Deserialize,Debug)]
pub struct GetInfoResult {
    // username:u64,
    // para:u64,
    #[serde_as(as = "JsonString")]
    pub results:Vec<GetInfoContent>,
    #[serde(rename="player")]
    #[serde_as(as = "JsonString")]
    pub player_info:PlayerInfo
}

#[derive(Debug)]

pub struct EloPerSeason(pub BTreeMap<Season,u32>);
#[derive(Debug)]

pub struct Info {
    // username:u64,
    // para:u64,
    pub elo:EloPerSeason,
    pub results:Vec<Event>,
    pub player_info:PlayerInfo
}