local joystick = {}
local joysticks = {}
local downTimes = {}
local bkspc = false
local keysLocked = false
local keyTime = 0
local keysPressed = {}
local keysReleased = {}
local buttons, buttons2 = {}, {}
local codes = {}
local empty = {}
local tempRect, tempMoose = {}, {}
local cursorToSet = nil
local isRelative = false
local keymap = {
	["space"] = 32,
	["'"] = 39,
	[","] = 44,
	["-"] = 45,
	["."] = 46,
	["/"] = 47,
	["0"] = 48,
	["1"] = 49,
	["2"] = 50,
	["3"] = 51,
	["4"] = 52,
	["5"] = 53,
	["6"] = 54,
	["7"] = 55,
	["8"] = 56,
	["9"] = 57,
	[";"] = 59,
	["="] = 61,
	["a"] = 65,
	["b"] = 66,
	["c"] = 67,
	["d"] = 68,
	["e"] = 69,
	["f"] = 70,
	["g"] = 71,
	["h"] = 72,
	["i"] = 73,
	["j"] = 74,
	["k"] = 75,
	["l"] = 76,
	["m"] = 77,
	["n"] = 78,
	["o"] = 79,
	["p"] = 80,
	["q"] = 81,
	["r"] = 82,
	["s"] = 83,
	["t"] = 84,
	["u"] = 85,
	["v"] = 86,
	["w"] = 87,
	["x"] = 88,
	["y"] = 89,
	["z"] = 90,
	["["] = 91,
	["\\"] = 92,
	["]"] = 93,
	["`"] = 96,
	["escape"] = 256,
	["return"] = 257,
	["enter"] = 257,
	["tab"] = 258,
	["backspace"] = 259,
	["insert"] = 260,
	["delete"] = 261,
	["right"] = 262,
	["left"] = 263,
	["down"] = 264,
	["up"] = 265,
	["pageup"] = 266,
	["pagedown"] = 267,
	["home"] = 268,
	["end"] = 269,
	["capslock"] = 280,
	["scrolllock"] = 281,
	["numlock"] = 282,
	["printscreen"] = 283,
	["pause"] = 284,
	["f1"] = 290,
	["f2"] = 291,
	["f3"] = 292,
	["f4"] = 293,
	["f5"] = 294,
	["f6"] = 295,
	["f7"] = 296,
	["f8"] = 297,
	["f9"] = 298,
	["f10"] = 299,
	["f11"] = 300,
	["f12"] = 301,
	["kp0"] = 320,
	["kp1"] = 321,
	["kp2"] = 322,
	["kp3"] = 323,
	["kp4"] = 324,
	["kp5"] = 325,
	["kp6"] = 326,
	["kp7"] = 327,
	["kp8"] = 328,
	["kp9"] = 329,
	["kp."] = 330,
	["kp/"] = 331,
	["kp*"] = 332,
	["kp-"] = 333,
	["kp+"] = 334,
	["kpenter"] = 335,
	["kp="] = 336,
	["lshift"] = 340,
	["lctrl"] = 341,
	["lalt"] = 342,
	["lgui"] = 343,
	["rshift"] = 344,
	["rctrl"] = 345,
	["ralt"] = 346,
	["rgui"] = 347,
	["menu"] = 348,
}

for k, v in pairs(keymap) do
	codes[v] = k
end

