rustyphoenixlecture 2.2.2

HTML lectures generation
/***************************************
	Auteur : Pierre Aubert
	Mail : pierre.aubert@lapp.in2p3.fr
	Licence : LGPL-3.0-only
****************************************/

use crate::pcontent::{
	PLabelId, pabstractcontent::{PAbstractContent, PAbstractLectureBackend},
	preferenceurl::PReferenceUrl,
	pcontentstatus::{PContentStatus, PStatusType},
};

///Content object of the lecture
#[derive(Debug, Clone, Default, PartialEq)]
pub struct PContentProgress{
	///Number of done ideas
	p_nb_done: usize,
	///Number of ongoing ideas
	p_nb_ongoing: usize,
	///Number of blocked ideas
	p_nb_blocked: usize,
	///Number of waiting ideas
	p_nb_waiting: usize,
	///Number of todo ideas
	p_nb_todo: usize,
}

impl PContentProgress {
	///Constructor of the PContentProgress
	/// # Returns
	/// Initialised PContentProgress
	pub fn new() -> Self{
		PContentProgress {
			p_nb_done: 0,
			p_nb_ongoing: 0,
			p_nb_blocked: 0,
			p_nb_waiting: 0,
			p_nb_todo: 0,
		}
	}
	///Update the status of the current PContentProgress
	/// # Parameters
	/// - `status` : status to be considered
	pub fn update_status(&mut self, status: &PContentStatus){
		match status.get_type() {
			PStatusType::Done => self.add_done(1),
			PStatusType::Ongoing => self.add_ongoing(1),
			PStatusType::Blocked => self.add_blocked(1),
			PStatusType::Waiting => self.add_waiting(1),
			PStatusType::Todo => self.add_todo(1),
			PStatusType::Backlog => {}
		};
	}
	
	///Add a done idea
	/// # Parameters
	/// - `value` : number to be added
	pub fn add_done(&mut self, value: usize){
		self.p_nb_done += value;
	}
	///Add an ongoing idea
	/// # Parameters
	/// - `value` : number to be added
	pub fn add_ongoing(&mut self, value: usize){
		self.p_nb_ongoing += value;
	}
	///Add a blocked idea
	/// # Parameters
	/// - `value` : number to be added
	pub fn add_blocked(&mut self, value: usize){
		self.p_nb_blocked += value;
	}
	///Add a waiting idea
	/// # Parameters
	/// - `value` : number to be added
	pub fn add_waiting(&mut self, value: usize){
		self.p_nb_waiting += value;
	}
	///Add a todo idea
	/// # Parameters
	/// - `value` : number to be added
	pub fn add_todo(&mut self, value: usize){
		self.p_nb_todo += value;
	}
}

impl PAbstractContent for PContentProgress{
	///Say if the PContentProgress has an embeded label
	/// # Returns
	/// True if the PContentProgress has an embeded label, false otherwise
	fn has_embeded_label(&self) -> bool{
		false
	}
	///Get the reference url of the current PContentProgress
	/// # Parameters
	/// - `current_file` : current output file of the PContentProgress
	/// - `id` : id of the PContentProgress
	/// # Returns
	/// Corresponding PReferenceUrl
	fn get_reference_url(&self, current_file: &String, id: usize) -> PReferenceUrl{
		PReferenceUrl::from_text(current_file, id, &String::from(&format!("PContentProgress {}", id)))
	}
	///Convert the current struct into html
	/// # Parameters
	/// - `backend` : backend which write a lecture in files
	/// - `id` : id of the PContentProgress
	fn to_html<TLectureBackend>(&self, backend: &mut TLectureBackend, id: &PLabelId)
		where TLectureBackend: PAbstractLectureBackend
	{
		//Let's pick a 200px progress bar
		let full_pixel_width: usize = 200;
		let full_nb_idea: usize = self.p_nb_blocked + self.p_nb_done + self.p_nb_ongoing + self.p_nb_todo + self.p_nb_waiting;
		
		backend.write(&String::from(format!("Status <span id=\"{}\" style=\"display: inline-block;width: {}px;height: 30px\">", id.get_id(), full_pixel_width)));
		
		create_html_progress_segment(backend, full_nb_idea, self.p_nb_done, full_pixel_width, &String::from("#4c1"));
		create_html_progress_segment(backend, full_nb_idea, self.p_nb_waiting, full_pixel_width, &String::from("#cccc08"));
		create_html_progress_segment(backend, full_nb_idea, self.p_nb_ongoing, full_pixel_width, &String::from("#0acc75"));
		create_html_progress_segment(backend, full_nb_idea, self.p_nb_blocked, full_pixel_width, &String::from("#cc490d"));
		create_html_progress_segment(backend, full_nb_idea, self.p_nb_todo, full_pixel_width, &String::from("#08cccc"));
		
		backend.write(&String::from("</span>"));
		let percent: usize = if full_nb_idea == 0 {0}else{(self.p_nb_done*100)/full_nb_idea};
		backend.write(&String::from(format!(" Done <b>{} %</b>", percent)));
	}
}

///Create the html progress segment for a given counter
/// # Parameters
/// - `backend` : backend which write a lecture in files
/// - `full_nb_idea` : total number of idea
/// - `value` : value to get the progress segment
/// - `full_pixel_width` : width of the total progress bar in pixels
/// - `background_color` : background color of the progress segment
fn create_html_progress_segment<TLectureBackend>(backend: &mut TLectureBackend,
				full_nb_idea: usize, value: usize, full_pixel_width: usize, background_color: &String)
	where TLectureBackend: PAbstractLectureBackend
{
	if value == 0 || full_nb_idea == 0 {
		return;
	}
	let segment_pixel_witdh = (full_pixel_width*value)/full_nb_idea;
	backend.write(&String::from(format!("<span style=\"display: inline-block;width: {}px;height: 30px;background-color: {}\"></span>", segment_pixel_witdh, background_color)));
}

#[cfg(test)]
mod tests{
	use super::*;
	use crate::pcontent::pstrbackend::PStrBackend;
	
	///Test the default PContentProgress
	#[test]
	fn test_pcontent_progress_default(){
		let progress = PContentProgress::new();
		let mut backend = PStrBackend::new();
		progress.to_html(&mut backend, &PLabelId::new(42));
		assert_eq!(backend.get_body(), &String::from("Status <span id=\"42\" style=\"display: inline-block;width: 200px;height: 30px\"></span> Done <b>0 %</b>"));
	}
}