#include "AnimationTreeRegistryEditor.hpp"
#include <imgui.h>
#include <OgreLogManager.h>

AnimationTreeRegistryEditor::AnimationTreeRegistryEditor()
{
	m_newNameBuf[0] = '\0';
}

void AnimationTreeRegistryEditor::selectTree(const Ogre::String &name)
{
	m_pendingSelect = true;
	m_pendingSelectName = name;
	m_nodeEditor.reset();
}

void AnimationTreeRegistryEditor::renderMenuBar()
{
	if (!ImGui::BeginMenuBar())
		return;

	if (ImGui::BeginMenu("File")) {
		if (ImGui::MenuItem("Save", nullptr))
			AnimationTreeRegistry::getSingleton().saveToFile(
				AnimationTreeRegistry::defaultPath());
		if (ImGui::MenuItem("Load", nullptr))
			AnimationTreeRegistry::getSingleton().loadFromFile(
				AnimationTreeRegistry::defaultPath());
		ImGui::EndMenu();
	}
	ImGui::EndMenuBar();
}

void AnimationTreeRegistryEditor::renderListPane()
{
	ImGui::BeginChild("TreeList", ImVec2(250, 0), true);

	if (ImGui::Button("Add Tree")) {
		AnimationTreeRegistry &reg =
			AnimationTreeRegistry::getSingleton();
		Ogre::String name = reg.generateUniqueName("new_tree");
		AnimationTreeRegistry::AnimationTreeDefinition def;
		def.name = name;
		def.root.type = "output";
		def.root.speed = 1.0f;
		reg.registerTree(def);
		m_selectedTreeName = name;
	}

	AnimationTreeRegistry &reg = AnimationTreeRegistry::getSingleton();
	std::vector<Ogre::String> names = reg.getTreeNames();
	std::sort(names.begin(), names.end());

	for (size_t i = 0; i < names.size(); ++i) {
		const auto &name = names[i];
		bool selected = (m_selectedTreeName == name);
		ImGui::PushID(static_cast<int>(i));
		if (ImGui::Selectable(name.c_str(), selected)) {
			if (m_selectedTreeName != name)
				m_nodeEditor.reset();
			m_selectedTreeName = name;
		}
		ImGui::PopID();
	}

	ImGui::EndChild();
}

void AnimationTreeRegistryEditor::renderEditPane()
{
	ImGui::SameLine();
	ImGui::BeginChild("TreeEdit", ImVec2(0, 0), true);

	AnimationTreeRegistry &reg = AnimationTreeRegistry::getSingleton();
	AnimationTreeRegistry::AnimationTreeDefinition *def =
		reg.findTree(m_selectedTreeName);

	if (!def) {
		ImGui::Text("Select a tree from the list to edit.");
		ImGui::EndChild();
		return;
	}

	/* Name */
	char nameBuf[256];
	snprintf(nameBuf, sizeof(nameBuf), "%s", def->name.c_str());
	if (ImGui::InputText("Name", nameBuf, sizeof(nameBuf))) {
		Ogre::String newName = nameBuf;
		if (!newName.empty() && newName != def->name &&
		    !reg.hasTree(newName)) {
			AnimationTreeRegistry::AnimationTreeDefinition renamed =
				*def;
			renamed.name = newName;
			reg.removeTree(def->name);
			reg.registerTree(renamed);
			m_selectedTreeName = newName;
			def = reg.findTree(newName);
		}
	}

	/* Skeleton source */
	std::vector<AnimationTreeRegistry::SkeletonSource> sources =
		reg.getAvailableSkeletonSources();
	Ogre::String currentSource = def->skeletonSource;
	Ogre::String currentSkelName =
		currentSource.empty() ?
			Ogre::String() :
			reg.getSkeletonNameForMesh(currentSource);
	Ogre::String preview =
		currentSkelName.empty() ? "(none)" : currentSkelName;
	if (ImGui::BeginCombo("Skeleton Source", preview.c_str())) {
		bool noneSel = currentSource.empty();
		if (ImGui::Selectable("(none)", noneSel)) {
			def->skeletonSource = "";
			reg.markModified(def->name);
		}
		for (size_t i = 0; i < sources.size(); ++i) {
			const auto &src = sources[i];
			bool sel = (currentSource == src.meshName);
			ImGui::PushID(static_cast<int>(i));
			if (ImGui::Selectable(src.skeletonName.c_str(), sel)) {
				def->skeletonSource = src.meshName;
				reg.markModified(def->name);
			}
			if (ImGui::IsItemHovered()) {
				ImGui::SetTooltip(
					"Representative mesh: %s",
					src.meshName.c_str());
			}
			ImGui::PopID();
		}
		ImGui::EndCombo();
	}
	if (ImGui::IsItemHovered()) {
		ImGui::SetTooltip(
			"Skeleton used to populate animation-name dropdowns. "
			"One representative mesh per skeleton is shown.");
	}

	ImGui::Separator();

	/* Tree node editor */
	std::vector<Ogre::String> animNames =
		reg.getAnimationsForSource(def->skeletonSource);
	AnimationTreeNode *rootPtr = def ? &def->root : nullptr;
	if (rootPtr) {
		bool edited = m_nodeEditor.render(*rootPtr, animNames);
		if (edited)
			reg.markModified(def->name);
	}

	ImGui::Separator();

	if (ImGui::Button("Delete Tree")) {
		reg.removeTree(def->name);
		m_selectedTreeName.clear();
	}

	ImGui::EndChild();
}

void AnimationTreeRegistryEditor::render(bool *open)
{
	if (m_pendingSelect) {
		m_selectedTreeName = m_pendingSelectName;
		m_pendingSelect = false;
	}

	ImGui::SetNextWindowSize(ImVec2(900, 600), ImGuiCond_FirstUseEver);
	if (!ImGui::Begin("Animation Tree Registry", open,
			  ImGuiWindowFlags_MenuBar)) {
		ImGui::End();
		return;
	}

	renderMenuBar();

	renderListPane();
	renderEditPane();

	ImGui::End();
}
