use std::borrow::Cow;
use std::cmp::Ordering;
use chrono::naive::time::NaiveTime;
use chrono::offset::fixed::FixedOffset;
use chrono::offset::local::Local;
use chrono::offset::TimeZone;
pub struct Log<'a> {
pub entries: Vec<Event<'a>>,
}
#[derive(Clone, Debug, PartialEq, Eq, Ord, Hash, RustcEncodable, RustcDecodable)]
pub enum Time {
Unknown,
Hms(u8, u8, u8),
Timestamp(i64),
}
impl Time {
pub fn from_format(tz: &FixedOffset, s: &str, f: &str) -> Time {
tz.datetime_from_str(s, f)
.map(|d| d.timestamp())
.map(Time::Timestamp)
.unwrap_or(Time::Unknown)
}
pub fn with_format(&self, tz: &FixedOffset, f: &str) -> String {
match self {
&Time::Unknown => panic!("Time data for this event is not present"),
&Time::Hms(h, m, s) => {
format!("{}",
NaiveTime::from_hms(h as u32, m as u32, s as u32).format(f))
}
&Time::Timestamp(t) => format!("{}", tz.timestamp(t, 0).format(f)),
}
}
pub fn as_timestamp(&self) -> i64 {
use self::Time::*;
match self {
&Unknown => 0,
&Hms(h, m, s) => {
Local::today()
.and_hms(h as u32, m as u32, s as u32)
.timestamp()
}
&Timestamp(i) => i,
}
}
pub fn to_timestamp(&self) -> Time {
Time::Timestamp(self.as_timestamp())
}
}
impl PartialOrd for Time {
fn partial_cmp(&self, other: &Time) -> Option<Ordering> {
use self::Time::*;
match (self, other) {
(&Unknown, _) | (_, &Unknown) => None,
(&Hms(a_h, a_m, a_s), &Hms(b_h, b_m, b_s)) => {
if (a_h >= b_h && a_m >= b_m && a_s > b_s) ||
(a_h >= b_h && a_m > b_m && a_s >= b_s) ||
(a_h > b_h && a_m >= b_m && a_s >= b_s) {
Some(Ordering::Greater)
} else {
Some(Ordering::Less)
}
}
(&Timestamp(a), &Timestamp(b)) => Some(a.cmp(&b)),
_ => unimplemented!(),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct Event<'a> {
pub ty: Type<'a>,
pub time: Time,
pub channel: Option<Cow<'a, str>>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct User<'a> {
nicks: Cow<'a, str>,
}
#[derive(Clone, Debug, Hash, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub enum Type<'a> {
Connect,
Disconnect,
Msg {
from: Cow<'a, str>,
content: Cow<'a, str>,
},
Action {
from: Cow<'a, str>,
content: Cow<'a, str>,
},
Join {
nick: Cow<'a, str>,
mask: Option<Cow<'a, str>>,
},
Part {
nick: Cow<'a, str>,
mask: Option<Cow<'a, str>>,
reason: Option<Cow<'a, str>>,
},
Quit {
nick: Cow<'a, str>,
mask: Option<Cow<'a, str>>,
reason: Option<Cow<'a, str>>,
},
Nick {
old_nick: Cow<'a, str>,
new_nick: Cow<'a, str>,
},
Notice {
from: Cow<'a, str>,
content: Cow<'a, str>,
},
Kick {
kicked_nick: Cow<'a, str>,
kicking_nick: Option<Cow<'a, str>>,
kick_message: Option<Cow<'a, str>>,
},
Topic {
topic: Cow<'a, str>,
},
TopicChange {
nick: Option<Cow<'a, str>>,
new_topic: Cow<'a, str>,
},
Mode {
nick: Option<Cow<'a, str>>,
mode: Cow<'a, str>,
masks: Cow<'a, str>,
},
}
impl<'a> Type<'a> {
pub fn involves(&self, needle: &str) -> bool {
use self::Type::*;
match self {
&Msg { ref from, .. } => from == needle,
&Action { ref from, .. } => from == needle,
&Join { ref nick, .. } => nick == needle,
&Part { ref nick, .. } => nick == needle,
&Quit { ref nick, .. } => nick == needle,
&Nick { ref old_nick, ref new_nick, .. } => old_nick == needle || new_nick == needle,
&Notice { ref from, .. } => from == needle,
&Kick { ref kicked_nick, ref kicking_nick, .. } => {
*kicked_nick == Cow::Borrowed(needle) ||
kicking_nick.as_ref().map_or(false, |k| k.as_ref() == Cow::Borrowed(needle))
}
&TopicChange { ref nick, .. } => nick.as_ref().map_or(false, |k| k.as_ref() == needle),
&Mode { ref nick, .. } => {
nick.as_ref().map_or(false, |k| k.as_ref() == Cow::Borrowed(needle))
}
_ => false,
}
}
}