local function setMouseVars()
	mouse.toClick = {}
	mouse.toRelease = {}
	mouse.line = mouse.line or {}
	mouse.tline = mouse.tline or {}

	local newx = mouse_getRelativeMode() and screenW / 2 or mouse.x * (game and game.resolution or 1)
	local newy = mouse_getRelativeMode() and screenH / 2 or mouse.y * (game and game.resolution or 1)

	mouse.moved = (mouse.x - mouse.px) ~= 0 or (mouse.y - mouse.py) ~= 0
	mouse.change = { x = newx - mouse.x, y = newy - mouse.y }
	mouse.x = newx or mouse.x
	mouse.y = newy or mouse.y

	engine.window.mouse.x, engine.window.mouse.y = mouse.x, mouse.y

	if mouse.penUpdated == 0 then
		mouse.pressure = 1
	else
		mouse.penUpdated = mouse.penUpdated and mouse.penUpdated - 1 or 0
	end

	mouse.dist = mouse.start.x and math.dist(mouse.x, mouse.y, mouse.start.x, mouse.start.y) or 0
	mouse.scroll.x = easeTo(mouse.scroll.x, 0, loSpec and 8 or 2)
	mouse.scroll.y = easeTo(mouse.scroll.y, 0, loSpec and 8 or 2)

	if mouse.moved then
		table.insert(mouse.line, 1, mouse.y)
		table.insert(mouse.line, 1, mouse.x)
	end
	if #mouse.line > 100 then
		table.remove(mouse.line, #mouse.line)
		table.remove(mouse.line, #mouse.line)
	end

	if mouse.moved then
		table.insert(mouse.tline, 1, mouse.y)
		table.insert(mouse.tline, 1, mouse.x)
	end
	if #mouse.tline > 10 then
		table.remove(mouse.tline, #mouse.tline)
		table.remove(mouse.tline, #mouse.tline)
	end
	mouse.trend = mouse.trend and mouse.trend:set(0, 0, 0) or vec3()
	local count = 4
	if #mouse.tline > count then
		for i = 1, count - 2, 2 do
			mouse.trend.x = mouse.trend.x + (mouse.tline[i] - mouse.tline[i + 2])
			mouse.trend.y = mouse.trend.y + (mouse.tline[i + 1] - mouse.tline[i + 3])
		end
		mouse.trend.x = mouse.trend.x / count
		mouse.trend.y = mouse.trend.y / count
		mouse.trend.z = math.abs(mouse.trend.x) > math.abs(mouse.trend.y) and 1 or 0
	end
end


function input_key_callback(keycode,charcode, action, mods)
	if not codes[keycode] then
		return
	end
  -- print("keycode",keycode,action,codes[keycode])
	local k = codes[keycode]
	if action == 1 then --DOWN
		if k == "enter" then
			k = "return"
		end
		if editor and ctx.editing and editor.coding and scriptsPanel.focused then
			polywell.keypressed(k)

			if cmdDown then
				if k == "return" then
					editor_playLevel()
				elseif k == "s" then
					local success, err = pcall(require, LINK_DIR .. scriptsPanel.script.filename)
					if success then
						pcall(lume.hotswap, LINK_DIR .. scriptsPanel.script.filename)
					else
						editor_tempTip(err, 3)
					end
				elseif k == "a" then
					scriptsPanel.b.point = 0
					scriptsPanel.b.point_line = 1
					scriptsPanel.b.mark = #lume.last(scriptsPanel.b.lines)
					scriptsPanel.b.mark_line = #scriptsPanel.b.lines
				elseif k == "-" then
					scriptsPanel.fontSize = scriptsPanel.fontSize > scriptsPanel.minFontSize
							and scriptsPanel.fontSize - 1
						or scriptsPanel.fontSize
				elseif k == "=" then
					scriptsPanel.fontSize = scriptsPanel.fontSize < scriptsPanel.maxFontSize
							and scriptsPanel.fontSize + 1
						or scriptsPanel.fontSize
				elseif k == "up" then
					local temp = scriptsPanel.b.lines[scriptsPanel.b.point_line]
					scriptsPanel.b.lines[scriptsPanel.b.point_line] =
						scriptsPanel.b.lines[scriptsPanel.b.point_line - 1]
					scriptsPanel.b.lines[scriptsPanel.b.point_line - 1] = temp
					polywell.word_wrap()
				elseif k == "down" then
					local temp = scriptsPanel.b.lines[scriptsPanel.b.point_line]
					scriptsPanel.b.lines[scriptsPanel.b.point_line] =
						scriptsPanel.b.lines[scriptsPanel.b.point_line + 1]
					scriptsPanel.b.lines[scriptsPanel.b.point_line + 1] = temp
					polywell.word_wrap()
				end
			end
			if k == "escape" then
				editor_closePanel(scriptsPanel, function()
					scriptsPanel.x = 9999
					scriptsPanel.border = nil
					editor.coding = false
					scriptsPanel.focused = false
					mouse_pushRelease(editor_releaseMouse)
					mouse_pushReleaseR(editor_releaseMouse)
				end)
			end
		else
			keysPressed[k] = true

			table.add(engine.keysDown, k)
			downTimes[k] = 0
			if cmdDown and altDown and shiftDown and k == "escape" then
				engine_exit()
			end
		end
	else
		if engine.project and ctx.editing and editor.coding and scriptsPanel.focused then
			polywell.keyreleased(k)
		else
			keysPressed[k] = nil
			lume.remove(engine.keysDown, k)
			table.add(keysReleased, k)
			--downTimes[k] = 0
		end
	end
end

function input_click_callback(button, action, mods)
	_TEMPTESTCLICK = function()
		print("mouse_callback", button, action)
    local index = {"L","R","M"}
		local x, y = mouse_getPosition()
		if action == 1 then
      mouse.down[index[button]]=true
			mouse.line = {}
			mouse.start.x, mouse.start.y = mouse.x, mouse.y

			if mouse.double and mouse.time < mouse.tripleTime then
				mouse.triple = true
			else
				mouse.triple = false
			end
			if mouse.double then
  			mouse.double = false
			elseif mouse.time < mouse.doubleTime then
				mouse.double = true
			end

			mouse.movedSinceClick = false
			mouse.time = 0

			if editor then
				editor.mouseStored = lume.clone(mouse)
			end

			if not mouse[index[button]].release then
				mouse[index[button]].func(unpack(mouse[index[button]].arg or empty))
			end
			
			local clicked = false
			for c, click in ipairs(mouse.toClick) do
				if button == click.button and (click.f(unpack(click.args or empty)) == true) then
					clicked = true
				end
			end
			mouse.toClick = {}
		else
      mouse.down[index[button]]=false
			-- released
			if mouse[index[button]] and mouse[index[button]].release then
				mouse[index[button]].func(unpack(mouse[index[button]].arg or empty))
			end
			if button == 1 then
				mouse.upSet = true
			end
			local released = false
			for c, release in ipairs(mouse.toRelease) do
				if button == release.button and (release.f(unpack(release.args or empty))) then
					released = true
				end
			end
			mouse.toRelease = {}
		end
    print("mouse_callback done")
	end 
  if not engine.project then 
    if _TEMPTESTCLICK then print("hmm")_TEMPTESTCLICK() _TEMPTESTCLICK = nil end
  end
end

function input_mouse_callback(x, y,dx,dy)
	local scale = mouse_getScale()
	local x = x * scale
	local y = y * scale

	mouse.movedSinceClick = true
	mouse.dx = dx
	mouse.dy = dy
	mouse.moved = true
	if editor and editor.viewport then
		local cam = editor.viewport.camera
		local mode = (
			cam
			and not (editor and editor.orbiting)
			and (cam.locked or mouse.down.M)
			and editor.state == "Panning"
		)
				and 1
			or (mouse_getRelativeMode() and 2 or 0)
		local speed = mode == 1 and -0.2 / cam.zoom or 1
		if mode == 1 or mode == 2 then
			cam.angle.tx = cam.angle.tx + math.rad(dx * speed * 0.2)
			cam.angle.ty = mc(-pi / 2, cam.angle.ty - math.rad(dy * speed * (mode == 1 and 0.2 or 0.1)), pi / 2)
		end
	end
  mouse.px, mouse.py = mouse.x, mouse.y
  mouse.x, mouse.y=x,y
end

function input_scroll_callback(x, y)
	for i, v in ipairs(mouse.toscroll) do
		local dir = v.h and x or y
		v.v[v.k] = v.v[v.k] + dir * v.s
	end
	mouse.toscroll = {}
	mouse.scroll = { x = easeTo(mouse.scroll.x, x, 2, 1), y = easeTo(mouse.scroll.y, y, loSpec and 8 or 2, 1) }
end

function input_pen_callback(x, y, z, pressure, pitch, yaw, roll)
	-- print("pen",x,y,z,pressure,pitch,yaw,roll)
	mouse.pressure = mc(0, utils.map(pressure, 0.1, 1, 0, 1), 1)

	-- print("mouse.pressure",mouse.pressure)
	if not lwindow.getVSync() then
		mouse.x, mouse.y = x, y
	end
	mouse.penUpdated = 10
end

function input_focus_callback(f)
	local focus = f == 1
	engine.focused = focus
	if not focus then
		mouse_setVisible(true)
	else
    print("FOCUSED")
		if not lfs.isFused() then
			engine_loadSource(true)
		end
		if game and game.state == "Edit" then
			if ctx.editing then
				if editor.debug.rebuild_on_focus then
					game.time = -1
				end
			end
			load_checkImages(LINK_DIR .. "symbols", "symbols/")
		end
	end
end

function input_getJoystickCount()
	return 0
end

function input_getJoysticks() end

function input_joyGetAxis(joy, button)
	return false
end

function input_joyIsDown(joy, button)
	return false
end

function input_updateControls()

	keyTime = #engine.keysDown > 0 and 4 or math.max(0, keyTime - 1)

	local wasLocked = keysLocked
	input_unlockKeys()
	for k, keyTime in pairs(downTimes) do
		downTimes[k] = input_keyDown(k) and downTimes[k] + 1 or downTimes[k]
	end
	if wasLocked then
		input_lockKeys()
	end

	setMouseVars()
	shiftDown = input_keyDown("lshift") or input_keyDown("rshift")
	altDown = input_keyDown("lalt") or input_keyDown("ralt")
	cmdDown = input_keyDown("lgui") or input_keyDown("rgui") or input_keyDown("lctrl") or input_keyDown("rctrl")

  if cmdDown and input_keyDown("q") then 
    engine.window.close=true
  end


	if joystick == {} and input_getJoystickCount() > 0 then
		joysticks = input_getJoysticks()
		joystick = joysticks[1]
	else
		joystick = joystick
	end

  local j = joystick
	--leftAnalogClicked = input_joyisDown(j,2) or input_keyDown("1")
	--rightAnalogClicked= input_joyisDown(j,3) or input_keyDown("2")

	buttons.leftAnalogVert = (input_joyGetAxis(j, 2) and math.abs(input_joyGetAxis(j, 2)) > 0.1) and input_joyGetAxis(
		j,
		2
	) or (buttons.upButtonDown and -1 or (buttons.downButtonDown and 1 or 0))
	buttons.leftAnalogHori = (input_joyGetAxis(j, 1) and math.abs(input_joyGetAxis(j, 1)) > 0.1) and input_joyGetAxis(
		j,
		1
	) or (buttons.leftButtonDown and -1 or (buttons.rightButtonDown and 1 or 0))
	--rightAnalogVert   = input_joygetAxis(j, 2 )
	--rightAnalogHori   = input_joygetAxis(j, 1 )

	buttons.upButtonDown = (input_joyGetAxis(j, 2) and input_joyGetAxis(j, 2) < -0.5)
		or input_joyIsDown(j, 5)
		or input_keyDown("up")
	buttons.downButtonDown = (input_joyGetAxis(j, 2) and input_joyGetAxis(j, 2) > 0.5)
		or input_joyIsDown(j, 7)
		or input_keyDown("down")
	buttons.leftButtonDown = (input_joyGetAxis(j, 1) and input_joyGetAxis(j, 1) < -0.5)
		or input_joyIsDown(j, 8)
		or input_keyDown("left")
	buttons.rightButtonDown = (input_joyGetAxis(j, 1) and input_joyGetAxis(j, 1) > 0.5)
		or input_joyIsDown(j, 6)
		or input_keyDown("right")

	buttons.aButtonDown = input_joyIsDown(j, 15) or input_keyDown("a")
	buttons.bButtonDown = input_joyIsDown(j, 14) or input_keyDown("s")
	buttons.xButtonDown = input_joyIsDown(j, 16) or input_keyDown("q")
	buttons.yButtonDown = input_joyIsDown(j, 13) or input_keyDown("w")
	buttons.selectButtonDown = input_joyIsDown(j, 1) or input_keyDown("backspace")
	buttons.startButtonDown = input_joyIsDown(j, 4) or input_keyDown("return")
	buttons.rightTrigButtonDown = input_joyIsDown(j, 12) or input_joyIsDown(j, 10) or input_keyDown("rshift")
	buttons.leftTrigButtonDown = input_joyIsDown(j, 11) or input_joyIsDown(j, 9) or input_keyDown("space")

	buttons2 = {
		["upButtonDown"] = buttons.upButtonDown,
		["downButtonDown"] = buttons.downButtonDown,
		["leftButtonDown"] = buttons.leftButtonDown,
		["rightButtonDown"] = buttons.rightButtonDown,
		["aButtonDown"] = buttons.aButtonDown,
		["bButtonDown"] = buttons.bButtonDown,
		["xButtonDown"] = buttons.xButtonDown,
		["yButtonDown"] = buttons.yButtonDown,
		["selectButtonDown"] = buttons.selectButtonDown,
		["startButtonDown"] = buttons.startButtonDown,
		["rightTrigButtonDown"] = buttons.rightTrigButtonDown,
		["leftTrigButtonDown"] = buttons.leftTrigButtonDown,
	}


	if not controls then
		return
	end
	if buttons ~= nil then
		for k, b in pairs(buttons2) do
			local str
			if buttons[k] == false and b == true then
				str = string.gsub(tostring(k), "ButtonDown", "") .. "ButtonPressed"
				controls[str] = true
				--log(str)
			end
			if buttons[k] == true and b == false then
				str = string.gsub(tostring(k), "ButtonDown", "") .. "ButtonReleased"
				controls[str] = true
				--log(str)
			end
			if buttons[k] == true and b == true then
				controls[string.gsub(tostring(k), "ButtonDown", "") .. "ButtonPressed"] = false
				controls[string.gsub(tostring(k), "ButtonDown", "") .. "ButtonReleased"] = false
			end
		end
	end
	controls.leftAnalogVert = leftAnalogVert
	controls.leftAnalogHori = leftAnalogHori
end

function input_resetControls()
	if buttons ~= nil then
		for k, b in pairs(buttons2) do
			controls[string.gsub(tostring(k), "ButtonDown", "") .. "ButtonPressed"] = false
			controls[string.gsub(tostring(k), "ButtonDown", "") .. "ButtonReleased"] = false
		end
	end
end

function input_keyRepeat(k, fast)
	return input_keyPressed(k) or (input_keyDown(k, 16) and (engine.fourstep == 2 or fast))
end

function input_keysDown(key, ...)
	if not key then
		return false
	end
	local keycode = keymap[key]
	assert(keycode and type(keycode) == "number", "Unknown key: " .. key)
	return input_keyDown(...)
end

function input_clearKeys()
	keysPressed = {}
end

function input_keyPressed(k)
	if keysLocked == true or lume.count(keysPressed) == 0 then
		return false
	end
	if type(k) == "table" then
	else
		return keysPressed[k]
	end
end

function input_anyKeyPressed(t)
	for k, key in ipairs(t) do
		if input_keyPressed(key) then
			return true
		end
	end
	return false
end

function input_keyReleased(k, t1, t2)
	if keysLocked == true or #keysReleased == 0 then
		return false
	end
	if downTimes[k] then
		return downTimes[k] > (t1 or -1) and downTimes[k] < (t2 or 999999) and (lume.find(keysReleased, k))
	else
		return (lume.find(keysReleased, k))
	end
end

function input_keyTapped(k)
	return input_keyReleased(k, 0, 10)
end

function input_keyDown(k, frames)
	if keysLocked == true or #engine.keysDown == 0 then
		return false
	end
	local heldEnough
	if frames then
		heldEnough = downTimes[k] and downTimes[k] > frames
	else
		heldEnough = true
	end
	return (lume.find(engine.keysDown, k) and heldEnough)
end

function input_anyKeyDown(keys)
	local any = false
	for _, k in ipairs(keys) do
		if input_keyDown(k) then
			any = true
		end
	end
	return any
end

function input_keyboardInput(t)
	if ctx.editing and editor.coding and scriptsPanel.focused then
		polywell.textinput(t)
	else
		if namer.open and namer.mode ~= "warning" then
			if #namer.text < (namer.target.limit or 9999) then
				local canType = true
				if namer.num then
					canType = false
					for i = 0, 9, 1 do
						if t == tostring(i) then
							canType = true
						end
					end
				end
				if canType then
					namer.text = namer.text .. t
				end
			end
		end
	end
end

function input_keysReset()
	lume.clear(keysPressed)
	lume.clear(keysReleased)
	keyboard.active = #engine.keysDown > 0
end

function input_keysModsTouched()
	return input_keysModsReleased() or input_keysModsPressed()
end

function input_keysModsReleased()
	return input_keyReleased("lgui")
		or input_keyReleased("rgui")
		or input_keyReleased("lshift")
		or input_keyReleased("rshift")
		or input_keyReleased("lctrl")
		or input_keyReleased("rctrl")
		or input_keyReleased("lalt")
		or input_keyReleased("ralt")
end

function input_keysModsPressed()
	return input_keyPressed("lgui")
		or input_keyPressed("rgui")
		or input_keyPressed("lshift")
		or input_keyPressed("rshift")
		or input_keyPressed("lctrl")
		or input_keyPressed("rctrl")
		or input_keyPressed("lalt")
		or input_keyPressed("ralt")
end

function input_lockKeys()
	keysLocked = true
end

function input_unlockKeys()
	keysLocked = false
end

function input_lockMouse()
	--mouse_setR(function ()end)
	mouse.locked = true
end
function input_unlockMouse()
	mouse.locked = false
	mouse.x = mouse.x
	mouse.y = mouse.y
end

function mouse_define()
	mouse.down = {}
	mouse.upSet = false
	mouse.down.L = false
	mouse.down.R = false
	mouse.scroll = { x = 0, y = 0 }
	mouse.pressure = 1
	mouse.locked = false
	mouse.tripleTime = 24
	mouse.time = 0
	mouse.double = false
	mouse.triple = false
	mouse.L = { func = function() end, release = false }
	mouse.R = { func = function() end, release = false }
	mouse.M = { func = function() end, release = false }
	mouse.doubleTime = 16
	mouse.toClick = {}
	mouse.toRelease = {}
	mouse.start = { x = 0, y = 0 }
	mouse.toscroll = {}
end

function mouse_set(func, release)
	if not mouse.locked then
		if type(func) == "table" then
			mouse.L = {
				func = type(func[1]) == "table" and func[1][1] or func[1],
				arg = lume.slice(func, 2),
				release = release or false,
			}
		else
			mouse.L = { func = func, release = release or false }
		end
	end
end
function mouse_setR(func, release)
	if not mouse.locked then
		if type(func) == "table" then
			mouse.R = {
				func = type(func[1]) == "table" and func[1][2] or func[1],
				arg = lume.slice(func, 2),
				release = release or false,
			}
		else
			mouse.R = { func = func, release = release or false }
		end
	end
end
function mouse_setM(func, release)
	if not mouse.locked then
		mouse.M = { func = func, release = release or false }
	end
end

function mouse_pushDown(f, ...)
	mouse_pushClick(f, arg)
	mouse_pushClickR(f, arg)
end
function mouse_pushUp(f, ...)
	mouse_pushRelease(f, arg)
	mouse_pushReleaseR(f, arg)
end

function mouse_pushClick(f, ...)
	table.insert(mouse.toClick, 1, { f = f, args = arg, button = 1 })
end
function mouse_pushClickR(f, ...)
	table.insert(mouse.toClick, 1, { f = f, args = arg, button = 2 })
end
function mouse_pushClickM(f, ...)
	table.insert(mouse.toClick, 1, { f = f, args = arg, button = 3 })
end

function mouse_pushRelease(f, ...)
	table.insert(mouse.toRelease, 1, { f = f, args = arg, button = 1 })
end
function mouse_pushReleaseR(f, ...)
	table.insert(mouse.toRelease, 1, { f = f, args = arg, button = 2 })
end
function mouse_pushReleaseM(f, ...)
	table.insert(mouse.toRelease, 1, { f = f, args = arg, button = 3 })
end

function mouse_reset()
	mouse.upSet = false
	mouse.active = (
		mouse.down.L
		or mouse.down.R
		or mouse.x ~= mouse.px
		or mouse.y ~= mouse.py
		or mouse.scroll.x ~= 0
		or mouse.scroll.y ~= 0
	)
end

function mouse_getScale()
  local x, _ = ffi.new("int[1]"), ffi.new("int[1]")
  -- C.glfwGetWindowSize(gfx.window, x, _)
  -- return screenW / x[0]
  return 1
end

function mouse_setX(x)
  local y = mouse.y
  local scale = mouse_getScale()
  -- C.glfwSetCursorPos(gfx.window, x / scale, y / scale)
end

function mouse_setY(y)
  local x = mouse.x
  local scale = mouse_getScale()
  -- C.glfwSetCursorPos(gfx.window, x / scale, y / scale)
end

function mouse_setPosition(x, y)
  local scale = mouse_getScale()
  -- C.glfwSetCursorPos(gfx.window, x / scale, y / scale)
end

function mouse_getPosition()
  local x, y = ffi.new("double[1]"), ffi.new("double[1]")
  local scale = mouse_getScale()
  -- C.glfwGetCursorPos(gfx.window, x, y)
  return x[0] * scale, y[0] * scale
end

function mouse_isDown(button, ...)
  if not button then
    return false
  end
  return false--C.glfwGetMouseButton(gfx.window, button - 1) > 0 or mouse_isDown(...)
end

function mouse_getRelativeMode()
  return isRelative
end

function mouse_setRelativeMode(enable)
  ffi.C.sapp_lock_mouse(enable)
  isRelative = enable
end


function mouse_release(func)
	if mouse.upSet then
		local func = func or nothing
		func()
		return true
	else
		return false
	end
end

function mouse_in(rect, y, w, h)
	local rect = rect
	if w and h then
		tempRect.x = rect
		tempRect.y = y
		tempRect.w = w
		tempRect.h = h
		rect = tempRect
	end

	if not mouse.locked and rect and rect.x and rect.y and (rect.w or rect.width) and (rect.h or rect.height) then
		return simplePointInRect(mouse, rect)
	else
		return false
    	end
end

function mouse_getCoords()
	return { x = mouse.x, y = mouse.y }
end


-- not really "input" but w/e
local pixels = ffi.new("unsigned char[?]", 16 * 16 * 4)
-- local image = ffi.new("GLFWimage", 16, 16, pixels)
local blankCursor = {}
function mouse_newCursor(imageData, x, y)
  -- print("new cursor1")
  -- print(imageData.data.width,imageData.data.height,imageData.data.data)
  -- print(inspect(imageData))
  -- print(imageData.data)
  -- print(imageData.data.width)
  -- print(imageData.data.data)
  -- local glfwImage = ffi.new("GLFWimage", imageData.data.width, imageData.data.height, imageData.data.data)
  -- print("new cursor2")
  -- local cursor = ffi.gc(C.glfwCreateCursor(glfwImage, x, y), C.glfwDestroyCursor)
  return {}
end

function mouse_setCursor(cursor)
  if cursorToSet ~= cursor then
    print("setcursor", time, cursor)

    -- C.glfwSetCursor(gfx.window, cursor)
    cursorToSet = cursor
  end
end

function mouse_getCursor()
  return cursorToSet
end

function mouse_setVisible()
--TODO cursor setvisible
  -- print("setviscursor",time,cursor)
  -- print("gfx window",engine.window.handle)
  -- C.glfwSetInputMode(gfx.window, C.GLFW_CURSOR, visible and  C.GLFW_CURSOR_NORMAL or C.GLFW_CURSOR_HIDDEN)
  -- C.glfwSetCursor(gfx.window  , (not visible) and blankCursor or cursorToSet);
end