//! A region object describes an area. region objects are used to describe the
//! opaque and input regions of a surface.

//
//
//              GENERATED BY OUR WAYLAND-SCANNER. DO NOT EDIT!
//
//

#![allow(unused)]
#![allow(clippy::from_over_into)]
#![allow(clippy::match_single_binding)]

use crate::wl::protocols::common::{EventSet, RequestSet};
use crate::wl::{
    Array, Connection, DeserializeError, Handle, Interface, Message, NewId, ObjectId, Opcode,
    Payload, PayloadType, RawMessage, SendError,
};
use alloc::rc::Rc;
use alloc::string::String;
use core::cell::RefCell;
use smallvec::smallvec;

use crate::wl::protocols::common::wl_buffer::WlBuffer;
use crate::wl::protocols::common::wl_callback::WlCallback;
use crate::wl::protocols::common::wl_compositor::WlCompositor;
use crate::wl::protocols::common::wl_data_device::WlDataDevice;
use crate::wl::protocols::common::wl_data_device_manager::WlDataDeviceManager;
use crate::wl::protocols::common::wl_data_offer::WlDataOffer;
use crate::wl::protocols::common::wl_data_source::WlDataSource;
use crate::wl::protocols::common::wl_display::WlDisplay;
use crate::wl::protocols::common::wl_keyboard::WlKeyboard;
use crate::wl::protocols::common::wl_output::WlOutput;
use crate::wl::protocols::common::wl_pointer::WlPointer;

use crate::wl::protocols::common::wl_registry::WlRegistry;
use crate::wl::protocols::common::wl_seat::WlSeat;
use crate::wl::protocols::common::wl_shell::WlShell;
use crate::wl::protocols::common::wl_shell_surface::WlShellSurface;
use crate::wl::protocols::common::wl_shm::WlShm;
use crate::wl::protocols::common::wl_shm_pool::WlShmPool;
use crate::wl::protocols::common::wl_subcompositor::WlSubcompositor;
use crate::wl::protocols::common::wl_subsurface::WlSubsurface;
use crate::wl::protocols::common::wl_surface::WlSurface;
use crate::wl::protocols::common::wl_touch::WlTouch;
use crate::wl::protocols::common::xdg_popup::XdgPopup;
use crate::wl::protocols::common::xdg_positioner::XdgPositioner;
use crate::wl::protocols::common::xdg_surface::XdgSurface;
use crate::wl::protocols::common::xdg_toplevel::XdgToplevel;
use crate::wl::protocols::common::xdg_wm_base::XdgWmBase;

macro_rules! from_optional_object_payload {
    ($ty:ident, $con:expr, $v:expr) => {
        match ($v).clone() {
            Payload::ObjectId(id) if id.is_null() => None,
            Payload::ObjectId(id) => Some($ty::new($con, id)),
            _ => return Err(DeserializeError::UnexpectedType), // Abort deserializing.
        }
    };
}

macro_rules! from_object_payload {
    ($ty:ident, $con:expr, $v:expr) => {
        match ($v).clone() {
            Payload::ObjectId(id) if id.is_null() => return Err(DeserializeError::ObjectIsNull),
            Payload::ObjectId(id) => $ty::new($con, id),
            _ => return Err(DeserializeError::UnexpectedType),
        }
    };
}

macro_rules! from_payload {
    ($ty:ident, $v:expr) => {
        match ($v).clone() {
            Payload::$ty(value) => value.into(),
            _ => return Err(DeserializeError::UnexpectedType),
        }
    };
}

#[derive(Debug)]
pub enum Request {
    /// Destroy the region. this will invalidate the object id.
    Destroy {},
    /// Add the specified rectangle to the region.
    Add {
        /// Region-local x coordinate.
        x: i32,
        /// Region-local y coordinate.
        y: i32,
        /// Rectangle width.
        width: i32,
        /// Rectangle height.
        height: i32,
    },
    /// Subtract the specified rectangle from the region.
    Subtract {
        /// Region-local x coordinate.
        x: i32,
        /// Region-local y coordinate.
        y: i32,
        /// Rectangle width.
        width: i32,
        /// Rectangle height.
        height: i32,
    },
}

