--	elseif input.UserInputType == self.activeGamepad and input.KeyCode == Enum.KeyCode.ButtonL3 then
--		if (state == Enum.UserInputState.Begin) then
--			self.L3ButtonDown = true
--		elseif (state == Enum.UserInputState.End) then
--			self.L3ButtonDown = false
--			self.currentZoomSpeed = 1.00
--		end
--	end

end

function BaseCamera:DoKeyboardZoom(name, state, input)
	if not self.hasGameLoaded and VRService.VREnabled then
		return Enum.ContextActionResult.Pass
	end

	if state ~= Enum.UserInputState.Begin then 
		return Enum.ContextActionResult.Pass
	end

	if self.distanceChangeEnabled then
		if input.KeyCode == Enum.KeyCode.I then
			self:SetCameraToSubjectDistance( self.currentSubjectDistance - 5 )
		elseif input.KeyCode == Enum.KeyCode.O then
			self:SetCameraToSubjectDistance( self.currentSubjectDistance + 5 )
		end
		return Enum.ContextActionResult.Sink
	end
	return Enum.ContextActionResult.Pass
end

function BaseCamera:BindAction(actionName, actionFunc, createTouchButton, ...)
	table.insert(self.boundContextActions, actionName)
	ContextActionService:BindActionAtPriority(actionName, actionFunc, createTouchButton, 
		CAMERA_ACTION_PRIORITY, ...)
end

function BaseCamera:BindGamepadInputActions()
	if FFlagPlayerScriptsBindAtPriority then 
		self:BindAction("BaseCameraGamepadPan", function(name, state, input) return self:GetGamepadPan(name, state, input) end,
			false, Enum.KeyCode.Thumbstick2)
		self:BindAction("BaseCameraGamepadZoom", function(name, state, input) return self:DoGamepadZoom(name, state, input) end,
			false, Enum.KeyCode.DPadLeft, Enum.KeyCode.DPadRight, Enum.KeyCode.ButtonR3)
	else 
		ContextActionService:BindAction("RootCamGamepadPan", function(name, state, input) self:GetGamepadPan(name, state, input) end, false, Enum.KeyCode.Thumbstick2)
		ContextActionService:BindAction("RootCamGamepadZoom", function(name, state, input) self:DoGamepadZoom(name, state, input) end, false, Enum.KeyCode.ButtonR3)
		--ContextActionService:BindAction("RootGamepadZoomAlt", function(name, state, input) self:DoGamepadZoom(name, state, input) end, false, Enum.KeyCode.ButtonL3)
		ContextActionService:BindAction("RootGamepadZoomOut", function(name, state, input) self:DoGamepadZoom(name, state, input) end, false, Enum.KeyCode.DPadLeft)
		ContextActionService:BindAction("RootGamepadZoomIn", function(name, state, input) self:DoGamepadZoom(name, state, input) end, false, Enum.KeyCode.DPadRight)
	end
end

function BaseCamera:BindKeyboardInputActions()
	self:BindAction("BaseCameraKeyboardPanArrowKeys", function(name, state, input) return self:DoKeyboardPanTurn(name, state, input) end,
		false, Enum.KeyCode.Left, Enum.KeyCode.Right)
	self:BindAction("BaseCameraKeyboardPan", function(name, state, input) return self:DoKeyboardPan(name, state, input) end,
		false, Enum.KeyCode.Comma, Enum.KeyCode.Period, Enum.KeyCode.PageUp, Enum.KeyCode.PageDown)
	self:BindAction("BaseCameraKeyboardZoom", function(name, state, input) return self:DoKeyboardZoom(name, state, input) end,
		false, Enum.KeyCode.I, Enum.KeyCode.O)
end

function BaseCamera:OnTouchBegan(input, processed)
	local canUseDynamicTouch = self.isDynamicThumbstickEnabled and not processed
	if canUseDynamicTouch then
		self.fingerTouches[input] = processed
		if not processed then
			self.inputStartPositions[input] = input.Position
			self.inputStartTimes[input] = tick()
			self.numUnsunkTouches = self.numUnsunkTouches + 1
		end
	end
