const std = @import("std");
pub const c = @import("c.zig").c;

pub const Joystick = opaque {
    pub inline fn isJoystickHaptic(joystick: *Joystick) bool {
        return c.SDL_IsJoystickHaptic(joystick);
    }

    pub inline fn openHapticFromJoystick(joystick: *Joystick) ?*Haptic {
        return c.SDL_OpenHapticFromJoystick(joystick);
    }
};

pub const Haptic = opaque {
    pub inline fn getHapticID(haptic: *Haptic) HapticID {
        return c.SDL_GetHapticID(haptic);
    }

    pub inline fn getHapticName(haptic: *Haptic) [*c]const u8 {
        return c.SDL_GetHapticName(haptic);
    }

    pub inline fn closeHaptic(haptic: *Haptic) void {
        return c.SDL_CloseHaptic(haptic);
    }

    pub inline fn getMaxHapticEffects(haptic: *Haptic) c_int {
        return c.SDL_GetMaxHapticEffects(haptic);
    }

    pub inline fn getMaxHapticEffectsPlaying(haptic: *Haptic) c_int {
        return c.SDL_GetMaxHapticEffectsPlaying(haptic);
    }

    pub inline fn getHapticFeatures(haptic: *Haptic) u32 {
        return c.SDL_GetHapticFeatures(haptic);
    }

    pub inline fn getNumHapticAxes(haptic: *Haptic) c_int {
        return c.SDL_GetNumHapticAxes(haptic);
    }

    pub inline fn hapticEffectSupported(haptic: *Haptic, effect: *const HapticEffect) bool {
        return c.SDL_HapticEffectSupported(haptic, @ptrCast(effect));
    }

    pub inline fn createHapticEffect(haptic: *Haptic, effect: *const HapticEffect) c_int {
        return c.SDL_CreateHapticEffect(haptic, @ptrCast(effect));
    }

    pub inline fn updateHapticEffect(haptic: *Haptic, effect: c_int, data: *const HapticEffect) bool {
        return c.SDL_UpdateHapticEffect(haptic, effect, @ptrCast(data));
    }

    pub inline fn runHapticEffect(haptic: *Haptic, effect: c_int, iterations: u32) bool {
        return c.SDL_RunHapticEffect(haptic, effect, iterations);
    }

    pub inline fn stopHapticEffect(haptic: *Haptic, effect: c_int) bool {
        return c.SDL_StopHapticEffect(haptic, effect);
    }

    pub inline fn destroyHapticEffect(haptic: *Haptic, effect: c_int) void {
        return c.SDL_DestroyHapticEffect(haptic, effect);
    }

    pub inline fn getHapticEffectStatus(haptic: *Haptic, effect: c_int) bool {
        return c.SDL_GetHapticEffectStatus(haptic, effect);
    }

    pub inline fn setHapticGain(haptic: *Haptic, gain: c_int) bool {
        return c.SDL_SetHapticGain(haptic, gain);
    }

    pub inline fn setHapticAutocenter(haptic: *Haptic, autocenter: c_int) bool {
        return c.SDL_SetHapticAutocenter(haptic, autocenter);
    }

    pub inline fn pauseHaptic(haptic: *Haptic) bool {
        return c.SDL_PauseHaptic(haptic);
    }

    pub inline fn resumeHaptic(haptic: *Haptic) bool {
        return c.SDL_ResumeHaptic(haptic);
    }

    pub inline fn stopHapticEffects(haptic: *Haptic) bool {
        return c.SDL_StopHapticEffects(haptic);
    }

    pub inline fn hapticRumbleSupported(haptic: *Haptic) bool {
        return c.SDL_HapticRumbleSupported(haptic);
    }

    pub inline fn initHapticRumble(haptic: *Haptic) bool {
        return c.SDL_InitHapticRumble(haptic);
    }

    pub inline fn playHapticRumble(haptic: *Haptic, strength: f32, length: u32) bool {
        return c.SDL_PlayHapticRumble(haptic, strength, length);
    }

    pub inline fn stopHapticRumble(haptic: *Haptic) bool {
        return c.SDL_StopHapticRumble(haptic);
    }
};

pub const HapticDirection = extern struct {
    _type: u8, // The type of encoding.
    dir: [3]i32, // The encoded direction.
};

pub const HapticConstant = extern struct {
    _type: u16, // SDL_HAPTIC_CONSTANT
    direction: HapticDirection, // Direction of the effect.
    length: u32, // Duration of the effect.
    delay: u16, // Delay before starting the effect.
    button: u16, // Button that triggers the effect.
    interval: u16, // How soon it can be triggered again after button.
    level: i16, // Strength of the constant effect.
    attack_length: u16, // Duration of the attack.
    attack_level: u16, // Level at the start of the attack.
    fade_length: u16, // Duration of the fade.
    fade_level: u16, // Level at the end of the fade.
};

