use std::collections::VecDeque;
use std::fmt;
use std::io;
use std::io::Read;
use std::io::Write;
use std::iter::ExactSizeIterator;
use base::AsRawDescriptor;
use base::RawDescriptor;
use base::ReadNotifier;
use base::StreamChannel;
use linux_input_sys::virtio_input_event;
use linux_input_sys::InputEventDecoder;
use serde::Deserialize;
use serde::Serialize;
use zerocopy::FromZeros;
use zerocopy::IntoBytes;
const EVENT_SIZE: usize = virtio_input_event::SIZE;
const EVENT_BUFFER_LEN_MAX: usize = 64 * EVENT_SIZE;
#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum EventDeviceKind {
    Mouse,
    Touchscreen,
    Keyboard,
}
#[derive(Deserialize, Serialize)]
pub struct EventDevice {
    kind: EventDeviceKind,
    event_buffer: VecDeque<u8>,
    event_socket: StreamChannel,
}
impl EventDevice {
    pub fn new(kind: EventDeviceKind, mut event_socket: StreamChannel) -> EventDevice {
        let _ = event_socket.set_nonblocking(true);
        EventDevice {
            kind,
            event_buffer: Default::default(),
            event_socket,
        }
    }
    #[inline]
    pub fn mouse(event_socket: StreamChannel) -> EventDevice {
        Self::new(EventDeviceKind::Mouse, event_socket)
    }
    #[inline]
    pub fn touchscreen(event_socket: StreamChannel) -> EventDevice {
        Self::new(EventDeviceKind::Touchscreen, event_socket)
    }
    #[inline]
    pub fn keyboard(event_socket: StreamChannel) -> EventDevice {
        Self::new(EventDeviceKind::Keyboard, event_socket)
    }
    #[inline]
    pub fn kind(&self) -> EventDeviceKind {
        self.kind
    }
    pub fn flush_buffered_events(&mut self) -> io::Result<bool> {
        while !self.event_buffer.is_empty() {
            let written = self.event_socket.write(self.event_buffer.as_slices().0)?;
            if written == 0 {
                return Ok(false);
            }
            self.event_buffer.drain(..written);
        }
        Ok(true)
    }
    pub fn is_buffered_events_empty(&self) -> bool {
        self.event_buffer.is_empty()
    }
    #[inline]
    fn can_buffer_events(&self, num_events: usize) -> bool {
        let event_bytes = match EVENT_SIZE.checked_mul(num_events) {
            Some(bytes) => bytes,
            None => return false,
        };
        let free_bytes = EVENT_BUFFER_LEN_MAX.saturating_sub(self.event_buffer.len());
        free_bytes >= event_bytes
    }
    pub fn send_report<E: IntoIterator<Item = virtio_input_event>>(
        &mut self,
        events: E,
    ) -> io::Result<bool>
    where
        E::IntoIter: ExactSizeIterator,
    {
        let it = events.into_iter();
        if !self.can_buffer_events(it.len() + 1) {
            return Ok(false);
        }
        for event in it {
            let bytes = event.as_bytes();
            self.event_buffer.extend(bytes.iter());
        }
        self.event_buffer
            .extend(virtio_input_event::syn().as_bytes().iter());
        self.flush_buffered_events()
    }
    pub fn send_event_encoded(&mut self, event: virtio_input_event) -> io::Result<bool> {
        if !self.flush_buffered_events()? {
            return Ok(false);
        }
        let bytes = event.as_bytes();
        let written = self.event_socket.write(bytes)?;
        if written == bytes.len() {
            return Ok(true);
        }
        if self.can_buffer_events(1) {
            self.event_buffer.extend(bytes[written..].iter());
        }
        Ok(false)
    }
    pub fn recv_event_encoded(&self) -> io::Result<virtio_input_event> {
        let mut event = virtio_input_event::new_zeroed();
        (&self.event_socket).read_exact(event.as_mut_bytes())?;
        Ok(event)
    }
}
impl AsRawDescriptor for EventDevice {
    fn as_raw_descriptor(&self) -> RawDescriptor {
        self.event_socket.as_raw_descriptor()
    }
}
impl ReadNotifier for EventDevice {
    fn get_read_notifier(&self) -> &dyn AsRawDescriptor {
        self.event_socket.get_read_notifier()
    }
}
impl fmt::Debug for EventDevice {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Event device ({:?})", self.kind)
    }
}