use std::fmt;
use std::str::FromStr;
use super::content_parser::*;
use super::request::*;
use reqwest::blocking::Response;
use scraper::Html;
use serde::Serialize;
use tinytemplate::TinyTemplate;
use log::*;
const LC_P: &str = "https://leetcode.com/problems/";
#[derive(Debug, Clone)]
pub struct Quiz {
title: String,
level: Level,
source_link: String,
content: serde_json::Value,
}
#[derive(Debug, Eq, PartialEq, Serialize, Clone)]
pub enum Level {
Easy,
Medium,
Hard,
}
#[derive(Serialize)]
struct FmtTemplate {
level: Level,
source: String,
title: String,
content: String,
#[serde(rename(serialize = "code"))]
code_snippet: String,
}
impl FromStr for Level {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"Easy" | "easy" | "e" => Ok(Self::Easy),
"Medium" | "medium" | "m" => Ok(Self::Medium),
"Hard" | "hard" | "h" => Ok(Self::Hard),
_ => Err("Unspport difficulty".to_string()),
}
}
}
#[cfg(feature = "emacs")]
impl emacs::FromLisp<'_> for Level {
fn from_lisp(value: emacs::Value<'_>) -> emacs::Result<Self> {
Ok(Level::from_str(&String::from_lisp(value).unwrap()).unwrap())
}
}
impl Quiz {
pub(super) fn from_resp(resp: Response, source_link: String) -> Result<Self, String> {
let content = graphql_response_parse(resp)?;
Ok(Quiz {
title: find_question_title_from_graphql_req(&content)?,
level: Level::from_str(&find_question_level_from_graphql_req(&content)?)?,
source_link,
content,
})
}
pub fn get_by_name(name: &str) -> Result<Self, String> {
get_quiz_by_url(&(LC_P.to_string() + name + "/"))
}
pub fn get_randomly(level: Option<Level>) -> Result<Self, String> {
get_random_quiz(level)
}
pub fn get_by_id(id: u64) -> Result<Self, String> {
get_quiz_by_id(id)
}
pub fn quiz_id(&self) -> Result<String, String> {
find_question_id_from_graphql_req(&self.content)
}
pub fn quiz_source(&self) -> &str {
&self.source_link
}
pub fn quiz_pure_description(&self) -> Result<String, String> {
let s = find_question_content(&self.content)?;
if s.starts_with("<p>") {
Ok(s.to_string())
} else {
Ok("<p>".to_string() + s + "</p>")
}
}
pub fn quiz_description(&self) -> Result<String, String> {
let fragment = Html::parse_fragment(&self.quiz_pure_description()?);
Ok(description_markdown(description_in_graphql(&fragment)).join(""))
}
pub fn quiz_level(&self) -> &Level {
&self.level
}
pub fn code_snippet(&self, lang: &str) -> Option<&str> {
match find_code_snippet(&self.content, lang) {
Ok(d) => d,
Err(e) => {
println!("{}", e.to_string());
None
}
}
}
pub fn use_fmt_temp(
&self,
temp: Option<String>,
code_lang: &Option<String>,
) -> Result<String, String> {
match temp {
Some(s) => {
let mut tt = TinyTemplate::new();
tt.add_template("quiz", &s).map_err(|e| e.to_string())?;
debug!(
"this is the quiz description in template: {}",
self.quiz_description()?
);
tt.render(
"quiz",
&FmtTemplate {
level: self.level.clone(),
source: self.source_link.clone(),
title: self.title.clone(),
content: self.quiz_description()?,
code_snippet: self
.code_snippet(code_lang.as_ref().unwrap_or(&"rust".to_string()))
.unwrap()
.to_string(),
},
)
.map_err(|e| e.to_string())
}
None => Ok(format!("{}", self)), }
}
}
impl fmt::Display for Quiz {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}: {}\n\n{}\n",
self.quiz_id().unwrap(),
self.title,
self.quiz_description().unwrap(),
)
}
}
#[cfg(test)]
impl Quiz {
fn new() -> Self {
Self {
title: String::new(),
level: Level::Easy,
source_link: String::new(),
content: serde_json::Value::Null,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fmt_temp() {
let s = "README {source}, {title}; {content}..{level}ll{code}";
let mut tt = TinyTemplate::new();
tt.add_template("quiz", s)
.map_err(|e| e.to_string())
.unwrap();
let result = tt
.render(
"quiz",
&FmtTemplate {
level: Level::Easy,
source: "linklink".to_string(),
title: "titititle".to_string(),
content: "main content".to_string(),
code_snippet: "codecode".to_string(),
},
)
.unwrap();
assert_eq!(
result,
"README linklink, titititle; main content..Easyllcodecode"
);
let s = "README {source}\n\n, {title}; {content}..{level}ll{code}";
tt.add_template("quiz", s)
.map_err(|e| e.to_string())
.unwrap();
let result = tt
.render(
"quiz",
&FmtTemplate {
level: Level::Easy,
source: "linklink".to_string(),
title: "titititle".to_string(),
content: "main content".to_string(),
code_snippet: "codecode".to_string(),
},
)
.unwrap();
assert_eq!(
result,
"README linklink
, titititle; main content..Easyllcodecode"
);
println!("{}", result);
}
}