// use crate::{Error, FrcResolution, ResultsCache};

// use locs::AllocatedLocalisation;
// use plotters::chart::{ChartContext};
// use plotters::coord::Shift;
// use plotters::coord::types::RangedCoordf64;
// use plotters::prelude::*;

// use std::io::{Write, Error as IoError};

// fn sampling_logic() -> &'static str
// {
// 	"This advice is based on the following logic. "
// }

// type Chart<'a> = ChartContext<'a, SVGBackend<'a>, Cartesian2d<RangedCoordf64, RangedCoordf64>>;

// fn render_plot_on_chart<'a>(chart: &mut Chart, resolution: &FrcResolution, plot_labels: bool) -> Result<(), DrawingAreaErrorKind<IoError>> 
// {
// 	let qs = resolution.qs();
// 	let correlations = resolution.correlations();
//     let data = qs.iter().copied().zip(correlations.iter().copied());
//     let series = chart.draw_series(LineSeries::new(data, &RED,))?;
//     if plot_labels
//     {
//         series.label("correlations").legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &RED));
//     }

//     let threshold_data = qs.iter().copied().zip(resolution.threshold_curve().iter().copied());

//     let series = chart.draw_series(LineSeries::new(threshold_data, &BLUE,))?;
//     if plot_labels
//     {
//     	series.label("threshold").legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &BLUE));
//     }

//     chart
//         .configure_series_labels()
//         .background_style(&WHITE.mix(0.8))
//         .border_style(&BLACK)
//         .draw()?;
// 	Ok(())
// }

// fn render_plot(area: &mut DrawingArea<SVGBackend<'_>, Shift>, resolution: &FrcResolution, label: &str) -> Result<(), DrawingAreaErrorKind<IoError>>
// {
// 	let qs = resolution.qs();
// 	let x_max = qs[qs.len() - 1];
// 	let correlations = resolution.correlations();
// 	let mut chart = ChartBuilder::on(area)
// 		        .caption(label, ("sans-serif", 50).into_font())
// 		        .margin(5)
// 		        .x_label_area_size(30)
// 		        .y_label_area_size(30)
// 		        .build_cartesian_2d(0f64..x_max, -1f64..1f64)?;

//     chart.configure_mesh().draw()?;

//     let data = qs.iter().copied().zip(correlations.iter().copied());
//     chart
//         .draw_series(LineSeries::new(data, &RED,))?
//         .label("correlations")
//         .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &RED));

//     let threshold_data = qs.iter().copied().zip(resolution.threshold_curve().iter().copied());

//     chart
//         .draw_series(LineSeries::new(threshold_data, &BLUE,))?
//         .label("threshold")
//         .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &BLUE));

//     chart
//         .configure_series_labels()
//         .background_style(&WHITE.mix(0.8))
//         .border_style(&BLACK)
//         .draw()?;
// 	Ok(())
// }

// fn close_together(zip_score: f64, half_score: f64, threshold: f64) -> bool
// {
// 	let ratio = zip_score / half_score;
// 	return ratio > (1.0 / threshold) && ratio < threshold
// }

// fn valid_bounds(zip_score: f64, half_score: f64) -> Option<String>
// {
// 	let ratio_threshold = 10.0;
// 	let mut message = String::new();
// 	if zip_score.is_infinite() || half_score.is_infinite()
// 	{
// 		message.push_str(&format!("one or more frcs are undefined"));
// 		return Some(message)
// 	}
// 	if !close_together(zip_score, half_score, ratio_threshold)
// 	{
// 		message.push_str("scores are very different");
// 	}
// 	if message.is_empty() {None} else{Some(message)}
// }

// fn to_io_error(error: DrawingAreaErrorKind<IoError>) -> IoError
// {
// 	IoError::new(std::io::ErrorKind::Other, error.to_string())
// }

// #[derive(Debug)]
// pub struct Sampling;

// impl Sampling
// {
// 	pub fn new() -> Self
// 	{
// 		Self
// 	}

// 	fn generate_data(localisations: &[AllocatedLocalisation], results: &mut ResultsCache) -> Result<(), Error>
// 	{
// 		{
// 			let _ = results.generate_zip_split_frc(localisations)?;
// 		}
// 		results.generate_half_split_frc(localisations).map(|_| ())
// 	}

// 	pub fn generate_with<W: Write>(&self, mut writer: W, localisations: &[AllocatedLocalisation], results: &mut ResultsCache) -> Result<(), Error>
// 	{
// 		let _ = writeln!(writer, r#"<svg height="100%" width="100%" xmlns="http://www.w3.org/2000/svg">"#).map_err(Error::from)?;
// 		let _ = write!(writer, "<text x=\"0\" y=\"30\" font-size=\"35\">\nSampling Report\n</text>").map_err(Error::from)?;
// 		let _ = Self::generate_data(localisations, results)?;
// 		let zip = results.get_zip().ok_or(Error::data("Could not generate zip data"))?;
// 		let half = results.get_half().ok_or(Error::data("Could not generate half data"))?;
// 		let zip_score = zip.as_value();
// 		let half_score = half.as_value();
// 		let error_message = valid_bounds(zip_score, half_score);
// 		let ok_snip = "<tspan fill=\"green\">your sampling is potentially sufficient</tspan>";
// 		let error_snip = "<tspan fill=\"red\">there is an issue</tspan> with your sampling";
// 		let x = if error_message.is_none() {ok_snip.to_string()} else{format!("{error_snip} because {}", error_message.unwrap())};
// 		let message = format!(r#"Frc bounds exist between {zip_score} and {half_score}. This indicates {x}."#);
// 		let _ = write!(writer, "\n<text x=\"0\" y=\"60\">\n{message}\n</text>").map_err(Error::from)?;

