#pragma once

#include "CoreMinimal.h"
#include "Factories/Factory.h"
#include "WingServer.h"
#include "WingHandler.h"
#include "WingFactories.h"
#include "WingPropHandle.h"
#include "WingTypes.h"
#include "Factories/BlueprintFactory.h"
#include "Factories/BlueprintMacroFactory.h"
#include "Factories/AnimBlueprintFactory.h"
#include "WidgetBlueprintFactory.h"
#include "EditorUtilityBlueprintFactory.h"
#include "EditorUtilityWidgetBlueprintFactory.h"
#include "Create_Blueprint.generated.h"

UCLASS()
class UWing_Create_Blueprint : public UWingHandler
{
	GENERATED_BODY()

public:
	UPROPERTY(EditAnywhere, meta=(Description="Full asset path for the new asset (e.g. '/Game/MyFolder/MyAsset')"))
	FString Path;

	UPROPERTY(meta=(Optional, Description="The parent class for the new blueprint"))
	FString ParentClass;

	static UClass *BlueprintInterfaceFactoryStaticClass()
	{ 
		return FindObject<UClass>(nullptr, TEXT("/Script/UnrealEd.BlueprintInterfaceFactory"));
	}

	virtual void Register() override
	{
		UWingServer::AddHandler(this, TEXT("Create_Blueprint"),
			UBlueprintFactory::StaticClass(), EWingHandlerKind::Create,
			TEXT("Create a normal blueprint"));
		UWingServer::AddHandler(this, TEXT("Create_BlueprintMacroLibrary"),
			UBlueprintMacroFactory::StaticClass(), EWingHandlerKind::Create,
			TEXT("Create a blueprint macro library"));
		UWingServer::AddHandler(this, TEXT("Create_WidgetBlueprint"),
			UWidgetBlueprintFactory::StaticClass(), EWingHandlerKind::Create,
			TEXT("Create a widget blueprint"));
		UWingServer::AddHandler(this, TEXT("Create_EditorUtilityBlueprint"),
			UEditorUtilityBlueprintFactory::StaticClass(), EWingHandlerKind::Create,
			TEXT("Create an editor utility blueprint"));
		UWingServer::AddHandler(this, TEXT("Create_EditorUtilityWidgetBlueprint"),
			UEditorUtilityWidgetBlueprintFactory::StaticClass(), EWingHandlerKind::Create,
			TEXT("Create an editor utility widget blueprint"));
		if (BlueprintInterfaceFactoryStaticClass() != nullptr)
			UWingServer::AddHandler(this, TEXT("Create_BlueprintInterface"),
				BlueprintInterfaceFactoryStaticClass(), EWingHandlerKind::Create,
				TEXT("Create a blueprint interface"));
	}

	virtual void Handle() override
	{
		if (!WingFactories::CheckNewAssetPath(Path)) return;

		// Resolve parent class, if specified.
		UClass *ParentClassObj = nullptr;
		if (!ParentClass.IsEmpty())
		{
			UWingTypes::Requirements Req;
			Req.BlueprintType = false;
			Req.Blueprintable = true;
			Req.AllowContainer = false;
			ParentClassObj = UWingTypes::TextToOneObjectType(ParentClass, Req);
			if (!ParentClassObj) return;
		}

		// Make the factory.
		UClass *FactoryClass = Cast<UClass>(ConfigurationObject);
		UFactory *Factory = NewObject<UFactory>(GetTransientPackage(), FactoryClass);
		if (Factory == nullptr)
		{
			UWingServer::Printf(TEXT("ERROR: factory creation failed (bug)\n"));
			return;
		}

		// Get the 'ParentClass' property.
		WingPropHandle Props;
		TSharedPtr<IPropertyHandle> PCProp = Props.NamedProperty(Factory, TEXT("ParentClass"), true);
		if (!PCProp) return;

		// Store the parent class.
		FPropertyAccess::Result SetResult = PCProp->SetValue(ParentClassObj);
		if (SetResult != FPropertyAccess::Result::Success)
		{
			UWingServer::Printf(TEXT("ERROR: property does not allow value: %s\n"), *ParentClass);
			return;
		}

		// Create the asset using the factory.
		UObject *Blueprint = WingFactories::CreateAsset(Path, Factory);
		if (Blueprint == nullptr) return;
		UWingServer::Printf(TEXT("Created.\n"));
	}
};
