use crate::plagiarism_database::{PlagiarismResult, TextOwnerID};
use crate::text_utils::get_boldtext_segments_from_intervals;
use fs_extra;
use gcollections::ops::*;
use handlebars::Handlebars;
use interval::interval_set::*;
use serde::Serialize;
use std::collections::HashMap;
use std::fs::create_dir_all;
use std::fs::File;
use std::process::Command;
const TEMPLATE_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/templates/report.hbs");
const ASSETS_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/assets/");
const OUTPUT_DIR: &str = "./www/";
const OUTPUT_FILE_PATH: &str = "./www/report.html";
#[derive(Serialize, PartialEq, Eq, Debug)]
pub struct TextMaybeBold {
pub text: String,
pub is_bold: bool,
}
#[derive(Serialize, Debug)]
struct HBPlagiarismResult {
owner_id1: TextOwnerID,
owner_id2: TextOwnerID,
trusted_owner1: bool,
equal_fragments: bool,
text_display1: Vec<TextMaybeBold>,
text_display2: Vec<TextMaybeBold>,
text1_plag_percent: usize,
text2_plag_percent: usize,
}
pub fn output_results(
results: &mut Vec<PlagiarismResult>,
texts: HashMap<TextOwnerID, Vec<String>>,
open_html_after: bool,
) {
results.sort_by(|a, b| {
b.matching_fragments
.len()
.partial_cmp(&a.matching_fragments.len())
.unwrap()
});
let mut plag_results: Vec<HBPlagiarismResult> = Vec::new();
for result in results {
let mut text1_intervals = IntervalSet::empty();
let mut text2_intervals = IntervalSet::empty();
for (text1_locs, text2_locs) in &result.matching_fragments_locations {
for text1_loc in text1_locs {
text1_intervals = text1_intervals.union(&text1_loc.to_interval_set());
}
for text2_loc in text2_locs {
text2_intervals = text2_intervals.union(&text2_loc.to_interval_set());
}
}
let numwords1 = text1_intervals.iter().fold(0, |acc, inter| {
acc + (bounded::Bounded::upper(inter) - bounded::Bounded::lower(inter) + 1)
});
let numwords2 = text2_intervals.iter().fold(0, |acc, inter| {
acc + (bounded::Bounded::upper(inter) - bounded::Bounded::lower(inter) + 1)
});
let t1_text = texts.get(&result.owner_id1).unwrap_or_else(|| {
panic!(
"Could not find text for owner {} in text map",
&result.owner_id1
)
});
let t1_boldtext: Vec<TextMaybeBold> =
get_boldtext_segments_from_intervals(&t1_text, &text1_intervals);
let t2_text: &Vec<String> = texts.get(&result.owner_id2).unwrap_or_else(|| {
panic!(
"Could not find text for owner {} in text map",
&result.owner_id2
)
});
let t2_boldtext: Vec<TextMaybeBold> =
get_boldtext_segments_from_intervals(&t2_text, &text2_intervals);
plag_results.push(HBPlagiarismResult {
owner_id1: result.owner_id1.clone(),
owner_id2: result.owner_id2.clone(),
trusted_owner1: result.trusted_owner1,
equal_fragments: result.equal_fragments,
text_display1: t1_boldtext,
text_display2: t2_boldtext,
text1_plag_percent: ((numwords1 as f32) / (t1_text.len() as f32) * 100.0) as usize,
text2_plag_percent: ((numwords2 as f32) / (t2_text.len() as f32) * 100.0) as usize,
})
}
let mut source_template = File::open(TEMPLATE_PATH).unwrap_or_else(|_| {
panic!(
"Cannot open template path {}, check path for existence of .hbs file",
TEMPLATE_PATH
);
});
create_dir_all(OUTPUT_DIR).unwrap_or_else(|_| {
panic!(
"Cannot create {} folder, check for permissions errors",
OUTPUT_DIR
)
});
let mut output_file = File::create(OUTPUT_FILE_PATH).unwrap_or_else(|_| {
panic!(
"Cannot create output {} file, check for permissions errors",
OUTPUT_FILE_PATH
)
});
let mut copy_options = fs_extra::dir::CopyOptions::new();
copy_options.overwrite = true;
fs_extra::dir::copy(ASSETS_PATH, OUTPUT_DIR, ©_options).unwrap_or_else(|_| {
panic!(
"Failed to copy assets from {} to {}",
ASSETS_PATH, OUTPUT_DIR
)
});
let hbars = Handlebars::new();
hbars
.render_template_source_to_write(&mut source_template, &plag_results, &mut output_file)
.unwrap_or_else(|_| {
panic!(
"Cannot render to template file without errors. JSON object: {:?}",
&plag_results
);
});
if open_html_after && cfg!(target_os = "linux") {
Command::new("xdg-open")
.args(&["./www/report.html"])
.output()
.expect("Failed to execute xdg-open to open ./www/report.html!");
}
}