nunc 0.2.0

WIP: time tracking application
Documentation
use clap::Subcommand;
use conciliator::{
	Claw,
	Conciliator
};
use greg::{
	Point,
	Calendar
};
use greg_tz::ZONES;

use crate::Nunc;
use crate::core::Zone;
use crate::data::zone::List;
use crate::error::Result;

use super::super::arg;

#[derive(Subcommand)]
pub(crate) enum Cmd {
	List,
	Current,
	Change {
		zone_name: String,

		when: Option<arg::TimeArg>,
	}
}

impl Cmd {
	pub(crate) fn run(self, con: &Claw, nunc: &Nunc) -> Result<()> {
		match self {
			Self::List => cmd_list(con, nunc),
			Self::Current => cmd_current(con, nunc),
			Self::Change {zone_name, when} =>
				cmd_change(con, nunc, zone_name, when)
		}
	}
}

pub(crate) fn cmd_list(con: &Claw, nunc: &Nunc) -> Result<()> {
	let zones = nunc.list()?;
	con.print(List::new(&zones));
	Ok(())
}
pub(crate) fn cmd_current(con: &Claw, nunc: &Nunc) -> Result<()> {
	match List::new(&nunc.list()?).current() {
		Some(current) => con.status(current),
		None => con.error("No time zone recorded!")
	};
	Ok(())
}

pub(crate) fn cmd_change(
	con: &Claw,
	nunc: &Nunc,
	zone_name: String,
	when: Option<arg::TimeArg>)
	-> Result<()>
{
	let zone = match ZONES.get(&zone_name) {
		Some(&zone) => zone,
		None => ret_errmsg!("Time zone {zone_name:?} not found!")
	};

	let when = match when {
		Some(time_arg) => {
			let point = time_arg.resolve_with(&Calendar(zone));
			con.status("Parsed time in new zone: ")
				.push(zone.format_with_name(point));
			let table = nunc.load_zone_table()?;
			let off = table.offset_at(point);
			con.info("Which was/will be: ")
				.push(Calendar(off).lookup(point))
				.push(' ')
				.push(off.name());
			point
		},
		None => Point::now()
	};

	let question = format!(
		"Change time zone to {} at {}?",
		zone.name(),
		zone.format_with_name(when)
	);

	match con.confirm(false, &question) {
		true if nunc.change(when, zone)? => con.status("Time zone changed!"),
		true => ret_errmsg!("Failed to change time zone!"),
		false => con.info("Time zone change aborted")
	};

	Ok(())
}