use std::io;
use super::{legacy, Flags, Reach};
use crate::civil::start_of_day;
use crate::task::Status;
use crate::verb::Verb;
pub(crate) fn parse(verb: Verb, args: &[String]) -> io::Result<Flags> {
let mut f = Flags::default();
let mut args = args.iter();
while let Some(arg) = args.next() {
match arg.as_str() {
"--json" => f.json = true,
"--plain" => f.plain = true,
"--status" | "-s" if verb == Verb::List => apply_status(&mut f, value(&mut args, "--status")?)?,
"--all" if verb == Verb::List => set_reach(&mut f, Reach::All)?,
"--everywhere" if verb == Verb::List => f.everywhere = true,
"--tag" if verb == Verb::List => f.tags.push(value(&mut args, "--tag")?.clone()),
"--claimant" if verb == Verb::List => f.claimant = Some(value(&mut args, "--claimant")?.clone()),
"--since" if verb == Verb::List => f.since = Some(date(value(&mut args, "--since")?)?),
"--until" if verb == Verb::List => f.until = Some(date(value(&mut args, "--until")?)? + 86_399),
arg if legacy::flag(arg).is_some() => f.legacy = legacy::flag(arg),
flag if flag.starts_with('-') => {
return Err(crate::usage(format!("{}: unexpected flag '{flag}'", verb.token())));
}
_ => {
if f.target.replace(arg.clone()).is_some() {
return Err(crate::usage(format!("{}: at most one argument", verb.token())));
}
}
}
}
if verb == Verb::Show && f.target.is_none() {
return Err(crate::usage("show: needs a ball id"));
}
if f.legacy.is_some() && f.reach != Reach::Live {
return Err(crate::usage("list: --legacy serves the live legacy set — it has no --all/--status closed reach"));
}
Ok(f)
}
fn value<'a>(args: &mut std::slice::Iter<'a, String>, flag: &str) -> io::Result<&'a String> {
args.next().ok_or_else(|| crate::usage(format!("list: {flag} needs a value")))
}
fn set_reach(f: &mut Flags, reach: Reach) -> io::Result<()> {
if f.reach != Reach::Live {
return Err(crate::usage("list: choose one of --status closed / --all"));
}
f.reach = reach;
Ok(())
}
fn date(value: &str) -> io::Result<i64> {
start_of_day(value).ok_or_else(|| crate::usage(format!("list: bad date '{value}' (want YYYY-MM-DD)")))
}
fn apply_status(f: &mut Flags, value: &str) -> io::Result<()> {
if value == "closed" {
return set_reach(f, Reach::Dead);
}
f.status = Some(Status::from_word(value).ok_or_else(|| {
crate::usage(format!("list: unknown --status '{value}' (want ready|blocked|claimed|closed)"))
})?);
Ok(())
}