pub mod constants;
use std::mem::size_of;
use constants::*;
use data_model::Le16;
use data_model::SLe32;
use zerocopy::FromBytes;
use zerocopy::Immutable;
use zerocopy::IntoBytes;
use zerocopy::KnownLayout;
pub trait InputEventDecoder {
    const SIZE: usize;
    fn decode(data: &[u8]) -> virtio_input_event;
}
#[derive(
    Copy, Clone, Debug, Default, Eq, PartialEq, FromBytes, Immutable, IntoBytes, KnownLayout,
)]
#[repr(C)]
pub struct input_event {
    pub timestamp_fields: [u64; 2],
    pub type_: u16,
    pub code: u16,
    pub value: i32,
}
impl input_event {
    pub fn from_virtio_input_event(other: &virtio_input_event) -> input_event {
        input_event {
            timestamp_fields: [0, 0],
            type_: other.type_.into(),
            code: other.code.into(),
            value: other.value.into(),
        }
    }
}
impl InputEventDecoder for input_event {
    const SIZE: usize = size_of::<Self>();
    fn decode(data: &[u8]) -> virtio_input_event {
        let e = input_event::read_from_bytes(data).unwrap();
        virtio_input_event {
            type_: Le16::from(e.type_),
            code: Le16::from(e.code),
            value: SLe32::from(e.value),
        }
    }
}
#[derive(
    Copy, Clone, Debug, Default, Eq, PartialEq, FromBytes, Immutable, IntoBytes, KnownLayout,
)]
#[repr(C)]
pub struct virtio_input_event {
    pub type_: Le16,
    pub code: Le16,
    pub value: SLe32,
}
impl InputEventDecoder for virtio_input_event {
    const SIZE: usize = size_of::<Self>();
    fn decode(data: &[u8]) -> virtio_input_event {
        virtio_input_event::read_from_bytes(data).unwrap()
    }
}
impl virtio_input_event {
    #[inline]
    pub fn syn() -> virtio_input_event {
        virtio_input_event {
            type_: Le16::from(EV_SYN),
            code: Le16::from(SYN_REPORT),
            value: SLe32::from(0),
        }
    }
    #[inline]
    pub fn absolute(code: u16, value: i32) -> virtio_input_event {
        virtio_input_event {
            type_: Le16::from(EV_ABS),
            code: Le16::from(code),
            value: SLe32::from(value),
        }
    }
    #[inline]
    pub fn relative(code: u16, value: i32) -> virtio_input_event {
        virtio_input_event {
            type_: Le16::from(EV_REL),
            code: Le16::from(code),
            value: SLe32::from(value),
        }
    }
    #[inline]
    pub fn multitouch_tracking_id(id: i32) -> virtio_input_event {
        Self::absolute(ABS_MT_TRACKING_ID, id)
    }
    #[inline]
    pub fn multitouch_slot(slot: i32) -> virtio_input_event {
        Self::absolute(ABS_MT_SLOT, slot)
    }
    #[inline]
    pub fn multitouch_absolute_x(x: i32) -> virtio_input_event {
        Self::absolute(ABS_MT_POSITION_X, x)
    }
    #[inline]
    pub fn multitouch_absolute_y(y: i32) -> virtio_input_event {
        Self::absolute(ABS_MT_POSITION_Y, y)
    }
    #[inline]
    pub fn absolute_x(x: i32) -> virtio_input_event {
        Self::absolute(ABS_X, x)
    }
    #[inline]
    pub fn absolute_y(y: i32) -> virtio_input_event {
        Self::absolute(ABS_Y, y)
    }
    #[inline]
    pub fn relative_x(x: i32) -> virtio_input_event {
        Self::relative(REL_X, x)
    }
    #[inline]
    pub fn relative_y(y: i32) -> virtio_input_event {
        Self::relative(REL_Y, y)
    }
    #[inline]
    pub fn touch(has_contact: bool) -> virtio_input_event {
        Self::key(BTN_TOUCH, has_contact, false)
    }
    #[inline]
    pub fn left_click(has_contact: bool) -> virtio_input_event {
        Self::key(BTN_LEFT, has_contact, false)
    }
    #[inline]
    pub fn wheel(delta: i32) -> virtio_input_event {
        Self::relative(REL_WHEEL, delta)
    }
    #[inline]
    pub fn right_click(has_contact: bool) -> virtio_input_event {
        Self::key(BTN_RIGHT, has_contact, false)
    }
    #[inline]
    pub fn middle_click(has_contact: bool) -> virtio_input_event {
        Self::key(BTN_MIDDLE, has_contact, false)
    }
    #[inline]
    pub fn forward_click(has_contact: bool) -> virtio_input_event {
        Self::key(BTN_FORWARD, has_contact, false)
    }
    #[inline]
    pub fn back_click(has_contact: bool) -> virtio_input_event {
        Self::key(BTN_BACK, has_contact, false)
    }
    #[inline]
    pub fn finger_tool(active: bool) -> virtio_input_event {
        Self::key(BTN_TOOL_FINGER, active, false)
    }
    #[inline]
    pub fn key(code: u16, down: bool, repeat: bool) -> virtio_input_event {
        virtio_input_event {
            type_: Le16::from(EV_KEY),
            code: Le16::from(code),
            value: SLe32::from(match (down, repeat) {
                (true, true) => 2,
                (true, false) => 1,
                _ => 0,
            }),
        }
    }
    pub fn get_led_state(&self, led_code: u16) -> Option<bool> {
        if self.type_ == EV_LED && self.code == led_code {
            return match self.value.to_native() {
                0 => Some(false),
                1 => Some(true),
                _ => None,
            };
        }
        None
    }
}