use problemo::{common::*, *};

// First see: examples/accumulate.rs

// If we want to have error-accumulating functions in dyn-compatible traits,
// we cannot use a generic ProblemReceiver.

// But we can use ProblemReceiverRef instead, which we will demonstrate here.

// This trait is dyn-compatible
pub trait FileReader {
    fn read_files(
        &self,
        paths: &[&str],
        problems: ProblemReceiverRef,
    ) -> Result<Vec<String>, Problem>;
}

pub struct StandardFileReader;

impl FileReader for StandardFileReader {
    fn read_files(
        &self,
        paths: &[&str],
        mut problems: ProblemReceiverRef,
    ) -> Result<Vec<String>, Problem> {
        let mut strings = Vec::default();
        for path in paths {
            // ProblemReceiverRef implements ProblemReceiver
            if let Some(string) = std::fs::read_to_string(path)
                .via(LowLevelError)
                .give_ok(&mut problems)?
            {
                strings.push(string);
            }
        }
        Ok(strings)
    }
}

// See? FileReader is really dyn-compatible.
fn run(file_reader: Box<dyn FileReader>) -> Result<Vec<String>, Problem> {
    let mut problems = Problems::default();

    // as_ref() will create a ProblemReceiverRef for any ProblemReceiver implementation
    let strings = file_reader.read_files(
        &["non-existing1.txt", "non-existing2.txt"],
        problems.as_ref(),
    )?;

    problems.check()?;
    Ok(strings)
}

fn main() {
    if let Err(problem) = run(Box::new(StandardFileReader)) {
        match problem.error_of_type::<Problems>() {
            Some(problems) => {
                for problem in problems {
                    println!("• {}", problem);
                }
            }

            None => println!("{}", problem),
        }
    }
}
