1use crate::question::QuestionType;
2use std::fs::File;
3use std::{fmt, ops::Deref};
4use xml::writer::{EmitterConfig, XmlEvent};
5
6#[derive(Debug)]
18pub enum QuizError {
19 XMLWriterError(xml::writer::Error),
20 EmptyError(String),
21 ValueError(String),
22 AnswerFractionError(String),
23 AnswerCountError(String),
24}
25impl From<xml::writer::Error> for QuizError {
26 fn from(e: xml::writer::Error) -> Self {
27 QuizError::XMLWriterError(e)
28 }
29}
30impl From<EmptyError> for QuizError {
31 fn from(e: EmptyError) -> Self {
32 QuizError::EmptyError(e.to_string())
33 }
34}
35impl From<ValueError> for QuizError {
36 fn from(e: ValueError) -> Self {
37 QuizError::ValueError(e.to_string())
38 }
39}
40
41#[derive(Debug)]
42pub struct EmptyError;
43
44impl fmt::Display for EmptyError {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 f.write_str("Quiz questions or answer is empty")
47 }
48}
49
50#[derive(Debug)]
51pub struct ValueError;
52
53impl fmt::Display for ValueError {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 f.write_str("Answer type has value outside of limits")
56 }
57}
58
59#[derive(Debug, Clone)]
62pub struct Category(String);
63
64impl Deref for Category {
65 type Target = String;
66
67 fn deref(&self) -> &Self::Target {
68 &self.0
69 }
70}
71impl From<String> for Category {
72 fn from(s: String) -> Self {
73 Category(s)
74 }
75}
76impl From<&str> for Category {
77 fn from(s: &str) -> Self {
78 Category(s.to_string())
79 }
80}
81impl From<Category> for Vec<Category> {
82 fn from(category: Category) -> Self {
83 vec![category]
84 }
85}
86
87pub struct Quiz {
89 questions: Vec<QuestionType>,
91 categories: Option<Vec<Category>>,
92}
93impl Quiz {
94 pub fn new(questions: Vec<QuestionType>) -> Self {
99 Self {
100 questions,
101 categories: None,
102 }
103 }
104 pub fn set_categories(&mut self, categories: Vec<Category>) {
106 self.categories = Some(categories);
107 }
108 pub fn to_xml(&mut self, filename: &str) -> Result<(), QuizError> {
118 if self.questions.is_empty() {
119 return Err(EmptyError.into());
120 }
121 let output: File = File::create(filename)
122 .unwrap_or_else(|e| panic!("Bad file path: {} More: {}", filename, e));
123 let mut writer = EmitterConfig::new()
124 .perform_indent(true)
125 .create_writer(&output);
126
127 writer.write(XmlEvent::start_element("quiz"))?;
128 if let Some(categories) = self.categories.as_ref() {
129 for category in categories {
130 writer.write(XmlEvent::start_element("question").attr("type", "category"))?;
131 writer.write(XmlEvent::start_element("category"))?;
132 writer.write(XmlEvent::start_element("text"))?;
133 let string = ["$course$/", category.as_str(), "/"].concat();
134 writer.write(XmlEvent::characters(string.as_str()))?;
135 writer.write(XmlEvent::end_element())?;
136 writer.write(XmlEvent::end_element())?;
137 writer.write(XmlEvent::end_element())?;
138 }
139 }
140
141 if self.questions.is_empty() {
142 return Err(EmptyError.into());
143 }
144 for question in &self.questions {
145 question.to_xml(&mut writer)?;
146 }
147 writer.write(XmlEvent::end_element())?;
148 Ok(())
149 }
150}