// Oleg Petruny proprietary.


#include "ContentLoader.h"

#include "IPlatformFilePak.h"

void UContentLoader::BeginDestroy()
{
    //if(mountedFiles.Num() > 0)
    //{
    //    while(mountedFiles.Num() > 0)
    //        UnmountPak(*mountedFiles.begin());
    //
    //    FPlatformFileManager::Get().RemovePlatformFile(GetPakPlatformFile());
    //}

    UObject::BeginDestroy();
}

UClass* UContentLoader::LoadPak(const FString& pakFilePath)
{
    UE_LOG(LogTemp, Log, TEXT("ContentLoader: Starting to mount pak %s"), *pakFilePath);

    FPakPlatformFile* pakFileMgr = (FPakPlatformFile*)(FPlatformFileManager::Get().FindPlatformFile(TEXT("PakFile")));
    if(!pakFileMgr)
    {
        UE_LOG(LogTemp, Warning, TEXT("ContentLoader: Unable to get PakPlatformFile."));
        return nullptr;
    }

    if(!pakFileMgr->Mount(*pakFilePath, 0))
    {
        UE_LOG(LogTemp, Warning, TEXT("ContentLoader: Unable to mount pak %s."), *pakFilePath);
        return nullptr;
    }

    UE_LOG(LogTemp, Warning, TEXT("ContentLoader: Pak %s mounted successfully."), *pakFilePath);

    TArray<FString> content;
    const FString mountPoint = GetPakMountContent(pakFilePath, &content);
    UE_LOG(LogTemp, Log, TEXT("ContentLoader: Pak '%s' contains %d items."), *FPaths::GetCleanFilename(pakFilePath), content.Num());

    FPackageName::RegisterMountPoint("/Game/", mountPoint);
    for(auto& i : content)
    {
        if(FPaths::GetCleanFilename(i).StartsWith(TEXT("BP_")))
        {
            UE_LOG(LogTemp, Log, TEXT("ContentLoader: Found BP class '%s' of pak %s."), *i, *pakFilePath);
            return GetPakClass(i);
        }
    }

    return nullptr;
}

FString UContentLoader::GetPakMountContent(const FString& pakFilePath, TArray<FString>* content)
{
    TArray<FString> contentProxy;
    if(!content)
        content = &contentProxy;

    FString mountPoint, contentPath, contentPathTail;
    TRefCountPtr<FPakFile> pakFile = new FPakFile(FPlatformFileManager::Get().FindPlatformFile(TEXT("PakFile")), *pakFilePath, false);
    auto pak = pakFile.GetReference();
    if(pakFile.GetReference()->IsValid())
    {
        mountPoint = pakFile.GetReference()->GetMountPoint();
        mountPoint.Split("/Content/", &contentPath, &contentPathTail);

        for(FPakFile::FFilenameIterator It(*pakFile.GetReference(), false); It; ++It)
            if(FPaths::GetExtension(It.Filename()) == TEXT("uasset"))
                content->Add(FString::Printf(TEXT("%s%s"), *contentPathTail, *It.Filename()));
    }

    if(!contentPath.IsEmpty())
    {
        return FString::Printf(TEXT("%s/Content/"), *contentPath);
    }
    else if(content->Num())
    {
        const FString fullPath = FString::Printf(TEXT("%s%s"), *mountPoint, *((*content)[0]));
        if(fullPath.Split("/Content/", &contentPath, &contentPathTail))
        {
            return FString::Printf(TEXT("%s/Content/"), *contentPath);
        }
    }

    return FString("");
}

UClass* UContentLoader::GetPakClass(const FString& pakContentPath)
{
    const FString assetName = FString::Printf(TEXT("/Game/%s.%s"), *FPaths::GetBaseFilename(pakContentPath, false), *FPaths::GetBaseFilename(pakContentPath, true));
    const FString className = assetName + TEXT(".") + FPackageName::GetShortName(assetName) + TEXT("_C");
    auto result = StaticLoadClass(UObject::StaticClass(), nullptr, *className);
    if(!result)
        UE_LOG(LogTemp, Warning, TEXT("ContentLoader: Unable to load pak class: %s."), *className);
    return result;
}

bool UContentLoader::UnloadPak(const FString& pakFilePath)
{
    FPakPlatformFile* pakFileMgr = (FPakPlatformFile*)(FPlatformFileManager::Get().FindPlatformFile(TEXT("PakFile")));
    if(!pakFileMgr)
    {
        UE_LOG(LogTemp, Warning, TEXT("Unable to get PakPlatformFile for pak file (Unmount): %s"), *pakFilePath);
        return false;
    }

    if(!pakFileMgr->Unmount(*pakFilePath))
    {
        UE_LOG(LogTemp, Warning, TEXT("Unable to unmount pak: %s"), *pakFilePath);
        return false;
    }

    const FString mountPoint = GetPakMountContent(pakFilePath);
    FPackageName::UnRegisterMountPoint("/Game/", mountPoint);

    return true;
}