pub const ext = @import("ext.zig");
const manette = @This();

const std = @import("std");
const compat = @import("compat");
const gio = @import("gio2");
const gobject = @import("gobject2");
const glib = @import("glib2");
const gmodule = @import("gmodule2");
const gudev = @import("gudev1");
/// An object representing a physical gamepad.
///
/// See also: `Monitor`.
pub const Device = opaque {
    pub const Parent = gobject.Object;
    pub const Implements = [_]type{};
    pub const Class = manette.DeviceClass;
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {
        /// Emitted when an absolute axis' value changes.
        pub const absolute_axis_event = struct {
            pub const name = "absolute-axis-event";

            pub fn connect(p_instance: anytype, comptime P_Data: type, p_callback: *const fn (@TypeOf(p_instance), p_event: *manette.Event, P_Data) callconv(.c) void, p_data: P_Data, p_options: gobject.ext.ConnectSignalOptions(P_Data)) c_ulong {
                return gobject.signalConnectClosureById(
                    @ptrCast(@alignCast(gobject.ext.as(Device, p_instance))),
                    gobject.signalLookup("absolute-axis-event", Device.getGObjectType()),
                    glib.quarkFromString(p_options.detail orelse null),
                    gobject.CClosure.new(@ptrCast(p_callback), p_data, @ptrCast(p_options.destroyData)),
                    @intFromBool(p_options.after),
                );
            }
        };

        /// Emitted when a button is pressed.
        pub const button_press_event = struct {
            pub const name = "button-press-event";

            pub fn connect(p_instance: anytype, comptime P_Data: type, p_callback: *const fn (@TypeOf(p_instance), p_event: *manette.Event, P_Data) callconv(.c) void, p_data: P_Data, p_options: gobject.ext.ConnectSignalOptions(P_Data)) c_ulong {
                return gobject.signalConnectClosureById(
                    @ptrCast(@alignCast(gobject.ext.as(Device, p_instance))),
                    gobject.signalLookup("button-press-event", Device.getGObjectType()),
                    glib.quarkFromString(p_options.detail orelse null),
                    gobject.CClosure.new(@ptrCast(p_callback), p_data, @ptrCast(p_options.destroyData)),
                    @intFromBool(p_options.after),
                );
            }
        };

        /// Emitted when a button is released.
        pub const button_release_event = struct {
            pub const name = "button-release-event";

            pub fn connect(p_instance: anytype, comptime P_Data: type, p_callback: *const fn (@TypeOf(p_instance), p_event: *manette.Event, P_Data) callconv(.c) void, p_data: P_Data, p_options: gobject.ext.ConnectSignalOptions(P_Data)) c_ulong {
                return gobject.signalConnectClosureById(
                    @ptrCast(@alignCast(gobject.ext.as(Device, p_instance))),
                    gobject.signalLookup("button-release-event", Device.getGObjectType()),
                    glib.quarkFromString(p_options.detail orelse null),
                    gobject.CClosure.new(@ptrCast(p_callback), p_data, @ptrCast(p_options.destroyData)),
                    @intFromBool(p_options.after),
                );
            }
        };

        /// Emitted when the device is disconnected.
        pub const disconnected = struct {
            pub const name = "disconnected";

            pub fn connect(p_instance: anytype, comptime P_Data: type, p_callback: *const fn (@TypeOf(p_instance), P_Data) callconv(.c) void, p_data: P_Data, p_options: gobject.ext.ConnectSignalOptions(P_Data)) c_ulong {
                return gobject.signalConnectClosureById(
                    @ptrCast(@alignCast(gobject.ext.as(Device, p_instance))),
                    gobject.signalLookup("disconnected", Device.getGObjectType()),
                    glib.quarkFromString(p_options.detail orelse null),
                    gobject.CClosure.new(@ptrCast(p_callback), p_data, @ptrCast(p_options.destroyData)),
                    @intFromBool(p_options.after),
                );
            }
        };

        /// Emitted for any kind of event before mapping it.
        pub const event = struct {
            pub const name = "event";

            pub fn connect(p_instance: anytype, comptime P_Data: type, p_callback: *const fn (@TypeOf(p_instance), p_event: *manette.Event, P_Data) callconv(.c) void, p_data: P_Data, p_options: gobject.ext.ConnectSignalOptions(P_Data)) c_ulong {
                return gobject.signalConnectClosureById(
                    @ptrCast(@alignCast(gobject.ext.as(Device, p_instance))),
                    gobject.signalLookup("event", Device.getGObjectType()),
                    glib.quarkFromString(p_options.detail orelse null),
                    gobject.CClosure.new(@ptrCast(p_callback), p_data, @ptrCast(p_options.destroyData)),
                    @intFromBool(p_options.after),
                );
            }
        };

        /// Emitted when a hat axis' value changes.
        pub const hat_axis_event = struct {
            pub const name = "hat-axis-event";

            pub fn connect(p_instance: anytype, comptime P_Data: type, p_callback: *const fn (@TypeOf(p_instance), p_event: *manette.Event, P_Data) callconv(.c) void, p_data: P_Data, p_options: gobject.ext.ConnectSignalOptions(P_Data)) c_ulong {
                return gobject.signalConnectClosureById(
                    @ptrCast(@alignCast(gobject.ext.as(Device, p_instance))),
                    gobject.signalLookup("hat-axis-event", Device.getGObjectType()),
                    glib.quarkFromString(p_options.detail orelse null),
                    gobject.CClosure.new(@ptrCast(p_callback), p_data, @ptrCast(p_options.destroyData)),
                    @intFromBool(p_options.after),
                );
            }
        };
    };

    /// Gets the device type of `self`.
    extern fn manette_device_get_device_type(p_self: *Device) manette.DeviceType;
    pub const getDeviceType = manette_device_get_device_type;

    /// Gets the identifier used by SDL mappings to discriminate game controller
    /// devices.
    extern fn manette_device_get_guid(p_self: *Device) [*:0]const u8;
    pub const getGuid = manette_device_get_guid;

    /// Gets the user mapping for `self`, or default mapping if there isn't any.
    ///
    /// Can return `NULL` if there's no mapping or `self` doesn't support mappings.
    extern fn manette_device_get_mapping(p_self: *Device) ?[*:0]u8;
    pub const getMapping = manette_device_get_mapping;

    /// Gets the device's name.
    extern fn manette_device_get_name(p_self: *Device) [*:0]const u8;
    pub const getName = manette_device_get_name;

    /// Gets whether the device has the given input.
    ///
    /// If the input is present, it means that the device can send events for it
    /// regardless of whether the device is mapped or not.
    extern fn manette_device_has_input(p_self: *Device, p_type: c_uint, p_code: c_uint) c_int;
    pub const hasInput = manette_device_has_input;

    /// Gets whether `self` supports rumble.
    extern fn manette_device_has_rumble(p_self: *Device) c_int;
    pub const hasRumble = manette_device_has_rumble;

    /// Gets whether `self` has a user mapping.
    extern fn manette_device_has_user_mapping(p_self: *Device) c_int;
    pub const hasUserMapping = manette_device_has_user_mapping;

    /// Removes the user mapping for `self`.
    extern fn manette_device_remove_user_mapping(p_self: *Device) void;
    pub const removeUserMapping = manette_device_remove_user_mapping;

    /// Make `self` rumble during `milliseconds` milliseconds.
    ///
    /// The heavy and light motors will rumble at their respectively defined
    /// magnitudes.
    ///
    /// The duration cannot exceed 32767 milliseconds.
    extern fn manette_device_rumble(p_self: *Device, p_strong_magnitude: u16, p_weak_magnitude: u16, p_milliseconds: u16) c_int;
    pub const rumble = manette_device_rumble;

    /// Saves `mapping_string` as the user mapping for `self`.
    extern fn manette_device_save_user_mapping(p_self: *Device, p_mapping_string: [*:0]const u8) void;
    pub const saveUserMapping = manette_device_save_user_mapping;

    /// Gets whether `self` supports mapping.
    extern fn manette_device_supports_mapping(p_self: *Device) c_int;
    pub const supportsMapping = manette_device_supports_mapping;

    extern fn manette_device_get_type() usize;
    pub const getGObjectType = manette_device_get_type;

    extern fn g_object_ref(p_self: *manette.Device) void;
    pub const ref = g_object_ref;

    extern fn g_object_unref(p_self: *manette.Device) void;
    pub const unref = g_object_unref;

    pub fn as(p_instance: *Device, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// An object monitoring the availability of devices.
///
/// See also: `Device`.
pub const Monitor = opaque {
    pub const Parent = gobject.Object;
    pub const Implements = [_]type{};
    pub const Class = manette.MonitorClass;
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {
        /// Emitted when `device` is connected.
        pub const device_connected = struct {
            pub const name = "device-connected";

            pub fn connect(p_instance: anytype, comptime P_Data: type, p_callback: *const fn (@TypeOf(p_instance), p_device: *manette.Device, P_Data) callconv(.c) void, p_data: P_Data, p_options: gobject.ext.ConnectSignalOptions(P_Data)) c_ulong {
                return gobject.signalConnectClosureById(
                    @ptrCast(@alignCast(gobject.ext.as(Monitor, p_instance))),
                    gobject.signalLookup("device-connected", Monitor.getGObjectType()),
                    glib.quarkFromString(p_options.detail orelse null),
                    gobject.CClosure.new(@ptrCast(p_callback), p_data, @ptrCast(p_options.destroyData)),
                    @intFromBool(p_options.after),
                );
            }
        };

        /// Emitted when `device` is disconnected.
        pub const device_disconnected = struct {
            pub const name = "device-disconnected";

            pub fn connect(p_instance: anytype, comptime P_Data: type, p_callback: *const fn (@TypeOf(p_instance), p_device: *manette.Device, P_Data) callconv(.c) void, p_data: P_Data, p_options: gobject.ext.ConnectSignalOptions(P_Data)) c_ulong {
                return gobject.signalConnectClosureById(
                    @ptrCast(@alignCast(gobject.ext.as(Monitor, p_instance))),
                    gobject.signalLookup("device-disconnected", Monitor.getGObjectType()),
                    glib.quarkFromString(p_options.detail orelse null),
                    gobject.CClosure.new(@ptrCast(p_callback), p_data, @ptrCast(p_options.destroyData)),
                    @intFromBool(p_options.after),
                );
            }
        };
    };

    /// Creates a new `ManetteMonitor`.
    extern fn manette_monitor_new() *manette.Monitor;
    pub const new = manette_monitor_new;

    /// Creates a new `ManetterMonitorIter` iterating on `self`.
    extern fn manette_monitor_iterate(p_self: *Monitor) *manette.MonitorIter;
    pub const iterate = manette_monitor_iterate;

    extern fn manette_monitor_get_type() usize;
    pub const getGObjectType = manette_monitor_get_type;

    extern fn g_object_ref(p_self: *manette.Monitor) void;
    pub const ref = g_object_ref;

    extern fn g_object_unref(p_self: *manette.Monitor) void;
    pub const unref = g_object_unref;

    pub fn as(p_instance: *Monitor, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

pub const DeviceClass = extern struct {
    pub const Instance = manette.Device;

    f_parent_class: gobject.ObjectClass,

    pub fn as(p_instance: *DeviceClass, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

pub const MonitorClass = extern struct {
    pub const Instance = manette.Monitor;

    f_parent_class: gobject.ObjectClass,

    pub fn as(p_instance: *MonitorClass, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// An object iterating over the available devices in `Monitor`.
pub const MonitorIter = opaque {
    /// Frees `self`.
    extern fn manette_monitor_iter_free(p_self: *MonitorIter) void;
    pub const free = manette_monitor_iter_free;

    /// Gets the next device from `self`.
    extern fn manette_monitor_iter_next(p_self: *MonitorIter, p_device: ?**manette.Device) c_int;
    pub const next = manette_monitor_iter_next;

    extern fn manette_monitor_iter_get_type() usize;
    pub const getGObjectType = manette_monitor_iter_get_type;

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// An event emitted by a `Device`.
pub const Event = opaque {
    /// Creates a copy of `self`.
    extern fn manette_event_copy(p_self: *const Event) *manette.Event;
    pub const copy = manette_event_copy;

    /// Frees `self`.
    extern fn manette_event_free(p_self: *Event) void;
    pub const free = manette_event_free;

    /// Gets the axis of `self`, if any.
    extern fn manette_event_get_absolute(p_self: *const Event, p_axis: *u16, p_value: *f64) c_int;
    pub const getAbsolute = manette_event_get_absolute;

    /// Gets the button of `self`, if any.
    extern fn manette_event_get_button(p_self: *const Event, p_button: *u16) c_int;
    pub const getButton = manette_event_get_button;

    /// Gets the `Device` associated with the `self`.
    extern fn manette_event_get_device(p_self: *const Event) *manette.Device;
    pub const getDevice = manette_event_get_device;

    /// Gets the event type of `self`.
    extern fn manette_event_get_event_type(p_self: *const Event) manette.EventType;
    pub const getEventType = manette_event_get_event_type;

    /// Gets the hardware code of `self`.
    extern fn manette_event_get_hardware_code(p_self: *const Event) u16;
    pub const getHardwareCode = manette_event_get_hardware_code;

    /// Gets the hardware index of `self`.
    extern fn manette_event_get_hardware_index(p_self: *const Event) u16;
    pub const getHardwareIndex = manette_event_get_hardware_index;

    /// Gets the hardware type of `self`.
    extern fn manette_event_get_hardware_type(p_self: *const Event) u16;
    pub const getHardwareType = manette_event_get_hardware_type;

    /// Gets the hardware value of `self`.
    extern fn manette_event_get_hardware_value(p_self: *const Event) u16;
    pub const getHardwareValue = manette_event_get_hardware_value;

    /// Gets the hat of `self`, if any.
    extern fn manette_event_get_hat(p_self: *const Event, p_axis: *u16, p_value: *i8) c_int;
    pub const getHat = manette_event_get_hat;

    /// Gets the timestamp of when `self` was received by the input driver that takes
    /// care of its device.
    ///
    /// Use this timestamp to ensure external factors such as synchronous disk writes
    /// don't influence your timing computations.
    extern fn manette_event_get_time(p_self: *const Event) u32;
    pub const getTime = manette_event_get_time;

    extern fn manette_event_get_type() usize;
    pub const getGObjectType = manette_event_get_type;

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// Describes available types of a `Device`.
///
/// More values may be added to this enumeration over time.
pub const DeviceType = enum(c_int) {
    generic = 0,
    steam_deck = 1,
    _,

    extern fn manette_device_type_get_type() usize;
    pub const getGObjectType = manette_device_type_get_type;

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// Specifies the type of the event.
pub const EventType = enum(c_int) {
    event_nothing = -1,
    event_button_press = 0,
    event_button_release = 1,
    event_absolute = 2,
    event_hat = 3,
    _,

    extern fn manette_event_type_get_type() usize;
    pub const getGObjectType = manette_event_type_get_type;

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// Returns the major version number of the libmanette library.
///
/// For example, in libmanette version 1.2.3 this is 1.
///
/// This function is in the library, so it represents the libmanette library your
/// code is running against. Contrast with the `MAJOR_VERSION` constant,
/// which represents the major version of the libmanette headers you have
/// included when compiling your code.
extern fn manette_get_major_version() c_uint;
pub const getMajorVersion = manette_get_major_version;

/// Returns the micro version number of the libmanette library.
///
/// For example, in libmanette version 1.2.3 this is 3.
///
/// This function is in the library, so it represents the libmanette library your
/// code is running against. Contrast with the `MAJOR_VERSION` constant,
/// which represents the micro version of the libmanette headers you have
/// included when compiling your code.
extern fn manette_get_micro_version() c_uint;
pub const getMicroVersion = manette_get_micro_version;

/// Returns the minor version number of the libmanette library.
///
/// For example, in libmanette version 1.2.3 this is 2.
///
/// This function is in the library, so it represents the libmanette library your
/// code is running against. Contrast with the `MAJOR_VERSION` constant,
/// which represents the minor version of the libmanette headers you have
/// included when compiling your code.
extern fn manette_get_minor_version() c_uint;
pub const getMinorVersion = manette_get_minor_version;

/// libmanette major version component (e.g. 1 if the version is 1.2.3).
pub const MAJOR_VERSION = 0;
/// libmanette micro version component (e.g. 3 if the version is 1.2.3).
pub const MICRO_VERSION = 13;
/// libmanette minor version component (e.g. 2 if the version is 1.2.3).
pub const MINOR_VERSION = 2;
/// libmanette version, encoded as a string, useful for printing and
/// concatenation.
pub const VERSION_S = "0.2.13";

test {
    @setEvalBranchQuota(100_000);
    std.testing.refAllDecls(@This());
    std.testing.refAllDecls(ext);
}
