// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.

#include "PolishBuildingsPrivatePCH.h"
#include "SPolishBuildingsToolbar.h"
#include "ModuleManager.h"
#include "WorkspaceMenuStructureModule.h"
#include "PolishBuildingsTool.h"
#include "BuildingsProxyTool.h"
#include "SDockTab.h"

#define LOCTEXT_NAMESPACE "PolishBuildingsModule"


static const FName PolishBuildingsTabName = FName("PolishBuildings");

/**
 * Merge Actors module
 */
class FPolishBuildingsModule : public IPolishBuildingsModule
{
public:

	/**
	 * Called right after the module DLL has been loaded and the module object has been created
	 */
	virtual void StartupModule() override;

	/**
	 * Called before the module is unloaded, right before the module object is destroyed.
	 */
	virtual void ShutdownModule() override;

	/**
	 * Register an IPolishBuildingsTool with the module, passing ownership to it
	 */
	virtual bool RegisterPolishBuildingsTool(TUniquePtr<IPolishBuildingsTool> Tool) override;

	/**
	 * Unregister an IPolishBuildingsTool with the module
	 */
	virtual bool UnregisterPolishBuildingsTool(IPolishBuildingsTool* Tool) override;


private:

	/** Creates the dock tab widget used by the tab manager */
	TSharedRef<SDockTab> CreatePolishBuildingsTab(const FSpawnTabArgs& Args);

private:

	/** Pointer to the toolbar widget */
	TWeakPtr<SPolishBuildingsToolbar> PolishBuildingsToolbarPtr;

	/** List of registered PolishBuildingsTool instances */
	TArray<TUniquePtr<IPolishBuildingsTool>> PolishBuildingsTools;
};

IMPLEMENT_MODULE(FPolishBuildingsModule, PolishBuildings);


TSharedRef<SDockTab> FPolishBuildingsModule::CreatePolishBuildingsTab(const FSpawnTabArgs& Args)
{
	// Build array of PolishBuildingsTool raw pointers
	TArray<IPolishBuildingsTool*> ToolsToRegister;
	for (const auto& MergeActorTool : PolishBuildingsTools)
	{
		check(MergeActorTool.Get() != nullptr);
		ToolsToRegister.Add(MergeActorTool.Get());
	}

	// Construct toolbar widget
	TSharedRef<SPolishBuildingsToolbar> PolishBuildingsToolbar =
		SNew(SPolishBuildingsToolbar)
		.ToolsToRegister(ToolsToRegister);

	// Construct dock tab
	TSharedRef<SDockTab> DockTab =
		SNew(SDockTab)
		.TabRole(ETabRole::NomadTab)
		[
			PolishBuildingsToolbar
		];

	// Keep weak pointer to toolbar widget
	PolishBuildingsToolbarPtr = PolishBuildingsToolbar;

	return DockTab;
}


void FPolishBuildingsModule::StartupModule()
{
	FGlobalTabmanager::Get()->RegisterNomadTabSpawner(PolishBuildingsTabName, FOnSpawnTab::CreateRaw(this, &FPolishBuildingsModule::CreatePolishBuildingsTab))
		.SetDisplayName(LOCTEXT("TabTitle", "Polish Buildings"))
		.SetTooltipText(LOCTEXT("TooltipText", "Open the Polish Buildings tab."))
		.SetGroup(WorkspaceMenu::GetMenuStructure().GetLevelEditorCategory())
		.SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "ClassViewer.TabIcon"));
		// This is still experimental in the editor, so it's added specifically in FMainMenu for now.
		// When no longer experimental, remove the below.
		//.SetAutoGenerateMenuEntry(false);

	// Register built-in merging tools straight away
	ensure(RegisterPolishBuildingsTool(MakeUnique<FPolishBuildingsTool>()));

	IMeshUtilities* MeshUtilities = FModuleManager::Get().LoadModulePtr<IMeshUtilities>("MeshUtilities");
	if (MeshUtilities != nullptr && MeshUtilities->GetMeshMergingInterface() != nullptr)
	{
		// Only register BuildingsProxyTool if Simplygon is available
		ensure(RegisterPolishBuildingsTool(MakeUnique<FBuildingsProxyTool>()));
	}
}


void FPolishBuildingsModule::ShutdownModule()
{
	if (FSlateApplication::IsInitialized())
	{
		FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(PolishBuildingsTabName);
	}
}


bool FPolishBuildingsModule::RegisterPolishBuildingsTool(TUniquePtr<IPolishBuildingsTool> Tool)
{
	if (Tool.Get() != nullptr && !PolishBuildingsTools.Contains(MoveTemp(Tool)))
	{
		PolishBuildingsTools.Add(MoveTemp(Tool));
		
		// If a tool is added while the toolbar widget is active, update it accordingly
		TSharedPtr<SPolishBuildingsToolbar> PolishBuildingsToolbar = PolishBuildingsToolbarPtr.Pin();
		if (PolishBuildingsToolbar.IsValid())
		{
			PolishBuildingsToolbar->AddTool(Tool.Get());
		}

		return true;
	}

	return false;
}


bool FPolishBuildingsModule::UnregisterPolishBuildingsTool(IPolishBuildingsTool* Tool)
{
	if (Tool != nullptr)
	{
		if (PolishBuildingsTools.RemoveAll([=](const TUniquePtr<IPolishBuildingsTool>& Ptr) { return Ptr.Get() == Tool; }) > 0)
		{
			TSharedPtr<SPolishBuildingsToolbar> PolishBuildingsToolbar = PolishBuildingsToolbarPtr.Pin();
			if (PolishBuildingsToolbar.IsValid())
			{
				PolishBuildingsToolbar->RemoveTool(Tool);
			}

			return true;
		}
	}
	return false;
}


#undef LOCTEXT_NAMESPACE
