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
115
116
117
118
119
120
121
use numerals::roman::Roman;

#[derive(Debug, Clone)]
pub enum CounterType {
    ARABIC,
    ROMAN,
    ALPHABITICAL,
}

#[derive(Debug, Clone)]
pub enum CounterValueType {
    ARABIC(isize),
    ROMAN(String),
    ALPHABITICAL(String),
}

impl CounterType {
    pub fn is_valid(string: &str) -> bool {
        string == "counter" || string == "roman_counter" || string == "alphabitical_counter"
    }

    pub fn from_str(string: &str) -> Option<Self> {
        match string {
            "counter" => Some(Self::ARABIC),
            "roman_counter" => Some(Self::ROMAN),
            "alphabitical_counter" => Some(Self::ALPHABITICAL),
            _ => None,
        }
    }
}

impl CounterValueType {
    fn is_valid(&self, value: &str) -> bool {
        match self {
            CounterValueType::ARABIC(_) => value.parse::<isize>().is_ok(),
            CounterValueType::ROMAN(roman) => {
                let roman = Roman::parse(roman);
                roman.is_some()
            }
            CounterValueType::ALPHABITICAL(alpha) => alpha.chars().all(|c| {
                let code_point = c as u32;
                code_point >= 65
            }),
        }
    }

    fn default_value(&self, value: Option<&str>) -> Self {
        match self {
            CounterValueType::ARABIC(_) => {
                if let Some(value) = value {
                    if CounterValueType::ARABIC(0).is_valid(value) {
                        Self::ARABIC(value.parse::<isize>().unwrap())
                    } else {
                        panic!("Wrong Arabic counter value")
                    }
                } else {
                    Self::ARABIC(0)
                }
            }
            CounterValueType::ROMAN(_) => {
                if let Some(default_value) = value {
                    if CounterValueType::ROMAN("".to_string()).is_valid(default_value) {
                        Self::ROMAN(default_value.to_string())
                    } else {
                        panic!("Wrong Roman counter value")
                    }
                } else {
                    Self::ROMAN("0".to_string())
                }
            }
            CounterValueType::ALPHABITICAL(_) => {
                if let Some(default_value) = value {
                    if CounterValueType::ALPHABITICAL("".to_string()).is_valid(default_value) {
                        Self::ALPHABITICAL(default_value.to_string())
                    } else {
                        panic!("Wrong Aphabitical counter value")
                    }
                } else {
                    Self::ALPHABITICAL("0".to_string())
                }
            }
        }
    }

    pub fn from_str(string: &str, default_value: Option<&str>) -> Self {
        match string {
            "counter" => CounterValueType::ARABIC(0).default_value(default_value),
            "roman_counter" => CounterValueType::ROMAN("".to_string()).default_value(default_value),
            "alphabitical_counter" => {
                CounterValueType::ALPHABITICAL("".to_string()).default_value(default_value)
            }
            _ => Self::ARABIC(0),
        }
    }

    pub fn from_type(counter_type: &CounterType, default_value: Option<&str>) -> Self {
        match counter_type {
            CounterType::ARABIC => CounterValueType::ARABIC(0).default_value(default_value),
            CounterType::ROMAN => {
                CounterValueType::ROMAN("".to_string()).default_value(default_value)
            }
            CounterType::ALPHABITICAL => {
                CounterValueType::ALPHABITICAL("".to_string()).default_value(default_value)
            }
        }
    }

    pub fn to_string(&self) -> String {
        match self {
            CounterValueType::ARABIC(number) => {
                if *number < 0 {
                    "-".to_string()
                } else {
                    number.to_string()
                }
            }
            CounterValueType::ROMAN(roman) => roman.to_string(),
            CounterValueType::ALPHABITICAL(string) => string.to_string(),
        }
    }
}