use crate::{error::{MLE, MLError, ErrorType}, Modloader, config::Cfg, db::lists_get, get_current_list, List};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Input {
pub command: Option<Cmd>,
pub mod_options: Option<ModOptions>,
pub mod_id: Option<String>,
pub mod_version: Option<String>,
pub set_version: bool,
pub all_lists: bool,
pub clean: bool,
pub direct_download: bool,
pub delete_old: bool,
pub list: Option<List>,
pub list_options: Option<ListOptions>,
pub list_id: Option<String>,
pub list_mcversion: Option<String>,
pub modloader: Option<Modloader>,
pub directory: Option<String>,
pub io_options: Option<IoOptions>,
pub file: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Cmd {
Mod,
List,
Update,
Download,
Io,
Version,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ModOptions {
Add,
Remove
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ListOptions {
Add,
Remove,
Change,
Version,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum IoOptions {
Export,
Import
}
impl Input {
fn from(config: Cfg, input: Vec<String>) -> MLE<Self> {
let input_string = input.join(" ");
let mut args: Vec<&str> = input_string.split('-').collect();
args.reverse();
args.pop();
args.reverse();
let mut command: Option<Cmd> = None;
let mut mod_options: Option<ModOptions> = None;
let mut mod_id: Option<String> = None;
let mut mod_version: Option<String> = None;
let mut set_version = false;
let mut all_lists = false;
let mut clean = false;
let mut direct_download = true;
let mut delete_old = false;
let mut list: Option<List> = None;
let mut list_options: Option<ListOptions> = None;
let mut list_id: Option<String> = None;
let mut list_mcversion: Option<String> = None;
let mut modloader: Option<Modloader> = None;
let mut directory: Option<String> = None;
let mut io_options: Option<IoOptions> = None;
let mut file: Option<String> = None;
for arg in args {
let arg_split: Vec<&str> = arg.trim().split(" ").collect();
match arg_split[0] {
"v" | "version" => {
command = Some(Cmd::Version);
},
"d" | "download" => {
command = Some(Cmd::Download);
},
"u" | "update" => {
command = Some(Cmd::Update);
},
"ma" => {
command = Some(Cmd::Mod);
mod_options = Some(ModOptions::Add);
if arg_split.len() == 2 {
mod_id = Some(String::from(arg_split[1]));
}
},
"mv" => {
command = Some(Cmd::Mod);
mod_options = Some(ModOptions::Add);
if arg_split.len() == 2 {
mod_version = Some(String::from(arg_split[1]));
};
},
"mr" => {
command = Some(Cmd::Mod);
mod_options = Some(ModOptions::Remove);
if arg_split.len() == 2 {
mod_id = Some(String::from(arg_split[1]));
}
},
"set_version" => {
set_version = true;
},
"all_lists" => {
all_lists = true;
},
"clean" => {
clean = true;
},
"no-download" => {
direct_download = false;
},
"delete_old" => {
delete_old = true;
},
"l" => {
if arg_split.len() == 2 {
list = Some(lists_get(config.clone(), String::from(arg_split[1]))?);
} else {
return Err(MLError::new(ErrorType::ArgumentError, "Please specify a list via it's id"));
}
}
"la" => {
command = Some(Cmd::List);
list_options = Some(ListOptions::Add);
list_id = Some(String::from(arg_split[1]));
},
"lr" => {
command = Some(Cmd::List);
list_options = Some(ListOptions::Remove);
},
"lc" => {
command = Some(Cmd::List);
list_options = Some(ListOptions::Change);
},
"lv" => {
command = Some(Cmd::List);
list_options = Some(ListOptions::Version);
if arg_split.len() == 2 {
list_mcversion = Some(String::from(arg_split[1]));
} else {
return Err(MLError::new(ErrorType::ArgumentError, "Please specify a minecraft version"));
}
},
"mcv" => {
if arg_split.len() == 2 {
list_mcversion = Some(String::from(arg_split[1]));
} else {
return Err(MLError::new(ErrorType::ArgumentError, "Please specify a minecraft version"));
}
},
"ml" => {
modloader = Some(Modloader::from(arg_split[1])?);
},
"dir" => {
directory = Some(String::from(arg_split[1]));
},
"export" => {
command = Some(Cmd::Io);
io_options = Some(IoOptions::Export);
},
"import" => {
command = Some(Cmd::Io);
io_options = Some(IoOptions::Import);
},
"f" => {
file = Some(String::from(arg_split[1]));
},
_ => return Err(MLError::new(ErrorType::ArgumentError, format!("Unknown Argument ({})", arg_split[0]).as_str())),
}
}
Ok(Self {
command,
mod_options,
mod_id,
mod_version,
set_version,
all_lists,
clean,
direct_download,
delete_old,
list,
list_options,
list_id,
list_mcversion,
modloader,
directory,
io_options,
file
})
}
}
pub async fn get_input(config: Cfg, args: Vec<String>) -> MLE<Input> {
let input = Input::from(config.clone(), args)?;
if input.command.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "No command specified")); };
match input.clone().command.unwrap() {
Cmd::Mod => check_mod(input, config),
Cmd::List => check_list(input, config),
_ => Ok(input),
}
}
//Move checks to commands? translate to variables there?
fn check_mod(mut input: Input, config: Cfg) -> MLE<Input> {
if input.mod_options.is_none() {
return Err(MLError::new(ErrorType::ArgumentError, "No mod option"));
};
match input.clone().mod_options.unwrap() {
//Check for MV if no mod-id on both
ModOptions::Add => {
if input.mod_id.is_none() && input.mod_version.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "No mod id/slug or version id")); };
if input.list_id.is_none() { input.list = Some(get_current_list(config.clone())?); };
Ok(input)
},
ModOptions::Remove => {
if input.mod_id.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "MODS_NO_MODID")); };
Ok(input)
},
}
}
fn check_list(mut input: Input, config: Cfg) -> MLE<Input> {
if input.list_options.is_none() {
return Err(MLError::new(ErrorType::ArgumentError, "NO_LIST_ARGUMENT"));
};
match input.clone().list_options.unwrap() {
ListOptions::Add => {
if input.list_id.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "no list id specified")); };
if input.list_mcversion.is_none() {
println!("No Minecraft Version specified, defaulting to latest release");
//TODO Get latest version
input.list_mcversion = Some(String::from("1.19.3"));
};
if input.modloader.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "no modloader specified")); };
if input.directory.is_none() { input.directory = Some(format!("./downloads/{}", input.clone().list_id.expect("earlier if failed"))) };
Ok(input)
},
ListOptions::Remove => {
if input.list.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "NO_LIST_SPECIFIED")); };
Ok(input)
},
ListOptions::Change => {
//TODO check if no change
if input.list.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "NO_LIST_SPECIFIED")); };
Ok(input)
},
ListOptions::Version => {
if input.list.is_none() {
println!("No list specified, using default");
input.list = Some(get_current_list(config)?);
};
Ok(input)
}
}
}
#[test]
fn input_from() {
let config = Cfg::init("modlist.toml").unwrap();
assert_eq!(
Input::from(config.clone(), vec![String::from("-la test -lv 1.19.3")]).unwrap(),
Input {
command: Some(Cmd::List),
mod_options: None,
mod_id: None,
mod_version: None,
set_version: false,
all_lists: false,
clean: false,
direct_download: false,
delete_old: false,
list: None,
list_options: Some(ListOptions::Add),
list_id: Some(String::from("test")),
list_mcversion: Some(String::from("1.19.3")),
modloader: None,
directory: None,
io_options: None,
file: None
}
);
}
#[tokio::test]
async fn get_input_test() {
let config = Cfg::init("modlist.toml").unwrap();
assert_eq!(
get_input(config.clone(), vec![String::from("-ma test")]).await.unwrap(),
Input {
command: Some(Cmd::Mod),
mod_options: Some(ModOptions::Add),
mod_id: Some(String::from("test")),
mod_version: None,
set_version: false,
all_lists: false,
clean: false,
direct_download: false,
delete_old: false,
list: Some(lists_get(config.clone(), String::from("one")).unwrap()),
list_options: None,
list_id: None,
list_mcversion: None,
modloader: None,
directory: None,
io_options: None,
file: None
}
)
}