// Copyright (c) 2024 Codemongous LLC. All Rights Reserved.

#include "SCW_UClass.h"
#include "SCW_UField.h"
#include "SCW_UFunction.h"
#include "SourcifyCoreUEWrapperModule.h"
#include "UObject/Class.h"

using namespace Sourcify;

SCW_UClass::SCW_UClass(UClass* InClass) : SCW_UStruct(InClass), Class(InClass)
{

}

ISCW_UClassPtr SCW_UClass::ToUClassPtr()
{
	return GetSharedThisAs<SCW_UClass>();
}

ISCW_UClassConstPtr SCW_UClass::ToUClassPtr() const
{
	return GetSharedThisAs<SCW_UClass>();
}

void SCW_UClass::ClassConstructor(ISCW_UObjectPtr ObjectToConstruct, ISCW_UObjectPtr ArchitypeObject, SCW_EObjectInitializerOptions ObjectInitializerOptions) const
{
	Class->ClassConstructor(FObjectInitializer(dynamic_cast<SCW_UObject*>(ObjectToConstruct.get())->ToUObjectRawPtr(), dynamic_cast<SCW_UObject*>(ArchitypeObject.get())->ToUObjectRawPtr(), static_cast<EObjectInitializerOptions>(ObjectInitializerOptions)));
}

ISCW_UObjectPtr SCW_UClass::FindArchetype(ISCW_UClassConstPtr ArchetypeClass, const wstring& ArchetypeName) const
{
	const SCW_UClass* Archetype = dynamic_cast<const SCW_UClass*>(ArchetypeClass.get());
	if (UObject* ArchetypeUObject = Class->FindArchetype(Archetype->ToUClass(), FName(ArchetypeName.c_str())))
	{
		return FSourcifyCoreUEWrapper::Get().Wrap(*ArchetypeUObject);
	}
	return nullptr;
}

ISCW_UFunctionPtr SCW_UClass::FindFunctionByName(const wstring& InName, SCW_EIncludeSuperFlagType IncludeSuper) const
{
	if (UFunction* Function = Class->FindFunctionByName(FName(InName.c_str()), static_cast<EIncludeSuperFlag::Type>(IncludeSuper)))
	{
		return FSourcifyCoreUEWrapper::Get().Wrap(*Function);
	}
	return nullptr;
}

void SCW_UClass::GenerateFunctionList(vector<wstring>& OutArray) const
{
	TArray<FName> FunctionNames;
	Class->GenerateFunctionList(FunctionNames);

	for (auto FunctionName : FunctionNames)
	{
		OutArray.push_back(*FunctionName.ToString());
	}
}

ISCW_UClassPtr SCW_UClass::GetAuthoritativeClass() const
{
	return Class->GetAuthoritativeClass() ? FSourcifyCoreUEWrapper::Get().Wrap(*Class->GetAuthoritativeClass()) : nullptr;
}

ISCW_UObjectPtr SCW_UClass::GetClassDefaultObject() const
{
	TObjectPtr<UObject> ClassDefaultObject = GetMutableDefault<UObject>(Class);
	return ClassDefaultObject ? FSourcifyCoreUEWrapper::Get().Wrap(*ClassDefaultObject) : nullptr;
}

shared_ptr<ISCW_UObject> SCW_UClass::GetClassGeneratedBy() const
{
	return Class->ClassGeneratedBy ? FSourcifyCoreUEWrapper::Get().Wrap(*Class->ClassGeneratedBy) : nullptr;
}

wstring SCW_UClass::GetClassPathName() const
{
	return *Class->GetClassPathName().ToString();
}

wstring SCW_UClass::GetConfigName() const
{
	return *Class->GetConfigName();
}

ISCW_UObjectPtr SCW_UClass::GetDefaultObject(bool bCreateIfNeeded/* = true*/) const
{
	return FSourcifyCoreUEWrapper::Get().Wrap(*Class->GetDefaultObject(bCreateIfNeeded));
}

void SCW_UClass::GetDefaultObjectSubobjects(vector<ISCW_UObjectPtr>& OutDefaultSubobjects) const
{
	ISCW_UObjectPtr DefaultObj = GetClassDefaultObject();
	if (DefaultObj)
	{
		DefaultObj->GetDefaultSubobjects(OutDefaultSubobjects);
	}
	else
	{
		OutDefaultSubobjects.clear();
	}
}

ISCW_UScriptStructPtr SCW_UClass::GetSparseClassDataStruct() const
{
	return Class->GetSparseClassDataStruct() ? FSourcifyCoreUEWrapper::Get().Wrap(*Class->GetSparseClassDataStruct()) : nullptr;
}

ISCW_UClassPtr SCW_UClass::GetSuperClass() const
{
	return Class->GetSuperClass() ? FSourcifyCoreUEWrapper::Get().Wrap(*Class->GetSuperClass()) : nullptr;
}

bool SCW_UClass::HasAllClassFlags(SCW_EClassFlags FlagsToCheck) const
{
	return Class->HasAllClassFlags(static_cast<EClassFlags>(FlagsToCheck));
}

bool SCW_UClass::HasAnyClassFlags(SCW_EClassFlags FlagsToCheck) const
{
	return Class->HasAnyClassFlags(static_cast<EClassFlags>(FlagsToCheck));
}

vector<ISCW_FImplementedInterfacePtr> SCW_UClass::Interfaces() const
{
	vector<ISCW_FImplementedInterfacePtr> Result;
	Result.reserve(Class->Interfaces.Num());

	for (auto& Interface : Class->Interfaces)
	{
		Result.push_back(FSourcifyCoreUEWrapper::Get().Wrap(Interface));
	}

	return Result;
}

bool SCW_UClass::IsChildOf(ISCW_UClassConstPtr SomeBase) const
{
	const SCW_UClass* Base = dynamic_cast<const SCW_UClass*>(SomeBase.get());
	return Base ? Class->IsChildOf(Base->ToUClass()) : false;
}

bool SCW_UClass::IsChildOf_AActor() const
{
	return Class->IsChildOf<AActor>();
}

bool SCW_UClass::IsChildOf_UActorComponent() const
{
	return Class->IsChildOf<UActorComponent>();
}

bool SCW_UClass::IsChildOf_UInterface() const
{
	return Class->IsChildOf<UInterface>();
}

bool SCW_UClass::IsInterface() const
{
	return Class->HasAnyCastFlags(CLASS_Interface);
}

UClass* SCW_UClass::ToUClass() const
{
	return Class;
}