end

function BaseCamera:OnTouchChanged(input, processed)
	if self.fingerTouches[input] == nil then
		if self.isDynamicThumbstickEnabled then
			return
		end
		self.fingerTouches[input] = processed
		if not processed then
			self.numUnsunkTouches = self.numUnsunkTouches + 1
		end
	end

	if self.numUnsunkTouches == 1 then
		if self.fingerTouches[input] == false then
			self.panBeginLook = self.panBeginLook or self:GetCameraLookVector()
			self.startPos = self.startPos or input.Position
			self.lastPos = self.lastPos or self.startPos
			self.userPanningTheCamera = true

			local delta = input.Position - self.lastPos
			delta = Vector2.new(delta.X, delta.Y * UserGameSettings:GetCameraYInvertValue())
			if self.panEnabled then
				local desiredXYVector = self:InputTranslationToCameraAngleChange(delta, TOUCH_SENSITIVTY)
				self.rotateInput = self.rotateInput + desiredXYVector
			end
			self.lastPos = input.Position
		end
	else
		self.panBeginLook = nil
		self.startPos = nil
		self.lastPos = nil
		self.userPanningTheCamera = false
	end
	if self.numUnsunkTouches == 2 then
		local unsunkTouches = {}
		for touch, wasSunk in pairs(self.fingerTouches) do
			if not wasSunk then
				table.insert(unsunkTouches, touch)
			end
		end
		if #unsunkTouches == 2 then
			local difference = (unsunkTouches[1].Position - unsunkTouches[2].Position).magnitude
			if self.startingDiff and self.pinchBeginZoom then
				local scale = difference / math.max(0.01, self.startingDiff)
				local clampedScale = Util.Clamp(0.1, 10, scale)
				if self.distanceChangeEnabled then
					self:SetCameraToSubjectDistance(self.pinchBeginZoom / clampedScale)
				end
			else
				self.startingDiff = difference
				self.pinchBeginZoom = self:GetCameraToSubjectDistance()
			end
		end
	else
		self.startingDiff = nil
		self.pinchBeginZoom = nil
	end	
end

function BaseCamera:CalcLookBehindRotateInput()
	if not self.humanoidRootPart or not game.Workspace.CurrentCamera then
		return nil
	end

	local cameraLookVector = game.Workspace.CurrentCamera.CFrame.lookVector
	local newDesiredLook = (self.humanoidRootPart.CFrame.lookVector - Vector3.new(0,0.23,0)).unit
	local horizontalShift = Util.GetAngleBetweenXZVectors(newDesiredLook, cameraLookVector)
	local vertShift = math.asin(cameraLookVector.Y) - math.asin(newDesiredLook.Y)
	if not Util.IsFinite(horizontalShift) then
		horizontalShift = 0
	end
	if not Util.IsFinite(vertShift) then
		vertShift = 0
	end

	return Vector2.new(horizontalShift, vertShift)
end

function BaseCamera:OnTouchTap(position)
	if self.isDynamicThumbstickEnabled and not self.isAToolEquipped then
		if self.lastTapTime and tick() - self.lastTapTime < MAX_TIME_FOR_DOUBLE_TAP then
			self:SetCameraToSubjectDistance(self.defaultSubjectDistance)
		else
			if self.humanoidRootPart then
				self.rotateInput = self:CalcLookBehindRotateInput()
			end
		end
		self.lastTapTime = tick()
	end
end

function BaseCamera:IsTouchTap(input)
	-- We can't make the assumption that the input exists in the inputStartPositions because we may have switched from a different camera type.
	if self.inputStartPositions[input] then
		local posDelta = (self.inputStartPositions[input] - input.Position).magnitude
		if posDelta < MAX_TAP_POS_DELTA then
			local timeDelta = self.inputStartTimes[input] - tick()
			if timeDelta < MAX_TAP_TIME_DELTA then
				return true
			end
		end
	end
	return false
