mod client;
mod message;
mod router;
mod session;

//use client::ClientMsg;
//use router::Router;
//use session::{Session, SessionFilter, SessionMsg};
use client::{Client, ClientMsg};
use message::{Message, MsgData};
use router::Router;
use session::{Session, SessionData, SessionMsg};
use std::{
    sync::mpsc::{channel, Sender},
};

/// Support functions for Messages.
pub trait Msg {
    fn to_msgdata(&self) -> MsgData;
}

#[cfg(test)]
mod test_message {
    use super::*;

    pub enum Tester {
        Test1,
        Test2,
    }

    impl Msg for Tester {
        fn to_msgdata(&self) -> MsgData {
            match self {
                Tester::Test1 => MsgData::Test1,
                Tester::Test2 => MsgData::Test2,
            }
        }
    }
}

/// Application client to MoreThanText
#[derive(Clone)]
pub struct MoreThanText {
    session: Option<SessionData>,
    tx: Sender<Message>,
}

impl MoreThanText {
    /// Create a MoreThanText database.
    ///
    ///  Example:
    ///
    ///  ```
    ///  use morethantext::MoreThanText;
    ///
    ///  MoreThanText::new();
    ///  ```
    pub fn new() -> Self {
        let (tx, rx) = channel();
        let mut senders = Vec::new();
        senders.push(Client::start(tx.clone()));
        senders.push(Session::start(tx.clone()));
        Router::start(senders, rx);
        Self {
            session: None,
            tx: tx,
        }
    }

    /// Opens an existing or new session with the database.
    ///
    ///  If the string is None, incorrect, or expired,
    ///  a new session will be created.
    ///
    ///  Example:
    ///
    ///  ```
    ///  use morethantext::MoreThanText;
    ///
    ///  let mut mtt = MoreThanText::new();
    ///  mtt.open_session(None);
    ///  mtt.open_session(Some("7b1ff340-7dfa-4f29-b144-601384e54423".to_string()));
    ///  ```
    pub fn open_session(&mut self, id: Option<String>) {
        let (tx, rx) = channel();
        let req = ClientMsg::OpenSession(id, tx);
        let msg = Message::new(&req);
        self.tx.send(msg).unwrap();
        match rx.recv().unwrap().get_message() {
            MsgData::Session(data) => {
                match data {
                    SessionMsg::Opened(sess) => self.session = Some(sess.clone()),
                    _ => {},
                }
            },
            _ => {},
        };
    }

    /// Get the session id
    ///
    /// Example:
    ///
    /// ```
    ///  use morethantext::MoreThanText;
    ///
    ///  let mut mtt = MoreThanText::new();
    ///  let id = mtt.get_id();
    /// ```
    pub fn get_id(&self) -> String {
        match &self.session {
            Some(id) => id.to_string(),
            None => "".to_string(),
        }
    }
}

#[cfg(test)]
mod mtt_client {
    use super::*;

    #[test]
    fn default_values() {
        let mtt = MoreThanText::new();
        assert!(mtt.session.is_none());
    }

    #[test]
    fn new_session() {
        let mut mtt = MoreThanText::new();
        mtt.open_session(None);
        assert!(mtt.session.is_some());
    }

    #[test]
    fn session_ids_are_unique() {
        let mut mtt = MoreThanText::new();
        mtt.open_session(None);
        let id1 = mtt.get_id();
        mtt.open_session(None);
        assert_ne!(mtt.get_id(), id1);
    }
}