// Project Lab - NHTV Igad

#include "UnrealProject.h"
#include "MenuScreen.h"
#include "ButtonHintBar.h"
#include "SubMenu.h"
#include "MenuButton.h"

void UMenuScreen::NativeConstruct()
{
	Super::NativeConstruct();
	m_sideViewActive = false;
	m_buttonHintBar = Cast<UButtonHintBar>(WidgetTree->FindWidget("ButtonHintBar"));
	m_menuContainer = Cast<UOverlay>(WidgetTree->FindWidget("MenuContainer"));
	m_sideViewContainer = Cast<UOverlay>(WidgetTree->FindWidget("SideViewContainer"));
	m_menuTitle = Cast<UTextBlock>(WidgetTree->FindWidget("MenuTitle"));
	m_sideViewTitle = Cast<UTextBlock>(WidgetTree->FindWidget("SideViewTitle"));
}

UMenuPanel* UMenuScreen::OpenScreenMenu(TSubclassOf<UMenuPanel> cls)
{
	UMenuPanel* menu = CreateWidget<UMenuPanel>(GetWorld(), cls);
	if(!menu)
	{
		GERROR("Failed to create menu for screen " + GetName());
		return nullptr;
	}

	m_menuContainer->AddChildToOverlay(menu);
	OpenSubMenu(menu);

	menu->FadeIn();

	return menu;
}
USideView* UMenuScreen::OpenSideView(TSubclassOf<class USideView> cls)
{
	USideView* view = CreateWidget<USideView>(GetWorld(), cls);
	if(!view)
	{
		GERROR("Failed to create side view for screen " + GetName());
		return nullptr;
	}
	UPersistentSideView* pview = Cast<UPersistentSideView>(view);

	UOverlaySlot* slot = m_sideViewContainer->AddChildToOverlay(view);
	slot->SetHorizontalAlignment(HAlign_Fill);
	slot->SetVerticalAlignment(VAlign_Fill);
	
	if(pview)
		m_OpenSubMenu(view, false);
	else
		OpenSubMenu(view);

	view->FadeIn();

	// Switch side view active event
	if(!m_sideViewActive)
	{
		SwitchSideViewVisible(true);
		m_sideViewActive = true;
	}

	return view;
}

void UMenuScreen::CloseAllSideViews()
{
	TArray<USideView*> viewsToRemove;
	for(int32 i = 0; i < m_sideViewContainer->GetChildrenCount(); i++)
	{
		USideView* sv = Cast<USideView>(m_sideViewContainer->GetChildAt(i));
		if(sv && !sv->IsA<UPersistentSideView>())
			viewsToRemove.Add(sv);
	}

	for(USideView* sv : viewsToRemove)
	{
		CloseSubMenu(sv);
	}
}

void UMenuScreen::OpenPersistentSideView(UPersistentSideView* sideView)
{
	UMenuScreen::OpenSubMenu(sideView);
}
void UMenuScreen::ClosePersistentSideView(UPersistentSideView* sideView)
{
	m_CloseSubMenu(sideView, true);
}

void UMenuScreen::OpenSubMenu(class USubMenu* submenu)
{
	m_OpenSubMenu(submenu);
}
void UMenuScreen::CloseSubMenu(class USubMenu* submenu) 
{
	m_CloseSubMenu(submenu);
}

void UMenuScreen::m_OpenSubMenu(class USubMenu* submenu, bool transferFocus)
{
	CloseAllSideViews();

	if(transferFocus)
		Super::OpenSubMenu(submenu);
	UMenuScreenSubMenu* mssm = Cast<UMenuScreenSubMenu>(submenu);
	if(!m_menuTitle || !mssm)
		return;

	// Update titles and sub-titles
	UMenuPanel* panel = Cast<UMenuPanel>(submenu);
	if(panel)
		m_menuTitle->SetText(FText::FromString(mssm->menuName));
	USideView* view = Cast<USideView>(submenu);
	if(view)
	{
		m_sideViewTitle->SetText(FText::FromString(mssm->menuName));
		m_currentSideViews.Add(view);
	}
}
void UMenuScreen::m_CloseSubMenu(class USubMenu* submenu, bool persist)
{
	UMenuScreenSubMenu* mssm = Cast<UMenuScreenSubMenu>(submenu);
	if(mssm)
		mssm->m_isBeingClosed = true;
	UMenuPanel* panel = Cast<UMenuPanel>(submenu);
	if(panel)
	{
		CloseAllSideViews();
		panel->onAnimationEnded.RemoveAll(this);
		panel->onAnimationEnded.AddUObject(this, &UMenuScreen::m_OnFadeOutComplete);
		panel->FadeOut();
	}
	USideView* view = Cast<USideView>(submenu);
	if(view && !persist)
	{
		view->onAnimationEnded.RemoveAll(this);
		view->onAnimationEnded.AddUObject(this, &UMenuScreen::m_OnFadeOutComplete);
		view->FadeOut();

		// Switch side view active event
		if(m_currentSideViews.Num() > 0 && m_sideViewActive)
		{
			SwitchSideViewVisible(false);
			m_sideViewActive = false;
		}

		m_currentSideViews.Remove(view);
	}

	Super::CloseSubMenu(submenu);

	// Update titles and sub-titles
	if(panel)
	{
		if(m_subMenus.Num() > 0)
		{
			UMenuPanel* newMenu = Cast<UMenuPanel>(m_subMenus.Last());
			if(newMenu)
				m_menuTitle->SetText(FText::FromString(newMenu->menuName));
			else
				goto _set_no_panel_text;
		}
		else
		{
		_set_no_panel_text:
			m_menuTitle->SetText(FText());
		}
	}
	else if(view && !persist)
	{
		if(m_subMenus.Num() > 0)
		{
			USideView* newMenu = Cast<USideView>(m_subMenus.Last());
			if(newMenu)
				m_sideViewTitle->SetText(FText::FromString(newMenu->menuName));
			else
				goto _set_no_view_text;
		}
		else
		{
		_set_no_view_text:
			m_sideViewTitle->SetText(FText());
		}
	}
	if(mssm)
		mssm->m_isBeingClosed = false;
}

