use clap::Subcommand;
use conciliator::{
Claw,
Conciliator
};
use greg::Point;
use crate::error::Result;
use crate::Nunc;
use crate::cli::arg;
use crate::core::{
Log,
Tree,
Zone
};
#[derive(Subcommand)]
pub(crate) enum Cmd {
Start {
activity: arg::Activity,
when: Option<arg::TimeArg>
},
Stop {
when: Option<arg::TimeArg>,
#[clap(short, long)]
activity: Option<arg::Activity>
},
}
pub(crate) fn cmd_start(
con: &Claw,
nunc: &Nunc,
activity: arg::Activity,
when: Option<arg::TimeArg>)
-> Result<()>
{
let cal = nunc.load_calendar()?;
let when = match when {
Some(t) => {
let validated = t.resolve_with(&cal);
con.status("Parsed time: ").push(cal.lookup(validated));
validated
},
None => Point::now()
};
let act = activity.validate(nunc, con)?;
nunc.start(&act, when)?;
con.status("Started ")
.push(&act)
.push(" at ")
.push(cal.lookup(when));
Ok(())
}
pub(crate) fn cmd_stop(
con: &Claw,
nunc: &Nunc,
activity: Option<arg::Activity>,
when: Option<arg::TimeArg>)
-> Result<()>
{
let cal = nunc.load_calendar()?;
let when = match when {
Some(t) => {
let validated = t.resolve_with(&cal);
con.status("Parsed time: ").push(cal.lookup(validated));
validated
},
None => Point::now()
};
let mut active = nunc.get_active_entries()?;
if let Some(activity) = activity {
let activity = activity.validate(nunc, con)?;
active.retain(|ent| ent.activity_id == activity.id);
if active.is_empty() {ret_errmsg!("Activity not started!")}
}
let (ent, act) = match active.len() {
0 => ret_errmsg!("No started activities!"),
1 => {
let ent = active.first().unwrap();
let act = nunc.get_activity(ent.activity_id)?;
(ent, act)
}
_ => {
let activities = active
.iter()
.map(|ent| nunc
.get_activity(ent.activity_id)
.and_then(|act| nunc
.get_path_string(act.category_id)
.map(|path| act.resolve(path))
)
.map_err(Into::into)
)
.collect::<Result<Vec<_>>>()?;
let selected = con
.select(activities, "activities", "Select activity")
.unwrap();
let entry = active
.iter()
.find(|ent| ent.activity_id == selected.id)
.unwrap();
(entry, selected.revert())
}
};
if nunc.stop(ent, when)? {
con.status("Stopped ")
.push(&act)
.push(" at ")
.push(cal.lookup(when));
Ok(())
}
else {
con.error("Failed to stop ")
.push(&act)
.push(" at ")
.push(cal.lookup(when));
ret_errmsg!("Failed to stop activity!")
}
}
impl Cmd {
pub(crate) fn run(self, con: &Claw, nunc: &Nunc) -> Result<()> {
match self {
Cmd::Start {activity, when} => cmd_start(con, nunc, activity, when),
Cmd::Stop {activity, when} => cmd_stop(con, nunc, activity, when)
}
}
}
#[test]
fn start_stop() -> Result<()> {
use crate::cli::Tester;
let tester = Tester::init()?;
tester.run(["start", "Invalid"]).unwrap_err();
tester.run(["create", "category", "/", "root"])?;
tester.run(["create", "activity", "/root", "one"])?;
tester.run(["start", "one"])?;
tester.run(["stop", "10m"]).unwrap_err();
tester.run(["stop"])?;
tester.run(["stop"]).unwrap_err();
tester.run(["start", "one", "10:15"])?;
tester.run(["stop", "10:14:59"]).unwrap_err();
tester.run(["stop", "10:15:01"])?;
tester.run(["stop"]).unwrap_err();
tester.run(["start", "one", "2022-01-01 10:15"])?;
tester.run(["stop", "2022-01-01 10:14:59"]).unwrap_err();
tester.run(["stop", "2022-01-02"])?;
tester.run(["stop"]).unwrap_err();
tester.run(["start", "one"])?;
tester.run(["stop", "-a", "one"])?;
tester.run(["stop", "-a", "one"]).unwrap_err();
tester.run(["create", "activity", "/root", "two"])?;
tester.run(["start", "one"])?;
tester.run(["start", "one"]).unwrap_err();
tester.run(["start", "two"])?;
tester.run(["stop", "-a", "one"])?;
tester.run(["start", "two"]).unwrap_err();
tester.run(["stop", "-a", "two"])?;
tester.run(["stop", "-a", "two"]).unwrap_err();
Ok(())
}