//+build linux
package evdev

import "core:fmt"
import "core:os"
import "core:intrinsics"
import "core:sys/unix"

// Hopefully safe definition.
@(private)
Timeval :: struct {
	tv_sec:  int,
	tv_usec: int,
}

// /dev/input/by-id/usb-Microsoft_Controller_30324B4530303836313733373439-event-joystick

InputEvent :: struct {
	time:  Timeval,
	type:  EventType,
	code:  u16,
	value: uint,
}

EventType :: enum u16 {
	Syn      = 0x00,
	Key      = 0x01,
	Rel      = 0x02,
	Abs      = 0x03,
	Msc      = 0x04,
	Sw       = 0x05,
	Led      = 0x11,
	Snd      = 0x12,
	Rep      = 0x14,
	Ff       = 0x15,
	Pwr      = 0x16,
	FfStatus = 0x17,
	Max      = 0x1f,
}

AbsAxis :: enum {
	X             = 0x00,
	Y             = 0x01,
	Z             = 0x02,
	Rx            = 0x03,
	Ry            = 0x04,
	Rz            = 0x05,
	Throttle      = 0x06,
	Rudder        = 0x07,
	Wheel         = 0x08,
	Gas           = 0x09,
	Brake         = 0x0a,
	Hat0X         = 0x10,
	Hat0Y         = 0x11,
	Hat1X         = 0x12,
	Hat1Y         = 0x13,
	Hat2X         = 0x14,
	Hat2Y         = 0x15,
	Hat3X         = 0x16,
	Hat3Y         = 0x17,
	Pressure      = 0x18,
	Distance      = 0x19,
	TiltX         = 0x1a,
	TiltY         = 0x1b,
	ToolWidth     = 0x1c,
	Volume        = 0x20,
	Profile       = 0x21,
	Misc          = 0x28,
	Reserved      = 0x2e,
	MtSlot        = 0x2,
	MtTouchMajor  = 0x30,
	MtTouchMinor  = 0x31,
	MtWidthMajor  = 0x32,
	MtWidthMinor  = 0x33,
	MtOrientation = 0x34,
	MtPositionX   = 0x35,
	MtPositionY   = 0x36,
	MtToolType    = 0x37,
	MtBlobId      = 0x38,
	MtTrackingId  = 0x39,
	MtPressure    = 0x3a,
	MtDistance    = 0x3b,
	MtToolX       = 0x3c,
	MtToolY       = 0x3d,
}

Button :: enum {
	Misc          = 0x100,
	Num0          = 0x100,
	Num1          = 0x101,
	Num2          = 0x102,
	Num3          = 0x103,
	Num4          = 0x104,
	Num5          = 0x105,
	Num6          = 0x106,
	Num7          = 0x107,
	Num8          = 0x108,
	Num9          = 0x109,
	Mouse         = 0x110,
	Left          = 0x110,
	Right         = 0x111,
	Middle        = 0x112,
	Side          = 0x113,
	Extra         = 0x114,
	Forward       = 0x115,
	Back          = 0x116,
	Task          = 0x117,
	Joystick      = 0x120,
	Trigger       = 0x120,
	Thumb         = 0x121,
	Thumb2        = 0x122,
	Top           = 0x123,
	Top2          = 0x124,
	Pinkie        = 0x125,
	Base          = 0x126,
	Base2         = 0x127,
	Base3         = 0x128,
	Base4         = 0x129,
	Base5         = 0x12a,
	Base6         = 0x12b,
	Dead          = 0x12f,
	GamepaD       = 0x130,
	South         = 0x130,
	A             = South,
	East          = 0x131,
	B             = East,
	C             = 0x132,
	North         = 0x133,
	X             = North,
	West          = 0x134,
	Y             = West,
	Z             = 0x135,
	Tl            = 0x136,
	Tr            = 0x137,
	Tl2           = 0x138,
	Tr2           = 0x139,
	Select        = 0x13a,
	Start         = 0x13b,
	Mode          = 0x13c,
	Thumbl        = 0x13d,
	Thumbr        = 0x13e,
	Digi          = 0x140,
	ToolPen       = 0x140,
	ToolRubber    = 0x141,
	ToolBrush     = 0x142,
	ToolPencil    = 0x143,
	ToolAirbrush  = 0x144,
	ToolFinger    = 0x145,
	ToolMouse     = 0x146,
	ToolLens      = 0x147,
	ToolQuinttap  = 0x148, /* Five fingers on trackpad =*/
	Stylus3       = 0x149,
	Touch         = 0x14a,
	Stylus        = 0x14b,
	Stylus2       = 0x14c,
	ToolDoubletap = 0x14d,
	ToolTripletap = 0x14e,
	ToolQuadtap   = 0x14f, /* Four fingers on trackpad =*/
	Wheel         = 0x150,
	GearDown      = 0x150,
	GearUp        = 0x151,
}

InputAbsinfo :: struct {
	value:      i16,
	minimum:    i16,
	maximum:    i16,
	fuzz:       i16,
	flag:       i16,
	resolution: i16,
}

InputKeymap :: struct {
	flags:    u8,
	len:      u8,
	index:    u16,
	keycode:  u32,
	scancode: [32]u8,
}

get_abs_axis :: proc(handle: os.Handle, axis: AbsAxis) -> InputAbsinfo {
	absinfo: InputAbsinfo
	result := int(
		intrinsics.syscall(
			unix.SYS_ioctl,
			uintptr(handle),
			uintptr(EVIOCGABS | ((0x40 + uint(axis)) << IOC_NRSHIFT)),
			uintptr(&absinfo),
		),
	)
	if result < 0 {
		fmt.printf("error: %d - %s\n", result, string(strerror(result)))
	}
	// fmt.printf("\t%#v\n", absinfo)
	return absinfo
}

get_key :: proc(handle: os.Handle) -> [(0x2ff + 7) / 8]u8 {
	buffer: [(0x2ff + 7) / 8]u8
	result := int(
		intrinsics.syscall(
			unix.SYS_ioctl,
			uintptr(handle),
			uintptr(EVIOCGKEY),
			uintptr(&buffer[0]),
		),
	)
	if result < 0 {
		fmt.printf("error: %d - %s\n", result, string(strerror(result)))
	}
	return buffer
}