use clap::ArgMatches;
use chrono::NaiveDateTime;
use chrono::Local;
use chrono::Timelike;
use failure::Error;
use failure::ResultExt;
use failure::err_msg;
use failure::Fallible as Result;
use option_inspect::*;
use libimagdiary::diary::Diary;
use libimagentryedit::edit::Edit;
use libimagrt::runtime::Runtime;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use crate::util::get_diary_name;
use crate::util::get_diary_timed_config;
use crate::util::Timed;
pub fn create(rt: &Runtime) -> Result<()> {
let diaryname = get_diary_name(rt)
.ok_or_else(|| err_msg("No diary selected. Use either the configuration file or the commandline option"))?;
let mut entry = create_entry(rt.store(), &diaryname, rt)?;
rt.report_touched(entry.get_location())?;
if rt.cli().subcommand_matches("create").unwrap().is_present("no-edit") {
debug!("Not editing new diary entry");
info!("Ok!");
Ok(())
} else {
debug!("Editing new diary entry");
entry.edit_content(rt).context(err_msg("Diary edit error")).map_err(Error::from)
}
}
fn create_entry<'a>(diary: &'a Store, diaryname: &str, rt: &Runtime) -> Result<FileLockEntry<'a>> {
use crate::util::parse_timed_string;
let create = rt.cli().subcommand_matches("create").unwrap();
let timed = match create.value_of("timed").map(|t| parse_timed_string(t, diaryname)) {
Some(t) => t.map(Some),
None => get_diary_timed_config(rt, diaryname)
}?;
if let Some(timed) = timed {
let time = create_id_from_clispec(&create, timed)?;
diary.new_entry_at(&diaryname, &time)
.context(err_msg("Store write error"))
.map_err(Error::from)
} else {
debug!("Creating non-timed entry");
diary.new_entry_today(diaryname)
}
}
fn create_id_from_clispec(create: &ArgMatches, timed_type: Timed) -> Result<NaiveDateTime> {
use std::str::FromStr;
let dt = Local::now();
let ndt = dt.naive_local();
match timed_type {
Timed::Daily => {
debug!("Creating daily-timed entry");
Ok(ndt.with_hour(0)
.unwrap() .with_minute(0)
.unwrap() .with_second(0)
.unwrap()) },
Timed::Hourly => {
debug!("Creating hourly-timed entry");
Ok(ndt.with_minute(0)
.unwrap() .with_second(0)
.unwrap()) },
Timed::Minutely => {
let min = create
.value_of("minute")
.inspect(|m| debug!("minute = {:?}", m))
.map(|s| {
FromStr::from_str(s)
.map_err(Error::from)
.context(format_err!("Could not parse minute: '{}'", s))
.map_err(Error::from)
})
.transpose()?
.unwrap_or_else(|| ndt.minute());
ndt.with_minute(min)
.ok_or_else(|| {
format_err!("Cannot set {} as minute, would yield invalid time!", min)
})
.map(|ndt| ndt.with_second(0).unwrap()) },
Timed::Secondly => {
let min = create
.value_of("minute")
.inspect(|m| debug!("minute = {:?}", m))
.map(|s| {
FromStr::from_str(s)
.map_err(Error::from)
.context(format_err!("Could not parse minute: '{}'", s))
.map_err(Error::from)
})
.transpose()?
.unwrap_or_else(|| ndt.minute());
let sec = create
.value_of("second")
.inspect(|s| debug!("second = {:?}", s))
.map(|s| {
FromStr::from_str(s)
.map_err(Error::from)
.context(format_err!("Could not parse second: '{}'", s))
.map_err(Error::from)
})
.transpose()?
.unwrap_or_else(|| ndt.second());
ndt.with_minute(min)
.ok_or_else(|| {
format_err!("Cannot set {} as minute, would yield invalid time!", min)
})?
.with_second(sec)
.ok_or_else(|| {
format_err!("Cannot set {} as second, would yield invalid time!", sec)
})
},
}
}