end

function BaseCamera:OnTouchEnded(input, processed)
	if self.fingerTouches[input] == false then
		if self.numUnsunkTouches == 1 then
			self.panBeginLook = nil
			self.startPos = nil
			self.lastPos = nil
			self.userPanningTheCamera = false
			if self:IsTouchTap(input) then
				self:OnTouchTap(input.Position)
			end
		elseif self.numUnsunkTouches == 2 then
			self.startingDiff = nil
			self.pinchBeginZoom = nil
		end
	end

	if self.fingerTouches[input] ~= nil and self.fingerTouches[input] == false then
		self.numUnsunkTouches = self.numUnsunkTouches - 1
	end
	self.fingerTouches[input] = nil
	self.inputStartPositions[input] = nil
	self.inputStartTimes[input] = nil
end

function BaseCamera:OnMouse2Down(input, processed)
	if processed then return end

	self.isRightMouseDown = true
	self:OnMousePanButtonPressed(input, processed)
end

function BaseCamera:OnMouse2Up(input, processed)
	self.isRightMouseDown = false
	self:OnMousePanButtonReleased(input, processed)
end

function BaseCamera:OnMouse3Down(input, processed)
	if processed then return end

	self.isMiddleMouseDown = true
	self:OnMousePanButtonPressed(input, processed)
end

function BaseCamera:OnMouse3Up(input, processed)
	self.isMiddleMouseDown = false
	self:OnMousePanButtonReleased(input, processed)
end

function BaseCamera:OnMouseMoved(input, processed)
	if not self.hasGameLoaded and VRService.VREnabled then
		return
	end

	local inputDelta = input.Delta
	inputDelta = Vector2.new(inputDelta.X, inputDelta.Y * UserGameSettings:GetCameraYInvertValue())

	if self.panEnabled and ((self.startPos and self.lastPos and self.panBeginLook) or self.inFirstPerson or self.inMouseLockedMode) then
		local desiredXYVector = self:InputTranslationToCameraAngleChange(inputDelta,MOUSE_SENSITIVITY)
		self.rotateInput = self.rotateInput + desiredXYVector
	end

	if self.startPos and self.lastPos and self.panBeginLook then
		self.lastPos = self.lastPos + input.Delta
	end
end

function BaseCamera:OnMousePanButtonPressed(input, processed)
	if processed then return end
	self:UpdateMouseBehavior()
	self.panBeginLook = self.panBeginLook or self:GetCameraLookVector()
	self.startPos = self.startPos or input.Position
	self.lastPos = self.lastPos or self.startPos
	self.userPanningTheCamera = true
end

function BaseCamera:OnMousePanButtonReleased(input, processed)
	self:UpdateMouseBehavior()
	if not (self.isRightMouseDown or self.isMiddleMouseDown) then
		self.panBeginLook = nil
		self.startPos = nil
		self.lastPos = nil
		self.userPanningTheCamera = false
	end
end

function BaseCamera:OnMouseWheel(input, processed)
	if not self.hasGameLoaded and VRService.VREnabled then
		return
	end
	if not processed then
		if self.distanceChangeEnabled then
			local wheelInput = Util.Clamp(-1, 1, -input.Position.Z)

			local newDistance
			if self.inFirstPerson and wheelInput > 0 then
				newDistance = FIRST_PERSON_DISTANCE_THRESHOLD
			else
				-- The 0.156 and 1.7 values are the slope and intercept of a line that is replacing the old
				-- rk4Integrator function which was not being used as an integrator, only to get a delta as a function of distance,
				-- which was linear as it was being used. These constants preserve the status quo behavior.
				newDistance = self.currentSubjectDistance + 0.156 * self.currentSubjectDistance * wheelInput + 1.7 * math.sign(wheelInput)
			end

			self:SetCameraToSubjectDistance(newDistance)
		end
	end
end
