diff options
Diffstat (limited to 'lib/domain/libimagdiary/src/diaryid.rs')
-rw-r--r-- | lib/domain/libimagdiary/src/diaryid.rs | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/lib/domain/libimagdiary/src/diaryid.rs b/lib/domain/libimagdiary/src/diaryid.rs new file mode 100644 index 00000000..da1afc42 --- /dev/null +++ b/lib/domain/libimagdiary/src/diaryid.rs @@ -0,0 +1,257 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; version +// 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// + +use std::convert::Into; +use std::fmt::{Display, Formatter, Error as FmtError}; + +use chrono::naive::NaiveDateTime; +use chrono::naive::NaiveTime; +use chrono::naive::NaiveDate; +use chrono::Datelike; +use chrono::Timelike; + +use libimagstore::storeid::StoreId; +use libimagstore::storeid::IntoStoreId; +use libimagstore::store::Result as StoreResult; + +use error::DiaryError as DE; +use error::DiaryErrorKind as DEK; +use error::MapErrInto; +use libimagerror::into::IntoError; + +use module_path::ModuleEntryPath; + +#[derive(Debug, Clone)] +pub struct DiaryId { + name: String, + year: i32, + month: u32, + day: u32, + hour: u32, + minute: u32, +} + +impl DiaryId { + + pub fn new(name: String, y: i32, m: u32, d: u32, h: u32, min: u32) -> DiaryId { + DiaryId { + name: name, + year: y, + month: m, + day: d, + hour: h, + minute: min, + } + } + + pub fn from_datetime<DT: Datelike + Timelike>(diary_name: String, dt: DT) -> DiaryId { + DiaryId::new(diary_name, dt.year(), dt.month(), dt.day(), dt.hour(), dt.minute()) + } + + pub fn diary_name(&self) -> &String { + &self.name + } + + pub fn year(&self) -> i32 { + self.year + } + + pub fn month(&self) -> u32 { + self.month + } + + pub fn day(&self) -> u32 { + self.day + } + + pub fn hour(&self) -> u32 { + self.hour + } + + pub fn minute(&self) -> u32 { + self.minute + } + + pub fn with_diary_name(mut self, name: String) -> DiaryId { + self.name = name; + self + } + + pub fn with_year(mut self, year: i32) -> DiaryId { + self.year = year; + self + } + + pub fn with_month(mut self, month: u32) -> DiaryId { + self.month = month; + self + } + + pub fn with_day(mut self, day: u32) -> DiaryId { + self.day = day; + self + } + + pub fn with_hour(mut self, hour: u32) -> DiaryId { + self.hour = hour; + self + } + + pub fn with_minute(mut self, minute: u32) -> DiaryId { + self.minute = minute; + self + } + + pub fn now(name: String) -> DiaryId { + use chrono::offset::Local; + + let now = Local::now(); + let now_date = now.date().naive_local(); + let now_time = now.time(); + let dt = NaiveDateTime::new(now_date, now_time); + + DiaryId::new(name, dt.year(), dt.month(), dt.day(), dt.hour(), dt.minute()) + } + +} + +impl Default for DiaryId { + + /// Create a default DiaryId which is a diaryid for a diary named "default" with + /// time = 0000-00-00 00:00:00 + fn default() -> DiaryId { + let dt = NaiveDateTime::new(NaiveDate::from_ymd(0, 0, 0), NaiveTime::from_hms(0, 0, 0)); + DiaryId::from_datetime(String::from("default"), dt) + } +} + +impl IntoStoreId for DiaryId { + + fn into_storeid(self) -> StoreResult<StoreId> { + let s : String = self.into(); + ModuleEntryPath::new(s).into_storeid() + } + +} + +impl Into<String> for DiaryId { + + fn into(self) -> String { + format!("{}/{:0>4}/{:0>2}/{:0>2}/{:0>2}:{:0>2}", + self.name, self.year, self.month, self.day, self.hour, self.minute) + } + +} + +impl Display for DiaryId { + + fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> { + write!(fmt, "{}/{:0>4}/{:0>2}/{:0>2}/{:0>2}:{:0>2}", + self.name, self.year, self.month, self.day, self.hour, self.minute) + } + +} + +impl Into<NaiveDateTime> for DiaryId { + + fn into(self) -> NaiveDateTime { + let d = NaiveDate::from_ymd(self.year, self.month, self.day); + let t = NaiveTime::from_hms(self.hour, self.minute, 0); + NaiveDateTime::new(d, t) + } + +} + +pub trait FromStoreId : Sized { + + fn from_storeid(&StoreId) -> Result<Self, DE>; + +} + +use std::path::Component; + +fn component_to_str<'a>(com: Component<'a>) -> Result<&'a str, DE> { + match com { + Component::Normal(s) => Some(s), + _ => None, + }.and_then(|s| s.to_str()) + .ok_or(DEK::IdParseError.into_error()) +} + +impl FromStoreId for DiaryId { + + fn from_storeid(s: &StoreId) -> Result<DiaryId, DE> { + use std::str::FromStr; + + use std::path::Components; + use std::iter::Rev; + + fn next_component<'a>(components: &'a mut Rev<Components>) -> Result<&'a str, DE> { + components.next() + .ok_or(DEK::IdParseError.into_error()) + .and_then(component_to_str) + } + + let mut cmps = s.components().rev(); + + let (hour, minute) = try!(next_component(&mut cmps).and_then(|time| { + let mut time = time.split(":"); + let hour = time.next().and_then(|s| FromStr::from_str(s).ok()); + let minute = time.next() + .and_then(|s| s.split("~").next()) + .and_then(|s| FromStr::from_str(s).ok()); + + debug!("Hour = {:?}", hour); + debug!("Minute = {:?}", minute); + + match (hour, minute) { + (Some(h), Some(m)) => Ok((h, m)), + _ => return Err(DE::new(DEK::IdParseError, None)), + } + })); + + let day: Result<u32,_> = next_component(&mut cmps) + .and_then(|s| s.parse::<u32>() + .map_err_into(DEK::IdParseError)); + + let month: Result<u32,_> = next_component(&mut cmps) + .and_then(|s| s.parse::<u32>() + .map_err_into(DEK::IdParseError)); + + let year: Result<i32,_> = next_component(&mut cmps) + .and_then(|s| s.parse::<i32>() + .map_err_into(DEK::IdParseError)); + + let name = next_component(&mut cmps).map(String::from); + + debug!("Day = {:?}", day); + debug!("Month = {:?}", month); + debug!("Year = {:?}", year); + debug!("Name = {:?}", name); + + let day = try!(day); + let month = try!(month); + let year = try!(year); + let name = try!(name); + + Ok(DiaryId::new(name, year, month, day, hour, minute)) + } + +} + |