// Oleg Petruny proprietary.

#include "CommonFunctions.h"

#include "GameFramework/Actor.h"
#include "InputCoreTypes.h"
#include "Kismet/GameplayStatics.h"
#include "UObject/Object.h"

#include "CustomGameInstance.h"
#include "Levels/LevelBase.h"
#include "PlayerBase.h"

bool UCommonFunctions::IsNonGameObject(UObject* object)
{
    if(object->HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))
        return true;

    return false;
}

FText UCommonFunctions::GetKeyDisplayName(FKey key)
{
    if(key == EKeys::MouseWheelAxis)
    {
        return NSLOCTEXT("KeyDisplayNames", "MouseWheelAxis", "Mouse Wheel");
    }

    return key.GetDisplayName(false);
}

void UCommonFunctions::DestroyActorRecursively(AActor* actor)
{
    TArray<AActor*> childs;
    actor->GetAttachedActors(childs, true, true);

    for(auto child : childs)
        child->Destroy();
    actor->Destroy();
}

TArray<int32> UCommonFunctions::GetRandomIntArray(int32 size, int32 min, int32 max)
{
    if(size <= 0)
        return {};

    TArray<int32> arr;
    arr.Reserve(size);
    for(int32 i = 0; i < size; ++i)
        arr.Add(FMath::RandRange(min, max));
    return arr;
}



namespace SlowMotion
{
    FTimerHandle timer;
    float targetDilation;
    FWorldDilationChangedDelegate worldDilationChangedDelegate;
}

void UCommonFunctions::EnterSlowMotion(float duration)
{
    if(SlowMotion::targetDilation == SlowMotion::slowDilation)
        return;

    SlowMotion::targetDilation = SlowMotion::slowDilation;

    auto GI = UCustomGameInstance::Get();
    if(!GI)
        return;

    auto world = GI->GetWorld();
    world->GetTimerManager().SetTimer(SlowMotion::timer, []() { SlowMotionTick(); }, 0.01f, true); // wrapped in lambda due to some template function class referencing
}

void UCommonFunctions::ExitSlowMotion(float duration)
{
    if(SlowMotion::targetDilation == SlowMotion::normalDilation)
        return;

    SlowMotion::targetDilation = SlowMotion::normalDilation;

    auto GI = UCustomGameInstance::Get();
    if(!GI)
        return;

    auto world = GI->GetWorld();
    world->GetTimerManager().SetTimer(SlowMotion::timer, []() { SlowMotionTick(); }, 0.01f, true);
}

FWorldDilationChangedDelegate& UCommonFunctions::GetWorldDilationChangedDelegate()
{
    return SlowMotion::worldDilationChangedDelegate;
}

void UCommonFunctions::SlowMotionTick()
{
    const UWorld* world = UCustomGameInstance::Get()->GetWorld();
    const float currentDilation = UGameplayStatics::GetGlobalTimeDilation(world);
    float newDilation = FMath::FInterpTo(currentDilation, SlowMotion::targetDilation, 1, SlowMotion::interpolationSpeed);

    UGameplayStatics::SetGlobalTimeDilation(world, newDilation);
    SlowMotion::worldDilationChangedDelegate.Broadcast(newDilation);
    if(FMath::IsNearlyEqual(newDilation, SlowMotion::targetDilation, UE_KINDA_SMALL_NUMBER))
    {
        UGameplayStatics::SetGlobalTimeDilation(world, SlowMotion::targetDilation);
        world->GetTimerManager().ClearTimer(SlowMotion::timer);
    }
}
