segul 0.23.2

An ultrafast and memory-efficient tool for phylogenomics
Documentation
use std::path::{Path, PathBuf};

use colored::Colorize;

use crate::core::sequence::rename::{SeqRenamingParameters, SequenceRenaming, SequenceRenamingDry};
use crate::helper::logger::AlignSeqLogger;
use crate::helper::utils;
use crate::parser::delimited;

use crate::cli::args::sequence::SequenceRenameArgs;
use crate::cli::{collect_paths, AlignSeqInput, InputCli, OutputCli};

impl InputCli for RenameParser<'_> {}
impl OutputCli for RenameParser<'_> {}
impl AlignSeqInput for RenameParser<'_> {}

pub(in crate::cli) struct RenameParser<'a> {
    args: &'a SequenceRenameArgs,
    input_dir: Option<PathBuf>,
}

impl<'a> RenameParser<'a> {
    pub(in crate::cli) fn new(args: &'a SequenceRenameArgs) -> Self {
        Self {
            args,
            input_dir: None,
        }
    }

    pub(in crate::cli) fn rename(&mut self) {
        let input_fmt = self.parse_input_fmt(&self.args.in_fmt.input_fmt);
        let datatype = self.parse_datatype(&self.args.in_fmt.datatype);
        let output_fmt = self.parse_output_fmt(&self.args.out_fmt.output_fmt);
        let task = "Sequence Renaming";
        let dir = &self.args.io.dir;
        let files = collect_paths!(self, dir, input_fmt);
        AlignSeqLogger::new(
            self.input_dir.as_deref(),
            &input_fmt,
            &datatype,
            files.len(),
        )
        .log(task);
        let opts = self.parse_rename_opts();
        if self.args.dry_run {
            SequenceRenamingDry::new(&input_fmt, &datatype, &opts).dry_run(&files);
        } else {
            self.check_output_dir_exist(&self.args.output, self.args.io.force);
            SequenceRenaming::new(&input_fmt, &datatype, &self.args.output, &output_fmt, &opts)
                .rename(&files);
        }
    }

    fn parse_rename_opts(&self) -> SeqRenamingParameters {
        log::info!("{}", "Renaming Parameters".yellow());

        if let Some(path) = &self.args.replace_id {
            let id_path = Path::new(&path);
            let names = self.parse_names(id_path);
            self.print_rename_id_info(id_path, &names.len());
            SeqRenamingParameters::RnId(names)
        } else if let Some(input_str) = &self.args.remove {
            self.print_remove_str_info(input_str);
            SeqRenamingParameters::RmStr(input_str.to_string())
        } else if let Some(re) = &self.args.remove_re {
            self.print_remove_re_info(re, "--remove-re");
            SeqRenamingParameters::RmRegex(re.to_string(), false)
        } else if let Some(re) = &self.args.remove_re_all {
            let is_all = true;
            self.print_remove_re_info(re, "--remove-re-all");
            SeqRenamingParameters::RmRegex(re.to_string(), is_all)
        } else if let Some(id) = &self.args.replace_from {
            match &self.args.replace_to {
                Some(to) => {
                    self.print_replace_str_info(id, to);
                    SeqRenamingParameters::RpStr(id.to_string(), to.to_string())
                }
                None => unreachable!("Missing replace-to"),
            }
        } else if let Some(re) = &self.args.replace_from_re {
            match &self.args.replace_to {
                Some(to) => {
                    self.print_replace_re_info(re, to, "--replace-from-re");
                    SeqRenamingParameters::RpRegex(re.to_string(), to.to_string(), false)
                }
                None => unreachable!("Missing replace-to"),
            }
        } else if let Some(re) = &self.args.replace_from_re_all {
            match &self.args.replace_to {
                Some(to) => {
                    self.print_replace_re_info(re, to, "--replace-from-re-all");
                    SeqRenamingParameters::RpRegex(re.to_string(), to.to_string(), true)
                }
                None => unreachable!("Missing replace-to"),
            }
        } else {
            unreachable!("Missing rename options")
        }
    }

    fn parse_names(&self, id_path: &Path) -> Vec<(String, String)> {
        delimited::parse_delimited_text(id_path)
    }

    fn print_rename_id_info(&self, id_path: &Path, id_count: &usize) {
        log::info!("{:18}: --replace", "Options");
        log::info!(
            "{:18}: {}",
            "File",
            id_path
                .file_name()
                .expect("Failed parsing name path")
                .to_string_lossy()
        );
        log::info!("{:18}: {}\n", "New ID counts", utils::fmt_num(id_count));
    }

    fn print_remove_str_info(&self, input_str: &str) {
        log::info!("{:18}: --remove", "Options");
        log::info!("{:18}: {}\n", "Input string", input_str);
    }

    fn print_replace_str_info(&self, input_str: &str, output_str: &str) {
        log::info!("{:18}: --replace", "Options");
        log::info!("{:18}: {}", "Replace from", input_str);
        log::info!("{:18}: {}\n", "Replace to", output_str);
    }

    fn print_remove_re_info(&self, input_re: &str, options: &str) {
        log::info!("{:18}: {}", "Options", options);
        log::info!("{:18}: {}\n", "Input regex", input_re);
    }

    fn print_replace_re_info(&self, input_re: &str, output_str: &str, options: &str) {
        log::info!("{:18}: {}", "Options", options);
        log::info!("{:18}: {}", "Replace from", input_re);
        log::info!("{:18}: {}\n", "Replace to", output_str);
    }
}