void UMenuScreen::m_OnFadeOutComplete(UMenuScreenSubMenu* panel, int32 type)
{
	if(type == 2) // Fade Out
	{
		panel->RemoveFromParent();
	}
}

static float animationDuration = 0.35f;
void UMenuScreenSubMenu::NativeConstruct()
{
	m_animationType = 0;
	m_animationTime = 0.0f;
	m_isBeingClosed = false;
	Super::NativeConstruct();
}
UMenuScreenSubMenu::UMenuScreenSubMenu(const FObjectInitializer& init)
	: Super(init)
{
	menuName = "<Unnamed Menu!>";
}
void UMenuScreenSubMenu::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
{
	Super::NativeTick(MyGeometry, InDeltaTime);

	float r = FMath::Clamp(m_animationTime / animationDuration, 0.0f, 1.0f);
	if(m_animationType == 1) // Fade In
	{
		SetRenderTranslation(FVector2D(0.0f - ((1.0f - r)*(1.0f - r)) * 100.0f, 0.0f));
		FLinearColor color = FLinearColor(1.0f, 1.0f, 1.0f, r);
		SetColorAndOpacity(color);
	}
	else if(m_animationType == 2) // Fade Out
	{
		SetRenderTranslation(FVector2D(0.0f + (r*r) * 100.0f, 0.0f));
		FLinearColor color = FLinearColor(1.0f, 1.0f, 1.0f, (1.0f-r));
		SetColorAndOpacity(color);
	}

	if(m_animationType != 0)
	{
		if(r >= 1.0f)
		{
			onAnimationEnded.Broadcast(this, m_animationType);
			m_animationType = 0;
		}
		m_animationTime += InDeltaTime;
	}
}

void UMenuScreenSubMenu::OnSuspend(USubMenu* newSubMenu, bool loseFocus)
{
	// Don't fade out / lose focus when side view is opened
	USideView* sv = Cast<USideView>(newSubMenu);

	if(sv)
		loseFocus = false;
	else
		FadeOut();
	Super::OnSuspend(newSubMenu, loseFocus);
}
void UMenuScreenSubMenu::OnRestore(USubMenu* removedMenu)
{
	// To prevent playing the fade in animation again when we receive focus from closing side views when we are actually closing this menu
	if(!m_isBeingClosed && !Cast<USideView>(removedMenu))
		FadeIn();
	Super::OnRestore(removedMenu);
}

void UMenuScreenSubMenu::FadeIn()
{
	m_animationTime = 0.0f;
	m_animationType = 1;
}
void UMenuScreenSubMenu::FadeOut()
{
	m_animationTime = 0.0f;
	m_animationType = 2;
}
UMenuPanel* UMenuScreenSubMenu::OpenScreenMenu(TSubclassOf<class UMenuPanel> cls)
{
	UMenuScreen* screen = Cast<UMenuScreen>(GetScreen());
	if(screen)
	{
		return screen->OpenScreenMenu(cls);
	}
	return nullptr;
}
USideView* UMenuScreenSubMenu::OpenSideView(TSubclassOf<class USideView> cls)
{
	UMenuScreen* screen = Cast<UMenuScreen>(GetScreen());
	if(screen)
	{
		screen->CloseAllSideViews();
		return screen->OpenSideView(cls);
	}
	return nullptr;
}

class UMenuButton* UMenuScreenSubMenu::AddButton(FString label)
{
	if(!container)
		return nullptr;

	UMenuButton* button = CreateWidget<UMenuButton>(GetWorld(), defaultButtonClass);
	if(!button)
		return nullptr;

	container->AddChild(button);
	RescanItems();

	button->SetButtonText(label);

	return button;
}

void UMenuScreenSubMenu::RescanItems()
{
	m_backButton = nullptr;

	Super::RescanItems();

	for(UMenuItemBase* item : m_items)
	{
		UMenuButton* button = Cast<UMenuButton>(item);
		if(button)
		{
			if(button->GetName() == "Back")
			{
				m_backButton = button;
				break;
			}
		}
	}
}
void UMenuScreenSubMenu::NativeOnMenuAction(EMenuActionBinding binding)
{
	Super::NativeOnMenuAction(binding);
	if(binding == EMenuActionBinding::Back)
	{
		if(m_backButton)
		{
			m_backButton->SimulatePressed();
		}
	}
}

