use csv;
use serde_json;
use serde::{Deserialize, Serialize};
use std::{error::Error, fmt, fs, path::Path};
use vrd::Random;
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
pub struct Quote {
pub quote_text: String,
pub author: String,
pub date_added: String,
pub image_url: String,
}
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
pub struct Quotes {
pub quotes: Vec<Quote>,
}
impl Quotes {
pub fn new(quotes: Vec<Quote>) -> Self {
Quotes { quotes }
}
pub fn select_random_quote(&mut self) -> Result<&Quote, Box<dyn Error>> {
if self.quotes.is_empty() {
return Err("No available quotes".into());
}
let mut rng = Random::new();
let rand_index = rng.int(0, self.quotes.len() as i32 - 1) as usize;
Ok(&self.quotes[rand_index])
}
pub fn select_all_quotes(&self) -> Result<Vec<&Quote>, Box<dyn Error>> {
if self.quotes.is_empty() {
return Err("No available quotes".into());
}
let mut sorted_quotes = self.quotes.iter().collect::<Vec<&Quote>>();
sorted_quotes.sort_by_key(|quote| "e.date_added);
Ok(sorted_quotes)
}
}
#[derive(Debug)]
pub enum QuoteError {
IOError(std::io::Error),
ParseError(String),
NoQuotesAvailable,
}
impl fmt::Display for QuoteError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
QuoteError::IOError(err) => write!(f, "I/O Error: {}", err),
QuoteError::ParseError(msg) => write!(f, "Parse Error: {}", msg),
QuoteError::NoQuotesAvailable => write!(f, "No Quotes Available"),
}
}
}
impl Error for QuoteError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
QuoteError::IOError(err) => Some(err),
QuoteError::ParseError(_) => None,
QuoteError::NoQuotesAvailable => None,
}
}
}
impl From<std::io::Error> for QuoteError {
fn from(error: std::io::Error) -> Self {
QuoteError::IOError(error)
}
}
impl From<serde_json::Error> for QuoteError {
fn from(error: serde_json::Error) -> Self {
QuoteError::ParseError(error.to_string())
}
}
impl From<csv::Error> for QuoteError {
fn from(error: csv::Error) -> Self {
QuoteError::ParseError(error.to_string())
}
}
pub fn read_quotes_from_file(file_path: &str) -> Result<Quotes, QuoteError> {
let path = Path::new(file_path);
match path.extension().and_then(|s| s.to_str()) {
Some("json") => read_quotes_from_json(file_path),
Some("csv") => read_quotes_from_csv(file_path),
_ => Err(QuoteError::ParseError("Unsupported file format".into())),
}
}
fn read_quotes_from_json(file_path: &str) -> Result<Quotes, QuoteError> {
let file_content = fs::read_to_string(file_path)?;
let quotes: Quotes = serde_json::from_str(&file_content)?;
Ok(quotes)
}
fn read_quotes_from_csv(file_path: &str) -> Result<Quotes, QuoteError> {
let mut rdr = csv::Reader::from_path(file_path)?;
let quotes = rdr.deserialize().collect::<Result<Vec<Quote>, csv::Error>>()?;
Ok(Quotes::new(quotes))
}