use std::error::Error;
use clap::{App, Arg};
use std::fs::File;
use std::io::{self, BufRead, BufReader};

type MyResult<T> = Result<T, Box<dyn Error>>;

#[derive(Debug)]
pub struct Config {
    files: Vec<String>,
    numbered: bool,
    nonblank: bool,
}

pub fn run(config: Config) -> MyResult<()> {
    for filename in config.files {
        match open(&filename) {
            Err(err) => eprintln!("Failed to open {}: {}", filename, err),
            Ok(file) => print(&file, &config.numbered, &config.nonblank),
        }
    }
    Ok(())
}

pub fn get_args() -> MyResult<Config> {
    let matches = App::new("cat")
        .version("0.1.0")
        .author("perro <hi@perrotuerto.blog>")
        .about("Rust cat")
        .arg(
            Arg::with_name("files")
                .value_name("ARCHIVOS")
                .help("Archivos de entrada")
                .multiple(true)
                .default_value("-"),
        )
        .arg(
            Arg::with_name("numbered")
                .short("n")
                .long("number")
                .help("Imprime números de línea")
                .takes_value(false)
                .conflicts_with("nonblank"),
        )
        .arg(
            Arg::with_name("nonblank")
                .short("b")
                .long("number-nonblank")
                .help("Imprime números de línea solo si no están vacías")
                .takes_value(false),
        )
        .get_matches();

    Ok(Config {
        files: matches.values_of_lossy("files").unwrap(),
        numbered: matches.is_present("numbered"),
        nonblank: matches.is_present("nonblank"),
    })
}

fn open(filename: &str) -> MyResult<Box<dyn BufRead>> {
    match filename {
        "-" => Ok(Box::new(BufReader::new(io::stdin()))),
        _ => Ok(Box::new(BufReader::new(File::open(filename)?))),
    }
}

fn print(_file: &Box<dyn BufRead>, _numbered: &bool, _nonblank: &bool) {
    // TODO
}
