// Oleg Petruny proprietary.

#pragma once

#include "Kismet/BlueprintFunctionLibrary.h"

#include "CommonFunctions.generated.h"

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FWorldDilationChangedDelegate, float, newDilation);

/**
 * Collection of common/universal/without own scope/specific functions.
 */
UCLASS()
class UCommonFunctions : public UBlueprintFunctionLibrary
{
    GENERATED_BODY()

public:
    /** Returns true if the object is UE class template (used for copy/archetype/meta system but not on the level) */
    UFUNCTION(BlueprintPure)
    static bool IsNonGameObject(class UObject* object);

    /** "Overload" of the built-in keys translator (to not build own engine copy) */
    UFUNCTION(BlueprintPure)
    static FText GetKeyDisplayName(struct FKey key);

    /** Recursively destroy actor and all its childs (the default Destroy doesn't have consistent behavior) */
    UFUNCTION(BlueprintCallable, Category = Actor)
    static void DestroyActorRecursively(class AActor* actor);



    UFUNCTION(BlueprintCallable, Category = World)
    static void EnterSlowMotion(float duration = 1.0f);

    UFUNCTION(BlueprintCallable, Category = World)
    static void ExitSlowMotion(float duration = 1.0f);

    static FWorldDilationChangedDelegate& GetWorldDilationChangedDelegate();



    UFUNCTION(BlueprintPure)
    static TArray<int32> GetRandomIntArray(int32 size = 16, int32 min = 0, int32 max = 16);

    template<typename T>
    static TArray<T> ArrayDiff(const TArray<T>& a, const TArray<T>& b);
    template<typename T>
    static void ArrayRemoveFirstFromEnd(TArray<T>& array, T element);

private:
    static void SlowMotionTick();

};

namespace SlowMotion
{
    constexpr float normalDilation = 1.0f;
    constexpr float slowDilation = 0.2f;
    constexpr float interpolationSpeed = 0.1f;
}

template<typename T>
inline TArray<T> UCommonFunctions::ArrayDiff(const TArray<T>& a, const TArray<T>& b)
{
    TSet<T> result;

    if(a.Num() == 0)
        return b;
    else if(b.Num() == 0)
        return a;

    for(auto& i : a)
        if(!b.Contains(i))
            result.Add(i);

    for(auto& i : b)
        if(!a.Contains(i))
            result.Add(i);

    return result.Array();
}

template<typename T>
inline void UCommonFunctions::ArrayRemoveFirstFromEnd(TArray<T>& array, T element)
{
    for(int32 i = array.Num() - 1; i > -1; --i)
    {
        if(array[i] == element)
        {
            array.RemoveAt(i);
            return;
        }
    }
}
