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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use crate::{
    catch::{CatchDifficultyAttributes, CatchPerformanceAttributes},
    mania::{ManiaDifficultyAttributes, ManiaPerformanceAttributes},
    osu::{OsuDifficultyAttributes, OsuPerformanceAttributes},
    taiko::{TaikoDifficultyAttributes, TaikoPerformanceAttributes},
};

use super::performance::{into::IntoPerformance, Performance};

/// The result of a difficulty calculation based on the mode.
#[derive(Clone, Debug, PartialEq)]
pub enum DifficultyAttributes {
    /// osu!standard difficulty calculation result.
    Osu(OsuDifficultyAttributes),
    /// osu!taiko difficulty calculation result.
    Taiko(TaikoDifficultyAttributes),
    /// osu!catch difficulty calculation result.
    Catch(CatchDifficultyAttributes),
    /// osu!mania difficulty calculation result.
    Mania(ManiaDifficultyAttributes),
}

impl DifficultyAttributes {
    /// The star value.
    pub const fn stars(&self) -> f64 {
        match self {
            Self::Osu(attrs) => attrs.stars,
            Self::Taiko(attrs) => attrs.stars,
            Self::Catch(attrs) => attrs.stars,
            Self::Mania(attrs) => attrs.stars,
        }
    }

    /// The maximum combo of the map.
    pub const fn max_combo(&self) -> u32 {
        match self {
            Self::Osu(attrs) => attrs.max_combo,
            Self::Taiko(attrs) => attrs.max_combo,
            Self::Catch(attrs) => attrs.max_combo(),
            Self::Mania(attrs) => attrs.max_combo,
        }
    }

    /// Returns a builder for performance calculation.
    pub fn performance<'a>(self) -> Performance<'a> {
        self.into_performance()
    }
}

/// The result of a performance calculation based on the mode.
#[derive(Clone, Debug, PartialEq)]
pub enum PerformanceAttributes {
    /// osu!standard performance calculation result.
    Osu(OsuPerformanceAttributes),
    /// osu!taiko performance calculation result.
    Taiko(TaikoPerformanceAttributes),
    /// osu!catch performance calculation result.
    Catch(CatchPerformanceAttributes),
    /// osu!mania performance calculation result.
    Mania(ManiaPerformanceAttributes),
}

impl PerformanceAttributes {
    /// The pp value.
    pub const fn pp(&self) -> f64 {
        match self {
            Self::Osu(attrs) => attrs.pp,
            Self::Taiko(attrs) => attrs.pp,
            Self::Catch(attrs) => attrs.pp,
            Self::Mania(attrs) => attrs.pp,
        }
    }

    /// The star value.
    pub const fn stars(&self) -> f64 {
        match self {
            Self::Osu(attrs) => attrs.stars(),
            Self::Taiko(attrs) => attrs.stars(),
            Self::Catch(attrs) => attrs.stars(),
            Self::Mania(attrs) => attrs.stars(),
        }
    }

    /// Difficulty attributes that were used for the performance calculation.
    pub fn difficulty_attributes(&self) -> DifficultyAttributes {
        match self {
            Self::Osu(attrs) => DifficultyAttributes::Osu(attrs.difficulty.clone()),
            Self::Taiko(attrs) => DifficultyAttributes::Taiko(attrs.difficulty.clone()),
            Self::Catch(attrs) => DifficultyAttributes::Catch(attrs.difficulty.clone()),
            Self::Mania(attrs) => DifficultyAttributes::Mania(attrs.difficulty.clone()),
        }
    }

    /// The maximum combo of the map.
    pub const fn max_combo(&self) -> u32 {
        match self {
            Self::Osu(attrs) => attrs.difficulty.max_combo,
            Self::Taiko(attrs) => attrs.difficulty.max_combo,
            Self::Catch(attrs) => attrs.difficulty.max_combo(),
            Self::Mania(attrs) => attrs.difficulty.max_combo,
        }
    }

    /// Returns a builder for performance calculation.
    pub fn performance<'a>(self) -> Performance<'a> {
        self.into_performance()
    }
}

impl From<PerformanceAttributes> for DifficultyAttributes {
    fn from(attrs: PerformanceAttributes) -> Self {
        attrs.difficulty_attributes()
    }
}