local N=require((game:GetService("\082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101")):WaitForChild("\078\101\118\101\114\109\111\114\101"))local C=N("\073\078\080\085\084\095\077\079\068\069\083")local F=N("\077\097\105\100")local h=N("\086\097\108\117\101\079\098\106\101\099\116")local d={}d.ClassName="\073\110\112\117\116\077\111\100\101\083\101\108\101\099\116\111\114"d.INPUT_MODES=C d.DEFAULT_MODES={C.Gamepads;C.Keyboard;C.Touch}function d.new(N)local C=setmetatable({},d)C._maid=F.new()C._activeMode=h.new()C.Changed=C._activeMode.Changed C._maid:GiveTask(C._activeMode)for N,F in pairs(N or d.DEFAULT_MODES)do C:_addInputMode(F)end return C end function d.__index(C,N)if N=="\086\097\108\117\101"then return(rawget(C,"\095\097\099\116\105\118\101\077\111\100\101")).Value elseif d[N]then return d[N]else local F=rawget(C,N)if F then return F else error(("\091\073\110\112\117\116\077\111\100\101\083\101\108\101\099\116\111\114\093 - \066\097\100 \105\110\100\101\120 \'\037\115\'"):format(tostring(N)))end end end function d.Bind(C,N)local h=F.new()C._maid[N]=h local function d(C,d)h._modeMaid=nil if C then local d=F.new()h._modeMaid=d N(C,d)end end h:GiveTask(C._activeMode.Changed:Connect(d))d(C._activeMode.Value,nil)return C end function d._addInputMode(C,N)assert(not C._maid[N])C._maid[N]=N.Enabled:Connect(function()C._activeMode.Value=N end)if not C._activeMode.Value then C._activeMode.Value=N elseif N:GetLastEnabledTime()>C._activeMode.Value:GetLastEnabledTime()then C._activeMode.Value=N end end function d.Destroy(N)N._maid:DoCleaning()end return d
-- Selects the most recent input mode and attempts to
-- identify the best state from it
-- @classmod InputModeSelector

local require = require(game:GetService("ReplicatedStorage"):WaitForChild("Nevermore"))

local INPUT_MODES = require("INPUT_MODES")
local Maid = require("Maid")
local ValueObject = require("ValueObject")

local InputModeSelector = {}
InputModeSelector.ClassName = "InputModeSelector"
InputModeSelector.INPUT_MODES = INPUT_MODES
InputModeSelector.DEFAULT_MODES = {
	INPUT_MODES.Gamepads,
	INPUT_MODES.Keyboard,
	INPUT_MODES.Touch
}

function InputModeSelector.new(inputModes)
	local self = setmetatable({}, InputModeSelector)

	self._maid = Maid.new()

	self._activeMode = ValueObject.new()
	self.Changed = self._activeMode.Changed

	self._maid:GiveTask(self._activeMode)

	for _, inputMode in pairs(inputModes or InputModeSelector.DEFAULT_MODES) do
		self:_addInputMode(inputMode)
	end

	return self
end

function InputModeSelector:__index(index)
	if index == "Value" then
		return rawget(self, "_activeMode").Value
	elseif InputModeSelector[index] then
		return InputModeSelector[index]
	else
		local value = rawget(self, index)
		if value then
			return value
		else
			error(("[InputModeSelector] - Bad index '%s'"):format(tostring(index)))
		end
	end
end

function InputModeSelector:Bind(updateBindFunction)
	local maid = Maid.new()
	self._maid[updateBindFunction] = maid

	local function onChange(newMode, oldMode)
		maid._modeMaid = nil

		if newMode then
			local modeMaid = Maid.new()
			maid._modeMaid = modeMaid
			updateBindFunction(newMode, modeMaid)
		end
	end

	maid:GiveTask(self._activeMode.Changed:Connect(onChange))
	onChange(self._activeMode.Value, nil)

	return self
end

function InputModeSelector:_addInputMode(inputMode)
	assert(not self._maid[inputMode])

	self._maid[inputMode] = inputMode.Enabled:Connect(function()
		self._activeMode.Value = inputMode
	end)

	if not self._activeMode.Value then
		self._activeMode.Value = inputMode
	elseif inputMode:GetLastEnabledTime() > self._activeMode.Value:GetLastEnabledTime() then
		self._activeMode.Value = inputMode
	end
end

function InputModeSelector:Destroy()
	self._maid:DoCleaning()
end

return InputModeSelector