1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use std::path::{Path, PathBuf};

use crate::handler::align::split::Splitter;
use crate::helper::logger::AlignSeqLogger;
use crate::helper::types::PartitionFmt;

use super::args::AlignSplitArgs;
use super::{AlignSeqInput, ConcatCli, InputCli, OutputCli};

impl OutputCli for SplitParser<'_> {}
impl InputCli for SplitParser<'_> {}
impl ConcatCli for SplitParser<'_> {}
impl AlignSeqInput for SplitParser<'_> {}

pub(in crate::cli) struct SplitParser<'a> {
    args: &'a AlignSplitArgs,
}

impl<'a> SplitParser<'a> {
    pub(in crate::cli) fn new(args: &'a AlignSplitArgs) -> Self {
        Self { args }
    }

    pub(in crate::cli) fn split(&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);

        // If users do not specify input partition.
        // Assume partition is in the sequence file.
        let partitions = match &&self.args.input_partition {
            Some(path) => path,
            None => &self.args.input,
        };

        let part_fmt = self.parse_part_fmt(partitions);
        let task_desc = "Alignment splitting";
        AlignSeqLogger::new(&None::<PathBuf>, &input_fmt, &datatype, task_desc, 1).log();
        self.check_output_dir_exist(&self.args.output, self.args.force);
        let split = Splitter::new(
            &self.args.input,
            &datatype,
            &input_fmt,
            &self.args.output,
            &output_fmt,
        );
        split.split_alignment(
            partitions,
            &part_fmt,
            &self.args.prefix,
            self.args.skip_checking,
        );
    }

    fn parse_part_fmt(&self, part_path: &Path) -> PartitionFmt {
        match &self.args.part_fmt {
            Some(fmt) => self.parse_partition_fmt(fmt),
            None => self.infer_part_fmt(part_path),
        }
    }

    fn infer_part_fmt(&self, part_path: &Path) -> PartitionFmt {
        let ext = part_path
            .extension()
            .expect("Failed getting file extension")
            .to_str()
            .expect("Failed getting file extension as string");
        self.parse_partition_ext(ext)
    }

    fn parse_partition_fmt(&self, fmt: &str) -> PartitionFmt {
        match fmt {
            "raxml" => PartitionFmt::Raxml,
            "nexus" => PartitionFmt::Nexus,
            _ => unreachable!(
                "Cannot infer partition format from the file extension.\
                Please, specify using the --partition (or -p in short version) option"
            ),
        }
    }

    fn parse_partition_ext(&self, ext: &str) -> PartitionFmt {
        match ext {
            "txt" | "raxml" => PartitionFmt::Raxml,
            "nex" | "nexus" | "charset" => PartitionFmt::Nexus,
            _ => panic!(
                "Cannot infer partition format from the file extension.\
                Please, specify using the --partition (or -p in short version) option"
            ),
        }
    }
}