/*
	GameEngine and Editor
	by John Ryland
	Copyright (c) 2023
*/

////////////////////////////////////////////////////////////////////////////////////
//	File Browser

#include "FileBrowser.h"
#include "FileWatch.hpp"
#include "imgui.h"
#include <thread>
#include <string>
#include <regex>
#include <iostream>
#include <unordered_set>

using FileWatcher = filewatch::FileWatch<std::string>;

namespace GameEngine {

FileBrowser::FileBrowser(ApplicationFramework::IApplication& app)
    : m_application(app)
{
}

FileBrowser::~FileBrowser()
{
}

void FileBrowser::AddShowMenuItem()
{
    ImGui::MenuItem("Show File Browser", NULL, &m_open);
}

struct DirectoryNode
{
	std::string                  FullPath;
	std::string                  FileName;
	std::vector<DirectoryNode>   Children;
	std::unique_ptr<FileWatcher> Watcher;
	bool                         IsDirectory;  // children.count != 0 ?  empty dir
	bool                         NeedsRefresh;
};

void RecursivelyAddDirectoryNodes(DirectoryNode& parentNode, std::filesystem::directory_iterator directoryIterator)
{
	for (const std::filesystem::directory_entry& entry : directoryIterator)
	{
		DirectoryNode& childNode = parentNode.Children.emplace_back();
		childNode.FullPath     = std::filesystem::absolute(entry.path()).u8string();
		childNode.FileName     = entry.path().filename().u8string();
        childNode.IsDirectory  = entry.is_directory();
		childNode.NeedsRefresh = false;
		if (childNode.IsDirectory)
		{
			childNode.Watcher = std::make_unique<FileWatcher>(childNode.FullPath, std::regex(".*"), [&childNode](const std::string& file, const filewatch::Event eventType)
			{
				childNode.NeedsRefresh = true;
			});
			RecursivelyAddDirectoryNodes(childNode, std::filesystem::directory_iterator(entry));
		}
	}

	auto moveDirectoriesToFront = [](const DirectoryNode& a, const DirectoryNode& b) { return (a.IsDirectory > b.IsDirectory); };
	std::sort(parentNode.Children.begin(), parentNode.Children.end(), moveDirectoriesToFront);
}

DirectoryNode CreateDirectryNodeTreeFromPath(const std::filesystem::path& rootPath)
{
	DirectoryNode rootNode;
	rootNode.FullPath = rootPath.u8string();
	rootNode.FileName = rootPath.filename().u8string();
	if (rootNode.IsDirectory = std::filesystem::is_directory(rootPath); rootNode.IsDirectory)
		RecursivelyAddDirectoryNodes(rootNode, std::filesystem::directory_iterator(rootPath));

	return rootNode;
}

void RecursivelyDisplayDirectoryNode(const DirectoryNode& parentNode)
{
	ImGui::PushID(&parentNode);
	if (parentNode.IsDirectory)
	{
		int flags = (parentNode.NeedsRefresh) ? ImGuiTreeNodeFlags_Selected : 0;
		if (ImGui::TreeNodeEx(parentNode.FileName.c_str(), ImGuiTreeNodeFlags_SpanFullWidth | flags))
		{
			for (const DirectoryNode& childNode : parentNode.Children)
				RecursivelyDisplayDirectoryNode(childNode);
			ImGui::TreePop();
		}
	}
	else
	{
		if (ImGui::TreeNodeEx(parentNode.FileName.c_str(), ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_SpanFullWidth))
		{
			// ... handle file click interaction
		}
	}
	ImGui::PopID();
}

 /*

void RecursivelyDirectlyDisplayDirectoryNode(const DirectoryNode& parentNode)
{
	ImGui::PushID(&parentNode);
	if (parentNode.IsDirectory)
	{
		if (ImGui::TreeNodeEx(parentNode.FileName.c_str(), ImGuiTreeNodeFlags_SpanFullWidth))
		{
			for (const DirectoryNode& childNode : parentNode.Children)
				RecursivelyDirectlyDisplayDirectoryNode(childNode);
			ImGui::TreePop();
		}
	}
	else
	{
		if (ImGui::TreeNodeEx(parentNode.FileName.c_str(), ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_SpanFullWidth))
		{
			// ... handle file click interaction
		}
	}
	ImGui::PopID();
}

void RecursivelyDirectlyDisplayDirectoryNode(const std::filesystem::path& rootPath)
{
	DirectoryNode rootNode;
	rootNode.FullPath = rootPath.u8string();
	rootNode.FileName = rootPath.filename().u8string();
	if (rootNode.IsDirectory = std::filesystem::is_directory(rootPath); rootNode.IsDirectory)
		RecursivelyDirectlyDisplayDirectoryNode(rootNode, std::filesystem::directory_iterator(rootPath));
}

*/

static DirectoryNode rootNode = CreateDirectryNodeTreeFromPath("src");//L"C:/SomeFolder");

void FileBrowser::Update()
{
    if (m_open)
    {
        if (ImGui::Begin("File Browser", &m_open))
            //RecursivelyDirectlyDisplayDirectoryNode(".");
            RecursivelyDisplayDirectoryNode(rootNode);
        ImGui::End();
    }
}

void FileBrowser::Initialize()
{
}

void FileBrowser::Shutdown()
{
}

/*
void PluginManager::SetPluginDirectory(const char* pluginDirectoryName)
{
    mPluginDirectoryName = pluginDirectoryName;
    mFileWatcher = std::make_unique<FileWatcher>(pluginDirectoryName, std::regex(".*"), [this](const std::string& file, const filewatch::Event eventType)
    {
        std::string pluginName = details::PluginNameFromFileName(file);
        if (!pluginName.empty() && eventType == filewatch::Event::added)
        {
            mPendingAdd = true;
        }
        if (!pluginName.empty() && eventType == filewatch::Event::modified && mPendingAdd != true)
        {
        }
        mNeedReload = true;
    });
}

void PluginManager::LoadPlugins()
{
    // Get the set of plugin file names now currently on disk
    std::unordered_map<std::string, std::string> pluginFileNames;
    for (const auto& entry : std::filesystem::directory_iterator(mPluginDirectoryName))
    {
        std::string fileName = entry.path();
        std::string pluginName = details::PluginNameFromFileName(fileName);
        if (!pluginName.empty())
            pluginFileNames[pluginName] = fileName;
    }
}
*/

} // GameEngine namespace