impl Message for Request {
    fn into_raw(self, sender: ObjectId) -> RawMessage {
        match self {
            Request::Destroy {} => RawMessage {
                sender,
                opcode: Opcode(1),
                args: smallvec![],
            },
            Request::Add {
                x,
                y,
                width,
                height,
            } => RawMessage {
                sender,
                opcode: Opcode(2),
                args: smallvec![x.into(), y.into(), width.into(), height.into()],
            },
            Request::Subtract {
                x,
                y,
                width,
                height,
            } => RawMessage {
                sender,
                opcode: Opcode(3),
                args: smallvec![x.into(), y.into(), width.into(), height.into()],
            },
        }
    }

    fn from_raw(
        con: Rc<RefCell<dyn Connection>>,
        m: &RawMessage,
    ) -> Result<Request, DeserializeError> {
        match m.opcode {
            Opcode(1) => Ok(Request::Destroy {}),
            Opcode(2) => Ok(Request::Add {
                x: from_payload!(Int, m.args[0]),

                y: from_payload!(Int, m.args[1]),

                width: from_payload!(Int, m.args[2]),

                height: from_payload!(Int, m.args[3]),
            }),
            Opcode(3) => Ok(Request::Subtract {
                x: from_payload!(Int, m.args[0]),

                y: from_payload!(Int, m.args[1]),

                width: from_payload!(Int, m.args[2]),

                height: from_payload!(Int, m.args[3]),
            }),

            _ => Err(DeserializeError::UnknownOpcode),
        }
    }

    fn into_received_event(self, con: Rc<RefCell<dyn Connection>>, id: ObjectId) -> EventSet {
        panic!("not a event!");
    }

    fn into_received_request(self) -> RequestSet {
        RequestSet::WlRegion(self)
    }
}

#[derive(Debug)]
pub enum Event {}

impl Message for Event {
    fn into_raw(self, sender: ObjectId) -> RawMessage {
        match self {}
    }

    fn from_raw(
        con: Rc<RefCell<dyn Connection>>,
        m: &RawMessage,
    ) -> Result<Event, DeserializeError> {
        match m.opcode {
            _ => Err(DeserializeError::UnknownOpcode),
        }
    }

    fn into_received_event(self, con: Rc<RefCell<dyn Connection>>, id: ObjectId) -> EventSet {
        EventSet::WlRegion(WlRegion::new(con, id), self)
    }

    fn into_received_request(self) -> RequestSet {
        panic!("not a request!");
    }
}

/// Region interface.
#[derive(Clone)]
pub struct WlRegion {
    con: Rc<RefCell<dyn Connection>>,
    object_id: ObjectId,
}

impl PartialEq for WlRegion {
    fn eq(&self, other: &Self) -> bool {
        self.id() == other.id()
    }
}

impl core::fmt::Debug for WlRegion {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        write!(f, "WlRegion@{}", self.object_id.0)
    }
}

impl Into<Payload> for WlRegion {
    fn into(self) -> Payload {
        Payload::ObjectId(self.id())
    }
}

impl Interface for WlRegion {
    type Event = Event;
    type Request = Request;
    const NAME: &'static str = "wl_region";
    const VERSION: u32 = 1;
    const PAYLOAD_TYPES: &'static [&'static [PayloadType]] = &[
        &[],
        &[
            PayloadType::Int,
            PayloadType::Int,
            PayloadType::Int,
            PayloadType::Int,
        ],
        &[
            PayloadType::Int,
            PayloadType::Int,
            PayloadType::Int,
            PayloadType::Int,
        ],
    ];

    fn new(con: Rc<RefCell<dyn Connection>>, object_id: ObjectId) -> WlRegion {
        WlRegion { con, object_id }
    }

    fn connection(&self) -> &Rc<RefCell<dyn Connection>> {
        &self.con
    }

    fn id(&self) -> ObjectId {
        self.object_id
    }

    fn as_new_id(&self) -> NewId {
        NewId(self.object_id.0)
    }
}
