
use crate::master::core::EtherCATMaster;
use std::sync::mpsc::{channel, sync_channel, Receiver, TryRecvError};
use std::sync::Mutex;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SlaveStateChangeEvent {

    pub master: u16,

    pub slave: u16,

    pub old_state: i32,

    pub new_state: i32,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EmergencyEvent {
    pub master: u16,
    pub slave: u16,
    pub error_code: u16,
    pub error_register: u16,
    pub b1: u8,
    pub w1: u16,
    pub w2: u16,
}

pub struct MasterStateStream {
    rx: Receiver<SlaveStateChangeEvent>,
}

impl MasterStateStream {

    pub fn recv(&self) -> Result<SlaveStateChangeEvent, std::sync::mpsc::RecvError> {
        self.rx.recv()
    }

    pub fn try_recv(&self) -> Result<SlaveStateChangeEvent, TryRecvError> {
        self.rx.try_recv()
    }

    pub fn into_inner(self) -> Receiver<SlaveStateChangeEvent> {
        self.rx
    }
}

impl IntoIterator for MasterStateStream {
    type Item = SlaveStateChangeEvent;
    type IntoIter = std::sync::mpsc::IntoIter<SlaveStateChangeEvent>;

    fn into_iter(self) -> Self::IntoIter {
        self.rx.into_iter()
    }
}

pub struct EmergencyStream {
    rx: Receiver<EmergencyEvent>,
}

impl EmergencyStream {
    pub fn recv(&self) -> Result<EmergencyEvent, std::sync::mpsc::RecvError> {
        self.rx.recv()
    }
    pub fn try_recv(&self) -> Result<EmergencyEvent, TryRecvError> {
        self.rx.try_recv()
    }
    pub fn into_inner(self) -> Receiver<EmergencyEvent> {
        self.rx
    }
}

impl IntoIterator for EmergencyStream {
    type Item = EmergencyEvent;
    type IntoIter = std::sync::mpsc::IntoIter<EmergencyEvent>;

    fn into_iter(self) -> Self::IntoIter {
        self.rx.into_iter()
    }
}

pub trait MasterStreamExt {

    fn state_stream(&self) -> MasterStateStream;

    fn state_stream_with_capacity(&self, cap: usize) -> MasterStateStream;

    fn emergency_stream(&self) -> EmergencyStream;
}

impl MasterStreamExt for EtherCATMaster {
    fn state_stream(&self) -> MasterStateStream {
        self.state_stream_with_capacity(1024)
    }

    fn state_stream_with_capacity(&self, cap: usize) -> MasterStateStream {
        let (tx, rx) = sync_channel::<SlaveStateChangeEvent>(cap);
        let tx = Mutex::new(tx);

        self.events().on_slave_state_changed_async(move |master, slave, old_state, new_state| {
            let ev = SlaveStateChangeEvent { master, slave, old_state, new_state };

            if let Ok(guard) = tx.lock() {
                let _ = guard.try_send(ev);
            }
        });
        MasterStateStream { rx }
    }

    fn emergency_stream(&self) -> EmergencyStream {

        let (tx, rx) = channel::<EmergencyEvent>();
        let tx = Mutex::new(tx);
        self.events().on_emergency(move |master, slave, error_code, error_register, b1, w1, w2| {
            let ev = EmergencyEvent {
                master, slave, error_code, error_register, b1, w1, w2,
            };
            if let Ok(guard) = tx.lock() {
                let _ = guard.send(ev);
            }
        });
        EmergencyStream { rx }
    }
}