// 		let svg_string = self.inner_frc_plots(zip, half).map_err(to_io_error)?;
// 		let _ = writeln!(writer, "\n{svg_string}").map_err(Error::from)?;
// 		write!(writer, "<text x=\"0\" y=\"620\">\n{}\n</text>\n</svg>", sampling_logic()).map_err(Error::from)
// 	}

// 	fn inner_frc_plots(&self, zip: &FrcResolution, half: &FrcResolution) -> Result<String, DrawingAreaErrorKind<IoError>>
// 	{
// 		let width = 640;
// 		let mut buffer = String::new();
// 		{
// 			let root = SVGBackend::with_string(&mut buffer, (width, 480)).into_drawing_area();
// 	    	root.fill(&WHITE)?;
// 	    	let (mut left, mut right) = root.split_horizontally(width / 2);
// 	    	let _ = render_plot(&mut left, zip, "Zip")?;
// 	    	let _ = render_plot(&mut right, half, "Half")?;
// 		    root.present()?;
// 		}
// 		buffer.insert_str(4, " x=\"0\" y=\"100\"");
// 	    Ok(buffer)
// 	}
// }

// #[derive(Debug)]
// pub struct Resolution;

// impl Resolution
// {
// 	pub fn new() -> Self
// 	{
// 		Self
// 	}

// 	pub fn generate_with<W: Write>(&self, mut writer: W, localisations: &[AllocatedLocalisation], results: &mut ResultsCache) -> Result<(), Error>
// 	{
// 		let _ = writeln!(writer, r#"<svg height="100%" width="100%" xmlns="http://www.w3.org/2000/svg">"#)?;
// 		let _ = writeln!(writer, "<text x=\"0\" y=\"30\" font-size=\"35\">\nResolution Report\n</text>")?;		
// 		for _ in 0..10
// 		{
// 			let _ = results.generate_random_frc(localisations)?;
// 		}
// 		{
// 			let _ = results.generate_zip_split_frc(localisations)?;
// 		}
// 		{
// 			let _ = results.generate_half_split_frc(localisations)?;
// 		}
// 		let zip = results.get_zip().ok_or(Error::data("Could not generate zip data"))?;
// 		let half = results.get_half().ok_or(Error::data("Could not generate half data"))?;
// 		let randoms = results.get_randoms();
// 		let mean_resolution = Self::mean_resolution(zip, half, randoms);
// 		let ok_snip = "<tspan fill=\"green\">This resolution is valid</tspan>";
// 		let error_snip = "<tspan fill=\"red\">There is an issue</tspan> with the resolution of your data";
// 		let x = if mean_resolution.is_finite() {ok_snip} else{error_snip};
// 		let _ = writeln!(writer, "<text x=\"0\" y=\"60\">Mean Resolution: {mean_resolution}. {x}\n</text>");
// 		let svg_string = self.inner_frc_plots(zip, half, randoms).map_err(to_io_error)?;
// 		let _ = writeln!(writer, "{svg_string}").map_err(Error::from)?;
// 		let methods = "This report was generated by taking the zip split and half split FRC results and adding 10 random splits of the localisation data. This tells you about the average resolution in your image.\nHAWKMAN reports a map of the resolution.";
// 		write!(writer, "<text x=\"0\" y=\"620\">\n{methods}</text>\n</svg>").map_err(Error::from)
// 	}

// 	fn mean_resolution(zip: &FrcResolution, half: &FrcResolution, randoms: &Vec<FrcResolution>) -> f64
// 	{
// 		let values = [zip, half].into_iter().chain(randoms.iter()).map(|r| r.as_value());
// 		let mut total = 0.0;
// 		let mut count = 0;
// 		for value in values
// 		{
// 			if value.is_infinite()
// 			{
// 				continue;
// 			}
// 			total += value;
// 			count += 1;
// 		}
// 		if count == 0
// 		{
// 			return std::f64::INFINITY
// 		}
// 		total / (count as f64)
// 	}

// 	fn inner_frc_plots(&self, zip: &FrcResolution, half: &FrcResolution, randoms: &Vec<FrcResolution>) -> Result<String, DrawingAreaErrorKind<IoError>>
// 	{
// 		let width = 640;
// 		let mut buffer = String::new();
// 		{
// 			let root = SVGBackend::with_string(&mut buffer, (width, 480)).into_drawing_area();
// 	    	root.fill(&WHITE)?;
// 	    	let qs = zip.qs();
// 			let x_max = qs[qs.len() - 1];
// 			let mut chart = ChartBuilder::on(&root)
// 		        .caption("FRCs", ("sans-serif", 50).into_font())
// 		        .margin(5)
// 		        .x_label_area_size(30)
// 		        .y_label_area_size(30)
// 		        .build_cartesian_2d(0f64..x_max, -1f64..1f64)?;

//     		chart.configure_mesh().draw()?;
//     		render_plot_on_chart(&mut chart, zip, true)?;
//     		render_plot_on_chart(&mut chart, half, false)?;
//     		for frc in randoms
//     		{
//     			let _ = render_plot_on_chart(&mut chart, frc, false)?;
//     		}
// 		    root.present()?;
// 		}
// 		buffer.insert_str(4, " x=\"0\" y=\"100\"");
// 	    Ok(buffer)
// 	}
// }
