////////////////////////////////////////////////////////////
//
// RootCanvas.cpp
//
////////////////////////////////////////////////////////////

#include "RootCanvas.h"
#include "Common.h"
#include "Blueprint/UserWidget.h"

UlxRootCanvasSlot::UlxRootCanvasSlot(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	// Children of the root canvas default to filling the parent,
	// matching the viewport's "stretch" behavior. Individual widgets
	// can still override anchors/offsets after being added.
	SetAnchors(FAnchors(0.0f, 0.0f, 1.0f, 1.0f));
	SetOffsets(FMargin(0.0f, 0.0f, 0.0f, 0.0f));
}


UClass* UlxRootCanvasPanel::GetSlotClass() const
{
	return UlxRootCanvasSlot::StaticClass();
}

UlxRootCanvasSlot *UlxRootCanvasPanel::GetRootCanvasSlot(UUserWidget *Widget, ElxSuccessOrWrongType &Result)
{
	if (IsValid(Widget))
	{
		if (UlxRootCanvasSlot *Slot = Cast<UlxRootCanvasSlot>(Widget->Slot))
		{
			Result = ElxSuccessOrWrongType::Success;
			return Slot;
		}
	}
	Result = ElxSuccessOrWrongType::WrongType;
	return nullptr;
}

UlxRootCanvasSlot* UlxRootCanvasPanel::AddChildToRootCanvas(UWidget* Content)
{
	return Cast<UlxRootCanvasSlot>(Super::AddChild(Content));
}

void UlxRootCanvasPanel::OnSlotAdded(UPanelSlot* InSlot)
{
	UlxRootCanvasSlot *Slot = CastChecked<UlxRootCanvasSlot>(InSlot);
	Slot->BringToFrontCount = ++BringToFrontCounter;
	Super::OnSlotAdded(InSlot);
}


UlxRootCanvasSlot* UlxRootCanvasPanel::GetTopWidget()
{
	UlxRootCanvasSlot* Top = nullptr;
	for (UPanelSlot* PanelSlot : Slots)
	{
		UlxRootCanvasSlot* Slot = CastChecked<UlxRootCanvasSlot>(PanelSlot);
		if (Cast<UUserWidget>(Slot->Content) == nullptr) continue;
		if ((Top == nullptr) || (*Top < *Slot)) Top = Slot;
	}
	return Top;
}

TArray<UlxRootCanvasSlot*> UlxRootCanvasPanel::GetSortedUserWidgets()
{
	TArray<UlxRootCanvasSlot*> Result;
	Result.Reserve(Slots.Num());
	for (UPanelSlot *PanelSlot : Slots)
	{
		UlxRootCanvasSlot *TypedSlot = Cast<UlxRootCanvasSlot>(PanelSlot);
		check(TypedSlot);
		if (Cast<UUserWidget>(TypedSlot->Content) == nullptr) continue;
		Result.Add(TypedSlot);
	}
	Result.StableSort([](const UlxRootCanvasSlot &A, const UlxRootCanvasSlot &B)
	{
		return A < B;
	});
	return Result;
}


void UlxRootCanvasPanel::UpdateZOrders()
{
	for (UPanelSlot *PanelSlot : Slots)
	{
		UlxRootCanvasSlot *Slot = Cast<UlxRootCanvasSlot>(PanelSlot);
		check(Slot);
		int32 ZOrder = (Slot->ShowPointer ? 1000000 : 0) + Slot->BringToFrontCount;
		Slot->SetZOrder(ZOrder);
	}
}

void UlxRootCanvasPanel::BringToFront(UUserWidget *Widget)
{
	if (!IsValid(Widget)) return;
	UlxRootCanvasSlot *Slot = Cast<UlxRootCanvasSlot>(Widget->Slot);
	if (!Slot) return;
	UlxRootCanvasPanel *Panel = Cast<UlxRootCanvasPanel>(Slot->Parent);
	if (!Panel) return;
	Slot->BringToFrontCount = ++Panel->BringToFrontCounter;
}

void UlxRootCanvasPanel::SetWidgetWindowManagement(class UUserWidget *Widget,
		bool ShowPointer, bool BlockInput, bool EnableEnhancedInput, bool BringToFront, UWidget *DesiredFocusWidget)
{
	if (!IsValid(Widget))
	{
		UE_LOG(LogLuprexIntegration, Error, TEXT("ManageRootWidget called with an invalid widget."));
		return;
	}
	UlxRootCanvasSlot *Slot = Cast<UlxRootCanvasSlot>(Widget->Slot);
	if (Slot == nullptr)
	{
		UE_LOG(LogLuprexIntegration, Error, TEXT("Widget is not yet a root widget, use 'AddWidgetToRoot' first"));
		return;
	}
	UlxRootCanvasPanel *Panel = Cast<UlxRootCanvasPanel>(Slot->Parent);
	check(Panel);
	Slot->ShowPointer = ShowPointer;
	Slot->BlockInput = BlockInput;
	Slot->EnableEnhancedInput = EnableEnhancedInput;
	if (DesiredFocusWidget)
	{
		if (!Widget->SetDesiredFocusWidget(DesiredFocusWidget))
			UE_LOG(LogLuprexIntegration, Error, TEXT("SetWidgetWindowManagement: focus widget must be a child of widget"));
	}
	else
	{
		Widget->SetDesiredFocusWidget(NAME_None);
	}
	if (BringToFront) Slot->BringToFrontCount = ++Panel->BringToFrontCounter;
}

