use crate::question::QuestionType;
use std::fs::File;
use std::{fmt, ops::Deref};
use xml::writer::{EmitterConfig, XmlEvent};
#[derive(Debug)]
pub enum QuizError {
XMLWriterError(xml::writer::Error),
EmptyError(String),
ValueError(String),
AnswerFractionError(String),
AnswerCountError(String),
}
impl From<xml::writer::Error> for QuizError {
fn from(e: xml::writer::Error) -> Self {
QuizError::XMLWriterError(e)
}
}
impl From<EmptyError> for QuizError {
fn from(e: EmptyError) -> Self {
QuizError::EmptyError(e.to_string())
}
}
impl From<ValueError> for QuizError {
fn from(e: ValueError) -> Self {
QuizError::ValueError(e.to_string())
}
}
#[derive(Debug)]
pub struct EmptyError;
impl fmt::Display for EmptyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Quiz questions or answer is empty")
}
}
#[derive(Debug)]
pub struct ValueError;
impl fmt::Display for ValueError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Answer type has value outside of limits")
}
}
#[derive(Debug, Clone)]
pub struct Category(String);
impl Deref for Category {
type Target = String;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<String> for Category {
fn from(s: String) -> Self {
Category(s)
}
}
impl From<&str> for Category {
fn from(s: &str) -> Self {
Category(s.to_string())
}
}
impl From<Category> for Vec<Category> {
fn from(category: Category) -> Self {
vec![category]
}
}
pub struct Quiz {
questions: Vec<QuestionType>,
categories: Option<Vec<Category>>,
}
impl Quiz {
pub fn new(questions: Vec<QuestionType>) -> Self {
Self {
questions,
categories: None,
}
}
pub fn set_categories(&mut self, categories: Vec<Category>) {
self.categories = Some(categories);
}
pub fn to_xml(&mut self, filename: &str) -> Result<(), QuizError> {
if self.questions.is_empty() {
return Err(EmptyError.into());
}
let output: File = File::create(filename)
.unwrap_or_else(|e| panic!("Bad file path: {} More: {}", filename, e));
let mut writer = EmitterConfig::new()
.perform_indent(true)
.create_writer(&output);
writer.write(XmlEvent::start_element("quiz"))?;
if let Some(categories) = self.categories.as_ref() {
for category in categories {
writer.write(XmlEvent::start_element("question").attr("type", "category"))?;
writer.write(XmlEvent::start_element("category"))?;
writer.write(XmlEvent::start_element("text"))?;
let string = ["$course$/", category.as_str(), "/"].concat();
writer.write(XmlEvent::characters(string.as_str()))?;
writer.write(XmlEvent::end_element())?;
writer.write(XmlEvent::end_element())?;
writer.write(XmlEvent::end_element())?;
}
}
if self.questions.is_empty() {
return Err(EmptyError.into());
}
for question in &self.questions {
question.to_xml(&mut writer)?;
}
writer.write(XmlEvent::end_element())?;
Ok(())
}
}