use std::str::FromStr;
use serialize::json::Json;
use super::error::{ParseEventTypeError, InvalidJsonError};
use std::ops::Index;
use std::ascii::AsciiExt;
#[derive(Debug, Clone, PartialEq)]
pub enum EventType {
Action,
ActionMe,
Command(String),
Connect,
Ctcp,
CtcpMe,
CtcpReply,
Disconnect,
Invite,
Join,
Kick,
Mode,
Names,
Nick,
Notice,
Numeric,
Part,
Pong,
PrivMsg,
PrivMsgMe,
Quit,
Topic,
Unknown,
Whois,
}
impl ToString for EventType {
fn to_string(&self) -> String {
match *self {
EventType::Command(ref s) => format!("COMMAND_{}", s),
EventType::Action => "ACTION".to_string(),
EventType::ActionMe => "ACTION_ME".to_string(),
EventType::Connect => "CONNECT".to_string(),
EventType::Ctcp => "CTCP".to_string(),
EventType::CtcpMe => "CTCP_ME".to_string(),
EventType::CtcpReply => "CTCP_REP".to_string(),
EventType::Disconnect => "DISCONNECT".to_string(),
EventType::Invite => "INVITE".to_string(),
EventType::Join => "JOIN".to_string(),
EventType::Kick => "KICK".to_string(),
EventType::Mode => "MODE".to_string(),
EventType::Names => "NAMES".to_string(),
EventType::Nick => "NICK".to_string(),
EventType::Notice => "NOTICE".to_string(),
EventType::Numeric => "NUMERIC".to_string(),
EventType::Part => "PART".to_string(),
EventType::Pong => "PONG".to_string(),
EventType::PrivMsg => "PRIVMSG".to_string(),
EventType::PrivMsgMe => "PRIVMSG_ME".to_string(),
EventType::Quit => "QUIT".to_string(),
EventType::Topic => "TOPIC".to_string(),
EventType::Unknown => "UNKNOWN".to_string(),
EventType::Whois => "WHOIS".to_string(),
}
}
}
impl FromStr for EventType {
type Err = ParseEventTypeError;
fn from_str(s: &str) -> Result<Self, ParseEventTypeError> {
match &s.to_ascii_uppercase()[..] {
"ACTION" => Ok(EventType::Action),
"ACTION_ME" => Ok(EventType::ActionMe),
"CONNECT" => Ok(EventType::Connect),
"CTCP" => Ok(EventType::Ctcp),
"CTCP_ME" => Ok(EventType::CtcpMe),
"CTCP_REP" => Ok(EventType::CtcpReply),
"DISCONNECT" => Ok(EventType::Disconnect),
"INVITE" => Ok(EventType::Invite),
"JOIN" => Ok(EventType::Join),
"KICK" => Ok(EventType::Kick),
"MODE" => Ok(EventType::Mode),
"NAMES" => Ok(EventType::Names),
"NICK" => Ok(EventType::Nick),
"NOTICE" => Ok(EventType::Notice),
"NUMERIC" => Ok(EventType::Numeric),
"PART" => Ok(EventType::Part),
"PONG" => Ok(EventType::Pong),
"PRIVMSG" => Ok(EventType::PrivMsg),
"PRIVMSG_ME" => Ok(EventType::PrivMsgMe),
"QUIT" => Ok(EventType::Quit),
"TOPIC" => Ok(EventType::Topic),
"UNKNOWN" => Ok(EventType::Unknown),
"WHOIS" => Ok(EventType::Whois),
other if other.len() > 8 => {
match &other[..7] {
"COMMAND" => Ok(EventType::Command(other[8..].to_string())),
_ => Err(ParseEventTypeError::new())
}
},
_ => Err(ParseEventTypeError::new())
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Event {
pub event: EventType,
pub params: Vec<String>,
}
pub fn is_event_json(data: &Json) -> bool {
data.is_object() && data.as_object().unwrap().contains_key("event")
}
impl Event {
pub fn new(event: EventType, params: Vec<String>) -> Event {
Event { event: event, params: params }
}
pub fn from_json(data: &Json) -> Result<Event, InvalidJsonError> {
if data.is_object() {
let obj = data.as_object().unwrap();
if obj.contains_key("event") && obj.contains_key("params") {
let evt = obj.get("event").unwrap();
let params = obj.get("params").unwrap();
if evt.is_string() && params.is_array() {
Event::create_event(&evt.as_string().unwrap(), ¶ms.as_array().unwrap())
} else {
Err(InvalidJsonError::new(""))
}
} else {
Err(InvalidJsonError::new(""))
}
} else {
Err(InvalidJsonError::new(""))
}
}
fn create_event(evt: &str, params: &Vec<Json>) -> Result<Event, InvalidJsonError> {
if evt == "COMMAND" {
if params.len() >= 4 && params[3].is_string() {
let cmd = params[3].as_string().unwrap().to_string();
Ok(Event::new(EventType::Command(cmd), Event::param_strs(params)))
} else {
Err(InvalidJsonError::new(""))
}
} else {
match EventType::from_str(evt) {
Ok(evt) => Ok(Event::new(evt, Event::param_strs(params))),
Err(_) => Err(InvalidJsonError::new(""))
}
}
}
fn param_strs(params: &Vec<Json>) -> Vec<String> {
let mut strs = Vec::new();
for param in params {
if param.is_string() {
strs.push(param.as_string().unwrap().to_string());
}
}
strs
}
pub fn param<'a>(&'a self, idx: usize) -> &'a str {
&self.params[idx][..]
}
pub fn len(&self) -> usize {
self.params.len()
}
}
impl<'b> Index<usize> for Event {
type Output = str;
fn index<'a>(&'a self, index: usize) -> &'a str {
self.param(index)
}
}