// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.

#include "ComboActionGraphLayoutStrategy.h"

#include "Ed/EdComboActionGraph.h"
#include "Ed/EdComboActionGraphNode.h"
#include "Ed/SEdComboActionGraphNode.h"
#include "Nodes/ComboActionGraphNode.h"

#include "Kismet/KismetMathLibrary.h"


UComboActionGraphLayoutStrategy::UComboActionGraphLayoutStrategy()
{
	Settings = nullptr;
	MaxIteration = 50;
	OptimalDistance = 150;
}

int32 UComboActionGraphLayoutStrategy::GetNodeWidth(UEdComboActionGraphNode *EdNode)
{
	return EdNode->SEdNode->GetCachedGeometry().GetLocalSize().X;
}

int32 UComboActionGraphLayoutStrategy::GetNodeHeight(UEdComboActionGraphNode *EdNode)
{
	return EdNode->SEdNode->GetCachedGeometry().GetLocalSize().Y;
}

FBox2D UComboActionGraphLayoutStrategy::GetNodeBound(UEdGraphNode* EdNode)
{
	int32 NodeWidth = GetNodeWidth(Cast<UEdComboActionGraphNode>(EdNode));
	int32 NodeHeight = GetNodeHeight(Cast<UEdComboActionGraphNode>(EdNode));
	FVector2D Min(EdNode->NodePosX, EdNode->NodePosY);
	FVector2D Max(EdNode->NodePosX + NodeWidth, EdNode->NodePosY + NodeHeight);
	return FBox2D(Min, Max);
}

FBox2D UComboActionGraphLayoutStrategy::GetActualBounds(UComboActionGraphNode *RootNode)
{
	int Level = 0;
	TArray<UComboActionGraphNode*> CurrLevelNodes = { RootNode };
	TArray<UComboActionGraphNode*> NextLevelNodes;

	FBox2D Rtn = GetNodeBound(this->EdGraph->NodeMap[RootNode]);

	while (CurrLevelNodes.Num() != 0)
	{
		for (const UComboActionGraphNode *Node : CurrLevelNodes)
		{
			check(Node != nullptr);

			Rtn += GetNodeBound(this->EdGraph->NodeMap[Node]);

			for (UComboActionGraphNode *ChildNode : Node->ChildrenNodes)
			{
				NextLevelNodes.Add(ChildNode);
			}
		}

		CurrLevelNodes = NextLevelNodes;
		NextLevelNodes.Reset();
		++Level;
	}
	return Rtn;
}

void UComboActionGraphLayoutStrategy::RandomLayoutOneTree(UComboActionGraphNode *RootNode, const FBox2D &Bound)
{
	int Level = 0;
	TArray<UComboActionGraphNode*> CurrLevelNodes = { RootNode };
	TArray<UComboActionGraphNode*> NextLevelNodes;

	while (CurrLevelNodes.Num() != 0)
	{
		for (const UComboActionGraphNode *Node : CurrLevelNodes)
		{
			check(Node != nullptr);

			UEdComboActionGraphNode *EdNode_Node = this->EdGraph->NodeMap[Node];

			EdNode_Node->NodePosX = UKismetMathLibrary::RandomFloatInRange(Bound.Min.X, Bound.Max.X);
			EdNode_Node->NodePosY = UKismetMathLibrary::RandomFloatInRange(Bound.Min.Y, Bound.Max.Y);

			for (UComboActionGraphNode *ChildNode : Node->ChildrenNodes)
			{
				NextLevelNodes.Add(ChildNode);
			}
		}

		CurrLevelNodes = NextLevelNodes;
		NextLevelNodes.Reset();
		++Level;
	}
}
