
#include "InputDeviceTracker.h"
#include "Framework/Application/SlateApplication.h"
#include "GenericPlatform/GenericApplicationMessageHandler.h"
#include "InputCoreTypes.h"

// Last observed device classification. Read with no
// synchronization; updates happen on the game thread
// from Slate's input pipeline, and stale reads on
// other threads are acceptable for this use case.
//
static ElxControllerType GLastControllerType = ElxControllerType::KeyboardMouse;

// Keywords identifying a PlayStation-family gamepad.
// Matched case-insensitively against the InputDeviceName
// and HardwareDeviceIdentifier fields of the current
// FInputDeviceScope.
//
static const TCHAR* const PlaystationKeywords[] = {
	TEXT("Playstation"),
	TEXT("PS3"),
	TEXT("PS4"),
	TEXT("PS5"),
	TEXT("PS6"),
	TEXT("PS7"),
	TEXT("Dualsense"),
	TEXT("Dualshock"),
};

namespace
{
	bool ContainsAnyPlaystationKeyword(const FString& Haystack)
	{
		for (const TCHAR* Keyword : PlaystationKeywords)
		{
			if (Haystack.Contains(Keyword, ESearchCase::IgnoreCase))
			{
				return true;
			}
		}
		return false;
	}

	// Classifies the active gamepad by scanning the current
	// FInputDeviceScope. Defaults to Xbox; switches to
	// PlayStation only on a keyword match.
	//
	ElxControllerType ClassifyGamepadFromScope()
	{
		const FInputDeviceScope* Scope = FInputDeviceScope::GetCurrent();
		if (Scope != nullptr)
		{
			if (ContainsAnyPlaystationKeyword(Scope->InputDeviceName.ToString()) ||
				ContainsAnyPlaystationKeyword(Scope->HardwareDeviceIdentifier))
			{
				return ElxControllerType::PlayStationGamepad;
			}
		}
		return ElxControllerType::XboxGamepad;
	}
}

bool FInputDeviceTrackerProcessor::HandleKeyDownEvent(FSlateApplication& SlateApp, const FKeyEvent& KeyEvent)
{
	if (KeyEvent.GetKey().IsGamepadKey())
	{
		GLastControllerType = ClassifyGamepadFromScope();
	}
	else
	{
		GLastControllerType = ElxControllerType::KeyboardMouse;
	}
	return false;
}

bool FInputDeviceTrackerProcessor::HandleMouseButtonDownEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent)
{
	GLastControllerType = ElxControllerType::KeyboardMouse;
	return false;
}

void UlxInputDeviceTracker::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);
	if (FSlateApplication::IsInitialized())
	{
		Processor = MakeShared<FInputDeviceTrackerProcessor>();
		FSlateApplication::Get().RegisterInputPreProcessor(Processor);
	}
}

void UlxInputDeviceTracker::Deinitialize()
{
	if (Processor.IsValid() && FSlateApplication::IsInitialized())
	{
		FSlateApplication::Get().UnregisterInputPreProcessor(Processor);
	}
	Processor.Reset();
	Super::Deinitialize();
}

ElxControllerType UlxInputDeviceTracker::GetLastControllerType()
{
	return GLastControllerType;
}
