1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use std::collections::HashMap;
use std::time::Duration;

use serde::Deserialize;

#[derive(Debug, Deserialize)]
pub struct StarRailNote {
    /// A.K.A. Trailblaze Power.
    pub current_stamina: u16,
    /// Max value of Trailblaze Power.
    pub max_stamina: u16,
    /// Full recovery time.
    pub stamina_recover_time: u32,
    /// A limit of accept expeditions

    #[serde(rename = "accepted_epedition_num")]
    pub accepted_expedition_num: u8,
    /// Current Count that expeditions
    pub total_expedition_num: u8,
    /// Details of Expeditions.
    pub expeditions: Option<Vec<Expedition>>,
    /// Current Value of Daily Training.
    pub current_train_score: u16,
    /// Max Value of Daily Training.
    pub max_train_score: u16,
    /// Current Value of Point Rewards on Simulated Universe.
    pub current_rogue_score: u32,
    /// Max Value of Point Rewards on Simulated Universe.
    pub max_rogue_score: u32,
    /// Echo of War count that can get Reward claims.
    pub weekly_cocoon_cnt: u8,
    /// Echo of War attempt Limit that can get Reward claims.
    pub weekly_cocoon_limit: u8,
    /// Current Owned Reserved Trailblaze Power
    pub current_reserve_stamina: u32,
    /// Filled Reserved Trailblaze Power or Not
    pub is_reserve_stamina_full: bool,
}
impl StarRailNote {
    /// The difference from max [`max_stamina`] to [`current_stamina`]
    pub fn diff_stamina(&self) -> u16 {
        self.max_stamina - self.current_stamina
    }

    /// Check the all [`expeditions`] finished or not as `Option<bool>`. If there's no Expeditions return value is `None`
    pub fn is_all_done(&self) -> Option<bool> {
        if self.expeditions.is_none() {
            return None;
        }

        let result = self.expeditions.as_ref().unwrap()
            .iter()
            .all(|expedition| {
                expedition.is_done()
            });
        Some(result)
    }

    /// A simply info of [`expedition`].
    pub fn expedition_details(&self) -> Option<HashMap<String, Duration>> {
        if self.expeditions.is_none() {
            return None;
        }
        let mut details = HashMap::new();

        for info in self.expeditions.as_ref().unwrap() {
            details.insert(info.name.to_string(), Duration::from_secs(info.remaining_time as u64));
        }

        Some(details)
    }

    /// The return value is Stamina recover time as [`Duration`]
    pub fn recover_time_as_duration(&self) -> Duration {
        Duration::from_secs(self.stamina_recover_time as u64)
    }
}

/// Detail of Expedition
#[derive(Debug, Deserialize)]
pub struct Expedition {
    /// Dispatched Character(s)
    pub avatars: Vec<String>,
    /// Finished or Not yet
    pub status: String,
    /// Time remaining
    pub remaining_time: u32,
    /// Place Name to expedition
    pub name: String,
    /// image url of Material
    pub item_url: String,
}
impl Expedition {
    /// Check the expedition finished or not as `bool`. If already finished, the return value is true.
    pub fn is_done(&self) -> bool {
        self.status.eq("Finished")
    }
}