use std::fs::ReadDir;
use std::path::Path;

//#[derive(Debug)]
//#[allow(dead_code)]
struct Walk {
    rds: Vec<ReadDir>,
}

impl Walk {
    fn new(root: &str) -> Result<Walk, Box<dyn std::error::Error>> {
        let path = Path::new(root);
        match path.read_dir() {
            Ok(rd) => {
                let w = Walk { rds: vec![rd] };
                std::result::Result::Ok(w)
            }
            Err(err) => {
                println!("Could not open dir '{}': {}", root, err);
                Err(Box::new(err))
            }
        }
    }
}

impl Iterator for Walk {
    type Item = String;

    fn next(&mut self) -> Option<Self::Item> {
        if self.rds.is_empty() {
            //println!("empty rds");
            return None;
        }
        let count = self.rds.len();
        let entry = self.rds[count - 1].next();
        match entry {
            Some(result) => match result {
                Ok(dir_entry) => {
                    if dir_entry.path().is_dir() {
                        match dir_entry.path().read_dir() {
                            Ok(rd) => {
                                self.rds.push(rd);
                            }
                            Err(err) => {
                                println!("Could not open dir {}", err);
                            }
                        }
                    }
                    return Some(dir_entry.path().to_str().unwrap().to_string());
                }
                Err(_err) => None,
            },
            None => {
                self.rds.pop();
                self.next()
            }
        }
    }
}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    if args.len() != 2 {
        eprintln!("Usage: {} PATH", args[0]);
        std::process::exit(1);
    }
    let path_from_user = &args[1];
    let tree = match Walk::new(path_from_user) {
        Ok(tree) => tree,
        Err(err) => {
            println!("Error: {}", err);
            std::process::exit(1);
        }
    };
    //println!("{:?}", &tree);
    for entry in tree {
        println!("{:?}", entry);
    }
}
