1use super::ContentError;
6use serde::{Deserialize, Serialize};
7use std::ops::Range;
8use std::str::FromStr;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
12pub enum ContentType {
13 HighLevelOutline,
15 DetailedOutline,
17 BookChapter,
19 BlogPost,
21 PresentarDemo,
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
27pub enum CourseLevel {
28 Short,
30 #[default]
32 Standard,
33 Extended,
35 Custom { weeks: u8, modules: u8, videos_per_module: u8 },
37}
38
39impl CourseLevel {
40 pub fn weeks(&self) -> u8 {
42 match self {
43 CourseLevel::Short => 1,
44 CourseLevel::Standard => 3,
45 CourseLevel::Extended => 6,
46 CourseLevel::Custom { weeks, .. } => *weeks,
47 }
48 }
49
50 pub fn modules(&self) -> u8 {
52 match self {
53 CourseLevel::Short => 2,
54 CourseLevel::Standard => 3,
55 CourseLevel::Extended => 6,
56 CourseLevel::Custom { modules, .. } => *modules,
57 }
58 }
59
60 pub fn videos_per_module(&self) -> u8 {
62 match self {
63 CourseLevel::Short => 3,
64 CourseLevel::Standard => 5,
65 CourseLevel::Extended => 5,
66 CourseLevel::Custom { videos_per_module, .. } => *videos_per_module,
67 }
68 }
69}
70
71impl FromStr for CourseLevel {
72 type Err = ContentError;
73
74 fn from_str(s: &str) -> Result<Self, Self::Err> {
75 match s.to_lowercase().as_str() {
76 "short" | "s" | "1" => Ok(CourseLevel::Short),
77 "standard" | "std" | "3" => Ok(CourseLevel::Standard),
78 "extended" | "ext" | "6" => Ok(CourseLevel::Extended),
79 _ => Err(ContentError::InvalidContentType(format!(
80 "Invalid course level: {}. Use: short, standard, extended",
81 s
82 ))),
83 }
84 }
85}
86
87impl ContentType {
88 fn metadata(&self) -> (&'static str, &'static str, &'static str, Range<usize>) {
90 match self {
91 Self::HighLevelOutline => ("HLO", "High-Level Outline", "YAML/Markdown", 50..200),
92 Self::DetailedOutline => ("DLO", "Detailed Outline", "YAML/Markdown", 200..1000),
93 Self::BookChapter => ("BCH", "Book Chapter", "Markdown (mdBook)", 2000..8000),
94 Self::BlogPost => ("BLP", "Blog Post", "Markdown + TOML", 500..3000),
95 Self::PresentarDemo => ("PDM", "Presentar Demo", "HTML + YAML", 0..0),
96 }
97 }
98
99 pub fn code(&self) -> &'static str {
101 self.metadata().0
102 }
103
104 pub fn name(&self) -> &'static str {
106 self.metadata().1
107 }
108
109 pub fn output_format(&self) -> &'static str {
111 self.metadata().2
112 }
113
114 pub fn target_length(&self) -> Range<usize> {
116 self.metadata().3
117 }
118
119 pub fn all() -> Vec<ContentType> {
121 vec![
122 ContentType::HighLevelOutline,
123 ContentType::DetailedOutline,
124 ContentType::BookChapter,
125 ContentType::BlogPost,
126 ContentType::PresentarDemo,
127 ]
128 }
129}
130
131impl FromStr for ContentType {
132 type Err = ContentError;
133
134 fn from_str(s: &str) -> Result<Self, Self::Err> {
135 match s.to_lowercase().as_str() {
136 "hlo" | "high-level-outline" | "outline" => Ok(ContentType::HighLevelOutline),
137 "dlo" | "detailed-outline" | "detailed" => Ok(ContentType::DetailedOutline),
138 "bch" | "book-chapter" | "chapter" => Ok(ContentType::BookChapter),
139 "blp" | "blog-post" | "blog" => Ok(ContentType::BlogPost),
140 "pdm" | "presentar-demo" | "demo" => Ok(ContentType::PresentarDemo),
141 _ => Err(ContentError::InvalidContentType(s.to_string())),
142 }
143 }
144}