rrn 0.1.3

batch rename files/dirs by regex
use getopt::{Opt, Parser};
use regex::Regex;
use rust_i18n::t;
use std::{collections::HashMap, env};

#[derive(Debug)]
pub(crate) enum TargetMode {
    File,
    Dir,
}

#[derive(Debug)]
pub(crate) enum ExecMode {
    DryRun,
    Exec,
}

#[derive(Debug)]
pub(crate) enum ParseArgFailure {
    Help,
    Version,
    Invalid,
}

#[derive(Debug)]
pub(crate) struct Param {
    from: Option<String>,
    from_regex: Option<Regex>,
    to: Option<String>,
    target: TargetMode,
    exec: ExecMode,
}
impl Param {
    fn new(map: &HashMap<String, String>) -> Self {
        Self {
            from: map
                .get("from")
                .or(Some(&String::from("")))
                .map(|x| x.to_string()),
            from_regex: None,
            to: map
                .get("to")
                .or(Some(&String::from("")))
                .map(|x| x.to_string()),
            target: match map.get("dir") {
                None => TargetMode::File,
                Some(_) => TargetMode::Dir,
            },
            exec: match map.get("exec") {
                None => ExecMode::DryRun,
                Some(_) => ExecMode::Exec,
            },
        }
    }

    fn invalid(&self) -> bool {
        if check_if_not_exist(&self.from) {
            eprintln!("{}", t!("param.from.not_specified"));
            return true;
        }
        if check_if_not_exist(&self.to) {
            eprintln!("{}", t!("param.to.not_specified"));
            return true;
        }
        false
    }

    fn compile_regex(&mut self) {
        self.from_regex
            .replace(to_regex(self.from.as_ref().unwrap().clone()));
    }

    pub(crate) fn get_from_regex(&self) -> &Regex {
        self.from_regex.as_ref().unwrap()
    }

    pub(crate) fn get_to_pattern(&self) -> String {
        String::from(self.to.as_ref().unwrap())
    }

    pub(crate) fn get_target_mode(&self) -> &TargetMode {
        &self.target
    }

    pub(crate) fn get_exec_mode(&self) -> &ExecMode {
        &self.exec
    }
}

fn to_regex(from_pattern: String) -> Regex {
    match Regex::new(&from_pattern) {
        Ok(regex) => regex,
        Err(_) => panic!("{}", t!("param.not.regex", from_pattern=> from_pattern)),
    }
}

fn check_if_not_exist(opt: &Option<String>) -> bool {
    opt.is_none() || opt.as_ref().unwrap().to_string().is_empty()
}

pub(crate) fn args2param() -> Result<Param, ParseArgFailure> {
    let args = env::args().collect::<Vec<String>>();
    let mut opts = Parser::new(&args, "vhf:t:dx");
    let mut map = HashMap::new();
    loop {
        let rs = opts.next().transpose();
        if let Ok(opt) = rs {
            let (key, val) = match opt {
                None => break,
                Some(opt) => match opt {
                    Opt('f', Some(val)) => ("from".to_string(), val),
                    Opt('t', Some(val)) => ("to".to_string(), val),
                    Opt('d', None) => ("dir".to_string(), "true".to_string()),
                    Opt('x', None) => ("exec".to_string(), "true".to_string()),
                    Opt('h', None) => ("help".to_string(), "true".to_string()),
                    Opt('v', None) => ("version".to_string(), "true".to_string()),
                    _ => unreachable!(),
                },
            };
            map.insert(key, val);
        } else {
            continue;
        }
    }
    if map.is_empty() || map.contains_key("help") {
        print_help();
        return Err(ParseArgFailure::Help);
    }
    if map.contains_key("version") {
        println!(env!("CARGO_PKG_VERSION"));
        return Err(ParseArgFailure::Version);
    }
    let mut param = Param::new(&map);
    if param.invalid() {
        return Err(ParseArgFailure::Invalid);
    }
    param.compile_regex();
    Ok(param)
}

pub(crate) fn print_help() {
    eprintln!("------------------------------------------------------");
    eprintln!("{}",t!("help.00"));
    eprintln!();
    eprintln!("{}",t!("help.01"));
    eprintln!("{}",t!("help.02"));
    eprintln!("{}",t!("help.03"));
    eprintln!("{}",t!("help.04"));
    eprintln!("{}",t!("help.05"));
    eprintln!("{}",t!("help.06"));
    eprintln!("{}",t!("help.07"));
    eprintln!("{}",t!("help.08"));
    eprintln!("{}",t!("help.09"));
    eprintln!("{}",t!("help.10"));
    eprintln!("------------------------------------------------------");
}