pub const HapticPeriodic = extern struct {
    direction: HapticDirection, // Direction of the effect.
    length: u32, // Duration of the effect.
    delay: u16, // Delay before starting the effect.
    button: u16, // Button that triggers the effect.
    interval: u16, // How soon it can be triggered again after button.
    period: u16, // Period of the wave.
    magnitude: i16, // Peak value; if negative, equivalent to 180 degrees extra phase shift.
    offset: i16, // Mean value of the wave.
    phase: u16, // Positive phase shift given by hundredth of a degree.
    attack_length: u16, // Duration of the attack.
    attack_level: u16, // Level at the start of the attack.
    fade_length: u16, // Duration of the fade.
    fade_level: u16, // Level at the end of the fade.
};

pub const HapticCondition = extern struct {
    direction: HapticDirection, // Direction of the effect.
    length: u32, // Duration of the effect.
    delay: u16, // Delay before starting the effect.
    button: u16, // Button that triggers the effect.
    interval: u16, // How soon it can be triggered again after button.
    right_sat: [3]u16, // Level when joystick is to the positive side; max 0xFFFF.
    left_sat: [3]u16, // Level when joystick is to the negative side; max 0xFFFF.
    right_coeff: [3]i16, // How fast to increase the force towards the positive side.
    left_coeff: [3]i16, // How fast to increase the force towards the negative side.
    deadband: [3]u16, // Size of the dead zone; max 0xFFFF: whole axis-range when 0-centered.
    center: [3]i16, // Position of the dead zone.
};

pub const HapticRamp = extern struct {
    _type: u16, // SDL_HAPTIC_RAMP
    direction: HapticDirection, // Direction of the effect.
    length: u32, // Duration of the effect.
    delay: u16, // Delay before starting the effect.
    button: u16, // Button that triggers the effect.
    interval: u16, // How soon it can be triggered again after button.
    start: i16, // Beginning strength level.
    end: i16, // Ending strength level.
    attack_length: u16, // Duration of the attack.
    attack_level: u16, // Level at the start of the attack.
    fade_length: u16, // Duration of the fade.
    fade_level: u16, // Level at the end of the fade.
};

pub const HapticLeftRight = extern struct {
    _type: u16, // SDL_HAPTIC_LEFTRIGHT
    length: u32, // Duration of the effect in milliseconds.
    large_magnitude: u16, // Control of the large controller motor.
    small_magnitude: u16, // Control of the small controller motor.
};

pub const HapticCustom = extern struct {
    _type: u16, // SDL_HAPTIC_CUSTOM
    direction: HapticDirection, // Direction of the effect.
    length: u32, // Duration of the effect.
    delay: u16, // Delay before starting the effect.
    button: u16, // Button that triggers the effect.
    interval: u16, // How soon it can be triggered again after button.
    channels: u8, // Axes to use, minimum of one.
    period: u16, // Sample periods.
    samples: u16, // Amount of samples.
    data: *u16, // Should contain channels*samples items.
    attack_length: u16, // Duration of the attack.
    attack_level: u16, // Level at the start of the attack.
    fade_length: u16, // Duration of the fade.
    fade_level: u16, // Level at the end of the fade.
};

pub const HapticEffect = extern union {
    _type: u16, // Effect type.
    constant: HapticConstant, // Constant effect.
    periodic: HapticPeriodic, // Periodic effect.
    condition: HapticCondition, // Condition effect.
    ramp: HapticRamp, // Ramp effect.
    leftright: HapticLeftRight, // Left/Right effect.
    custom: HapticCustom, // Custom effect.
};

pub const HapticID = u32;

pub inline fn getHaptics(count: *c_int) ?*HapticID {
    return c.SDL_GetHaptics(@ptrCast(count));
}

pub inline fn getHapticNameForID(instance_id: HapticID) [*c]const u8 {
    return c.SDL_GetHapticNameForID(instance_id);
}

pub inline fn openHaptic(instance_id: HapticID) ?*Haptic {
    return c.SDL_OpenHaptic(instance_id);
}

pub inline fn getHapticFromID(instance_id: HapticID) ?*Haptic {
    return c.SDL_GetHapticFromID(instance_id);
}

pub inline fn isMouseHaptic() bool {
    return c.SDL_IsMouseHaptic();
}

pub inline fn openHapticFromMouse() ?*Haptic {
    return c.SDL_OpenHapticFromMouse();
}
