// Copyright (c) Microsoft Corporation. 
// Licensed under the MIT license.

#include "StandInsOutlinerDragDropOp.h"
#include "StandinUtilitiesModule.h"
#include "ITreeItem.h"
#include "TreeItemID.h"

DEFINE_LOG_CATEGORY_STATIC(LogStandinOutlinerDrag, Verbose, All);

StandInsOutliner::FDragDropPayload::FDragDropPayload()
{
	// QQ change this
	StaticMeshActors = TArray<TWeakObjectPtr<AActor>>();
	StandinLODActors = TArray<TWeakObjectPtr<AActor>>();
	TaggedActors = TArray<TWeakObjectPtr<AActor>>();
	bSceneOutliner = false;
}

bool StandInsOutliner::FDragDropPayload::ParseDrag(const FDragDropOperation& Operation)
{
	bool bApplicable = false;

	//is operation from scene outliner or replacement actor outliner
	IStandinUtilitiesModule& Module = IStandinUtilitiesModule::Get();// FModuleManager::Get().LoadModuleChecked<IReplacementVolumeModule>("ReplacementVolumeModule");
	UE_LOG(LogStandinOutlinerDrag, Display, TEXT("LogStandinUtilitiesModule Outliner Drag Parse"));

	if (Operation.IsOfType<FStandInsOutlinerDragDropOp>())
	{
		bApplicable = true;
		bSceneOutliner = false;
		

		const auto& OutlinerOp = static_cast<const FStandInsOutlinerDragDropOp&>(Operation);

		if (OutlinerOp.StaticMeshActorOp.IsValid())
		{
			StaticMeshActors = OutlinerOp.StaticMeshActorOp->Actors;
			UE_LOG(LogStandinOutlinerDrag, Display, TEXT("StandinLODActor DragDrop Op Static Meshes"));
		}

		if (OutlinerOp.StandinActorOp.IsValid())
		{
			StandinLODActors = OutlinerOp.StandinActorOp->Actors;
			UE_LOG(LogStandinOutlinerDrag, Display, TEXT("StandinLODActor DragDrop Op ReplacementActorOp"));
		}
		
	}
	else if (Operation.IsOfType<FActorDragDropGraphEdOp>())
	{
		bSceneOutliner = true;
		bApplicable = true;

		const auto& ActorOp = static_cast<const FActorDragDropGraphEdOp&>(Operation);
		for (auto& ActorPtr : ActorOp.Actors)
		{
			AActor* Actor = ActorPtr.Get();

			if (Module.IsActorValidForStandinInclusion(Actor))
			{
				if (!StaticMeshActors.IsSet())
				{
					StaticMeshActors = TArray<TWeakObjectPtr<AActor>>();
				}
				UE_LOG(LogStandinOutlinerDrag, Display, TEXT("Add StaticMeshActor Drag Parse"));
				StaticMeshActors->Add(Actor);
			}
			else
			{
				// This means we have invalid static mesh actors in the scene outliner selection (could lead to invalid state)
				bApplicable = false;
				break;
			}
			
		}
	}

	return bApplicable;
}

TSharedPtr<FDragDropOperation> StandInsOutliner::CreateDragDropOperation(const TArray<FTreeItemPtr>& InTreeItems)
{
	UE_LOG(LogStandinOutlinerDrag, Display, TEXT("Create Drag Operation"));

	if (InTreeItems.Num() == 0)
		UE_LOG(LogStandinOutlinerDrag, Warning, TEXT("No itmes in tree selected. payload would be empty"));

	FDragDropPayload DraggedObjects;
	for (const auto& Item : InTreeItems)
	{
		Item->PopulateDragDropPayload(DraggedObjects);
	}

	if (DraggedObjects.StandinLODActors.IsSet() || DraggedObjects.StaticMeshActors.IsSet())
	{
		UE_LOG(LogStandinOutlinerDrag, Display, TEXT("Create new Outliner Operation"));
		TSharedPtr<FStandInsOutlinerDragDropOp> OutlinerOp = MakeShareable(new FStandInsOutlinerDragDropOp(DraggedObjects));
		OutlinerOp->Construct();
		return OutlinerOp;
	}

	return nullptr;
}

StandInsOutliner::FStandInsOutlinerDragDropOp::FStandInsOutlinerDragDropOp(const FDragDropPayload& DraggedObjects)
	: OverrideText()
	, OverrideIcon(nullptr)
{
	if (DraggedObjects.StaticMeshActors)
	{
		StaticMeshActorOp = MakeShareable(new FActorDragDropOp);
		StaticMeshActorOp->Init(DraggedObjects.StaticMeshActors.GetValue());
	}

	if (DraggedObjects.StandinLODActors)
	{
		StandinActorOp = MakeShareable(new FActorDragDropOp);
		StandinActorOp->Init(DraggedObjects.StandinLODActors.GetValue());
	}
}

TSharedPtr<SWidget> StandInsOutliner::FStandInsOutlinerDragDropOp::GetDefaultDecorator() const
{
	TSharedRef<SVerticalBox> VerticalBox = SNew(SVerticalBox);

	VerticalBox->AddSlot()
		[
			SNew(SBorder)
			.BorderImage(FEditorStyle::GetBrush("Graph.ConnectorFeedback.Border"))
		.Visibility(this, &FStandInsOutlinerDragDropOp::GetOverrideVisibility)
		.Content()
		[
			SNew(SHorizontalBox)

			+ SHorizontalBox::Slot()
		.AutoWidth()
		.Padding(0.0f, 0.0f, 3.0f, 0.0f)
		[
			SNew(SImage)
			.Image(this, &FStandInsOutlinerDragDropOp::GetOverrideIcon)
		]

	+ SHorizontalBox::Slot()
		.AutoWidth()
		.VAlign(VAlign_Center)
		[
			SNew(STextBlock)
			.Text(this, &FStandInsOutlinerDragDropOp::GetOverrideText)
		]
		]
		];

	if (StandinActorOp.IsValid())
	{
		auto Content = StandinActorOp->GetDefaultDecorator();
		if (Content.IsValid())
		{
			Content->SetVisibility(TAttribute<EVisibility>(this, &FStandInsOutlinerDragDropOp::GetDefaultVisibility));
			VerticalBox->AddSlot()[Content.ToSharedRef()];
		}
	}

	if (StaticMeshActorOp.IsValid())
	{
		auto Content = StaticMeshActorOp->GetDefaultDecorator();
		if (Content.IsValid())
		{
			Content->SetVisibility(TAttribute<EVisibility>(this, &FStandInsOutlinerDragDropOp::GetDefaultVisibility));
			VerticalBox->AddSlot()[Content.ToSharedRef()];
		}
	}

	return VerticalBox;
}

EVisibility StandInsOutliner::FStandInsOutlinerDragDropOp::GetOverrideVisibility() const
{
	return OverrideText.IsEmpty() && OverrideIcon == nullptr ? EVisibility::Collapsed : EVisibility::Visible;
}

EVisibility StandInsOutliner::FStandInsOutlinerDragDropOp::GetDefaultVisibility() const
{
	return OverrideText.IsEmpty() && OverrideIcon == nullptr ? EVisibility::Visible : EVisibility::Collapsed;
}
