use std::{collections::HashSet, fs, path::PathBuf};
use serde::Deserialize;
use toml::{self, de::Error, value::{Date, Time}};
use crate::phighlighter::PFileParser;
use crate::{pcontent::{PContentTimeBlock, PContentTimeTable, PContentTitle, PContentType, PLabeler, PVecContent}, phighlighter::PLocation};
use crate::plectureparser::{PLectureParser, PLectureData};
#[derive(Debug, Clone, Deserialize)]
pub struct PTimeTableBlock{
pub week_title: Option<String>,
pub date: Option<Date>,
pub title: Option<String>,
pub invitation: Option<String>,
pub style: Option<String>,
pub speakers: Option<Vec<String>>,
pub description: Option<String>,
pub location: Option<String>,
pub begin: Option<Time>,
pub duration: Option<Time>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct PTimeTableDescription{
pub invitation: String,
pub main_url: String,
pub location: String,
pub label: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct PTimeTable{
pub timetable: PTimeTableDescription,
pub block: Vec<PTimeTableBlock>,
}
pub fn load_timetable(filename: &PathBuf) -> Result<PTimeTable, Error> {
let timetable: PTimeTable = match fs::read_to_string(filename) {
Ok(str) => match toml::from_str(&str){
Ok(value) => value,
Err(error) => panic!("load_timetable : cannot parse file {:?}\n\tParsing error {}", filename, error)
},
Err(err) => panic!("load_timetable : cannot read file {:?}\n\tError: {}", filename, err)
};
Ok(timetable)
}
fn phoenix_default_option(option: &Option<String>, default_value: &String) -> String{
match option {
Some(value) => value.clone(),
None => default_value.clone()
}
}
fn update_date_of_block(block: &mut PContentTimeBlock, option_date: &Option<Date>, option_begin: &mut Option<Time>, duration: &Time){
let date = match option_date {
Some(value) => value,
None => panic!("update_date_of_block : missing date of block '{}'", block.get_title())
};
let begin_time = match option_begin {
Some(value) => value,
None => panic!("update_date_of_block : missing begin of block '{}'", block.get_title())
};
let mut end_time: Time = begin_time.clone();
end_time.hour += duration.hour;
end_time.minute += duration.minute;
if end_time.minute >= 60 {
let nb_hour: u8 = end_time.minute / 60;
end_time.minute = end_time.minute % 60;
end_time.hour += nb_hour;
}
block.set_time(&date.to_string(), &begin_time.to_string(), &end_time.to_string(), &duration.to_string());
*option_begin = Some(end_time);
}
pub fn create_content_timetable(content: &mut PVecContent, lecture_data: &mut PLectureData, lecture_parser: &PLectureParser, filename: &PathBuf){
let timetable_config: PTimeTable = match load_timetable(filename){
Ok(value) => value,
Err(err) => panic!("load_timetable : cannot read file {:?}\n\tError: {}", filename, err)
};
let config_location = PLocation::new(filename, 0, 0);
let mut content_time_table = PContentTimeTable::new(&timetable_config.timetable.main_url, &timetable_config.timetable.invitation);
let mut week_invitation = String::from("");
let mut current_date: Option<Date> = None;
let mut current_time: Option<Time> = None;
let mut set_session_invitation: HashSet<String> = Default::default();
let mut vec_session_content: Vec<PVecContent> = vec![];
for block_config in timetable_config.block.iter(){
match &block_config.date {
Some(date) => current_date = Some(date.clone()),
None => {},
}
match &block_config.begin {
Some(value) => current_time = Some(value.clone()),
None => {},
}
match &block_config.week_title {
Some(week_title) => { let invitation: String = match &block_config.invitation {
Some(value) => value.clone(),
None => String::from("")
};
if !invitation.is_empty(){
week_invitation = invitation.clone(); }
content_time_table.add_week(week_title, &invitation);
},
None => { let mut block = PContentTimeBlock::new(&phoenix_default_option(&block_config.title, &String::from("")),
&phoenix_default_option(&block_config.invitation, &String::from("")));
block.set_location(&phoenix_default_option(&block_config.location, &timetable_config.timetable.location));
block.set_style(&phoenix_default_option(&block_config.style, &String::from("timetableBlockStyle")));
update_date_of_block(&mut block, ¤t_date, &mut current_time, &block_config.duration.unwrap());
create_session_content(&mut vec_session_content, &mut set_session_invitation, lecture_data, lecture_parser, &block, block_config, &config_location);
content_time_table.add_block(&week_invitation, &block);
}
}
}
content_time_table.udpate_block_row();
content_time_table.save_invitation(lecture_parser.get_output_path());
content.add_child(&PContentType::TimeTable(PLabeler::new(lecture_data.get_current_id(), &content_time_table)));
if !timetable_config.timetable.label.is_empty() {
lecture_data.add_label(content, &timetable_config.timetable.label);
}
for session in vec_session_content.iter(){
content.append_content(session);
}
}
fn create_session_content(vec_session_content: &mut Vec<PVecContent>, set_session_invitation: &mut HashSet<String>,
lecture_data: &mut PLectureData, lecture_parser: &PLectureParser, block: &PContentTimeBlock, block_config: &PTimeTableBlock,
config_location: &PLocation)
{
if block.get_invitation().is_empty() {
return; }
if set_session_invitation.contains(block.get_invitation()){
return; }
let mut content = PVecContent::new();
let mut session = PContentTitle::new(2, true, config_location);
session.get_title_mut().add_child(&PContentType::from_text(lecture_data.get_current_id(), block.get_title()));
content.add_child(&PContentType::Title(PLabeler::new(lecture_data.get_current_id(), &session)));
lecture_data.add_label(&mut content, &String::from(format!("sec_{}", block.get_invitation())));
let mut session_header = String::from(format!("<a href=\"invitation/{}.ics\"><div class=\"rendezvousStyle\"></div></a>", block.get_invitation()));
session_header += &format!("<b>Date</b> : {}<br />", block.get_date());
session_header += &format!("<b>Location</b> : {}<br />", block.get_location());
session_header += &format!("<b>Start at</b> : {}<br />", block.get_begin_time());
session_header += &format!("<b>Stop at</b> : {}<br />", block.get_end_time());
match &block_config.speakers {
Some(vec_speaker) => {
if vec_speaker.len() != 0 {
session_header += &String::from("<h3>Speakers</h3><ul>");
for speaker in vec_speaker.iter() {
session_header += &format!("<li>{}</li>", speaker);
}
session_header += &String::from("</ul>");
}
},
None => {}
}
content.add_child(&PContentType::from_text(lecture_data.get_current_id(), &session_header));
match &block_config.description {
Some(description) => {
let trim_description = String::from(description.trim());
if !trim_description.is_empty() {
content.add_child(&PContentType::from_text(lecture_data.get_current_id(), &String::from("<h3>Description</h3>")));
let parser: PFileParser = PFileParser::from_content(&trim_description);
let mut data = PLectureData::new(lecture_data.get_current_id(), &parser);
lecture_parser.parse(&mut content, &mut data);
lecture_data.set_current_id(data.get_current_id());
}
},
None => {}
}
vec_session_content.push(content);
set_session_invitation.insert(block.get_invitation().clone());
}