use crate::TestStatus;
use super::generic::Generic;

#[derive(Debug, Default)]
pub struct Case {
    pub(crate) status:		TestStatus,
    pub(crate) generic:		Generic,
    pub(crate) backtrace:	Option<String>,
    pub(crate) reason:		Option<String>,

    pub(crate) val_expect:	Option<String>,
    pub(crate) val_got:		Option<String>,

    pub(crate) stderr:		Option<std::fs::File>,
    pub(crate) stdout:		Option<std::fs::File>,
}

impl Case {
    pub fn new() -> Self
    {
	Self::default()
    }

    pub fn record_duration(&mut self, duration: std::time::Duration)
    {
	self.generic.record_duration(duration)
    }

    pub fn record_expect(&mut self, s: &str)
    {
	assert!(self.val_expect.is_none());

	self.val_expect = Some(s.to_string());
    }

    pub fn record_got(&mut self, s: &str)
    {
	assert!(self.val_got.is_none());

	self.val_got = Some(s.to_string());
    }

    fn read_file(f: &Option<std::fs::File>) -> std::io::Result<Option<String>>
    {
	fn read(mut f: std::fs::File) -> std::io::Result<String>
	{
	    use std::io::Read;
	    use std::io::Seek;
	    use std::io::SeekFrom;

	    let mut buf = String::new();

	    f.seek(SeekFrom::Start(0))?;
	    f.read_to_string(&mut buf)?;
	    Ok(buf)
	}

	Ok(if let Some(f) = f {
	    Some(read(f.try_clone()?)?)
	} else {
	    None
	})
    }

    pub fn read_stderr(&self) -> std::io::Result<Option<String>>
    {
	Self::read_file(&self.stderr)
    }

    pub fn read_stdout(&self) -> std::io::Result<Option<String>>
    {
	Self::read_file(&self.stdout)
    }

    pub fn get_stderr(&mut self) -> std::io::Result<std::fs::File>
    {
	use std::io::Write;

	if self.stderr.is_none() {
	    self.stderr = Some(tempfile::tempfile()?);
	}

	self.stderr.as_ref().unwrap().flush()?;
	self.stderr.as_ref().unwrap().try_clone()
    }

    pub fn get_stdout(&mut self) -> std::io::Result<std::fs::File>
    {
	use std::io::Write;

	if self.stdout.is_none() {
	    self.stdout = Some(tempfile::tempfile()?);
	}

	self.stdout.as_ref().unwrap().flush()?;
	self.stdout.as_ref().unwrap().try_clone()
    }

    #[allow(dead_code)]
    pub fn set_backtrace(&mut self, s: &str)
    {
	self.backtrace = Some(s.to_string());
    }

    pub fn set_reason(&mut self, s: &str)
    {
	self.reason = Some(s.to_string());
    }
}
