#include "GuiManager.h"


GuiManager::GuiManager(GLFWwindow* window)
	: mp_window(window)
{
	// ImGui initalize
	ImGui::CreateContext();
	ImGui_ImplGlfw_InitForOpenGL(mp_window, true);
	ImGui_ImplOpenGL3_Init("#version 330 core");

	// ImGui style setting
	ImGuiStyle& style = ImGui::GetStyle();
	ImGui::StyleColorsLight();
	//ImGui::StyleColorsDark();
	style.FrameBorderSize = 1.0f;
	style.WindowRounding = 4.0f;
	style.ScrollbarRounding = 4.0f;
	style.IndentSpacing = 15.0f;
	style.WindowTitleAlign = ImVec2(0.5f, 0.5f);
	style.ScaleAllSizes(1.2f); // Padding size

	// Default settings (UI)
	fps_ui_right_margin = 160; // Right alignment margin value for fps display | fps 표시용 우측 정렬 마진

	// Default settings (Geometry)
	m_iteration = 20;
	m_tree_size = 1.0f;

	m_branch_tallness = 0.5f;
	m_branch_shrinkage = 0.9f;
	m_branch_max_angle = 45;
	m_branch_angle_turbulence = 10;
	m_branch_number_of_new_branches_spawned_by_one_trunk = 4;
	m_branch_number_of_new_branches = 3;
	m_branch_number_of_new_branches_fluctuation = 0.5;

	m_leaf_density = 0.2;
	m_leaf_height = 10;

	m_tree_random_seed = 9;
	
	// Default settings (Light)
	light_position[2] = 10.0f; // Defalut light z position
	light_intensity = 50.0f;
	light_attenuation = 1.0f;

	ambient_color[0] = 0.5f;
	ambient_color[1] = 0.5f;
	ambient_color[2] = 0.5f;
	diffuse_color[0] = 0.5f;
	diffuse_color[1] = 0.5f;
	diffuse_color[2] = 0.5f;
	specular_color[0] = 0.5f;
	specular_color[1] = 0.5f;
	specular_color[2] = 0.5f;

	// Load leaf and bark images
	//PrepareTextureBrowserPalette();
	is_texture_browser_prepared = 0;

	// Set view mode
	m_need_to_show_leaf = true;
	m_need_to_show_branch = true;
}


GuiManager::~GuiManager()
{

}


void GuiManager::DrawGui()
{
	// 0. Start the Dear ImGui frame
	ImGui_ImplOpenGL3_NewFrame();
	ImGui_ImplGlfw_NewFrame();
	ImGui::NewFrame();

	// 1. Show main menu bar
	if (ImGui::BeginMainMenuBar())
	{
		if (ImGui::BeginMenu("File"))
		{
			if (ImGui::MenuItem("New project", "Ctrl+N")) {}
			if (ImGui::MenuItem("Open project", "Ctrl+O", &m_need_to_open_project)) {}
			if (ImGui::MenuItem("Save project", "Ctrl+S", &m_need_to_save_project)) {}
			ImGui::Separator();
			if (ImGui::MenuItem("Export to OBJ file", NULL, &m_need_to_export_obj)) {}
			ImGui::Separator();
			if (ImGui::MenuItem("Exit", "ESC")) { exit(0); }
			ImGui::EndMenu();
		}
		if (ImGui::BeginMenu("Edit"))
		{
			if (ImGui::MenuItem("Undo", "Ctrl+Z", false, false)) {}
			if (ImGui::MenuItem("Redo", "Ctrl+Y", false, false)) {}  // Disabled item
			ImGui::EndMenu();
		}
		if (ImGui::BeginMenu("Create"))
		{
			if (ImGui::MenuItem("L-system compiler", NULL, false, false)) {}
			ImGui::Separator();
			if (ImGui::MenuItem("Geometry modifier", NULL, &show_geometry_modifier_window)) {}
			if (ImGui::MenuItem("Texture browser", NULL, &show_texture_browser_window)) {}
			ImGui::Separator();
			if (ImGui::MenuItem("Default tree model", NULL)) {}

			ImGui::EndMenu();
		}
		if (ImGui::BeginMenu("Environment"))
		{
			if (ImGui::MenuItem("Morning light", NULL)) // Morning light preset
			{
				light_intensity = 300.0f;
				light_attenuation = 21.0f;
				light_position[0] = 400.0f;
				light_position[1] = 200.0f;
				light_position[2] = -100.0f;
				ambient_color[0] = 196.0f / 255;
				ambient_color[1] = 206.0f / 255;
				ambient_color[2] = 206.0f / 255;
				diffuse_color[0] = 255.0f / 255;
				diffuse_color[1] = 248.0f / 255;
				diffuse_color[2] = 229.0f / 255;
				specular_color[0] = 180.0f / 255;
				specular_color[1] = 146.0f / 255;
				specular_color[2] = 63.0f / 255;
			}
			if (ImGui::MenuItem("Noon light", NULL)) // Morning light preset
			{
				light_intensity = 520.0f;
				light_attenuation = 22.0f;
				light_position[0] = -200.0f;
				light_position[1] = 400.0f;
				light_position[2] = 200.0f;
				ambient_color[0] = 235.0f / 255;
				ambient_color[1] = 223.0f / 255;
				ambient_color[2] = 191.0f / 255;
				diffuse_color[0] = 255.0f / 255;
				diffuse_color[1] = 236.0f / 255;
				diffuse_color[2] = 221.0f / 255;
				specular_color[0] = 252.0f / 255;
				specular_color[1] = 255.0f / 255;
				specular_color[2] = 164.0f / 255;
			}
			if (ImGui::MenuItem("Dawn light", NULL)) // Dawn light preset
			{
				light_intensity = 380.0f;
				light_attenuation = 17.5f;
				light_position[0] = -400.0f;
				light_position[1] = 100.0f;
				light_position[2] = -50.0f;
				ambient_color[0] = 105.0f / 255;
				ambient_color[1] = 112.0f / 255;
				ambient_color[2] = 115.0f / 255;
				diffuse_color[0] = 190.0f / 255;
				diffuse_color[1] = 220.0f / 255;
				diffuse_color[2] = 255.0f / 255;
				specular_color[0] = 255.0f / 255;
				specular_color[1] = 221.0f / 255;
				specular_color[2] = 166.0f / 255;
			}
			ImGui::Separator();
			if (ImGui::MenuItem("Custom light", NULL, &show_custom_light_window)) {}
			ImGui::Separator();
			if (ImGui::MenuItem("View leaves", NULL, &m_need_to_show_leaf))
			{
				//m_need_to_show_leaf = true;
			}
			if (ImGui::MenuItem("View branches", NULL, &m_need_to_show_branch))
			{
				//m_need_to_show_branch = true;
			}
			if (ImGui::MenuItem("View lands", NULL, false, false)) {}
			if (ImGui::MenuItem("View shadows", NULL, false, false)) {}
			ImGui::Separator();
			if (ImGui::MenuItem("Wireframe mode", NULL, &wireframe_mode))
			{
				if (wireframe_mode == true)
				{
					glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
					glDisable(GL_CULL_FACE);
				}
				else
				{
					glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
					glEnable(GL_CULL_FACE);
				}
			}

			ImGui::EndMenu();
		}
		if (ImGui::BeginMenu("Animation"))
		{
			if (ImGui::MenuItem("Play", "Ctrl+P")) {}
			if (ImGui::MenuItem("Pause", "Ctrl+P")) {}
			ImGui::Separator();
			if (ImGui::MenuItem("Timeline", NULL, &show_timeline_window)) {}
			ImGui::EndMenu();
		}
		if (ImGui::BeginMenu("Help"))
		{
			if (ImGui::MenuItem("High DPI mode", NULL, &high_dpi_mode))
			{
				if (high_dpi_mode == true)
				{
					ImGui::GetIO().FontGlobalScale = 2.0f; // Bigger font size
					fps_ui_right_margin = 300; // More margin (because text size will be bigger)
				}
				else
				{
					ImGui::GetIO().FontGlobalScale = 1.0f;
					fps_ui_right_margin = 160;
				}
			}
			ImGui::Separator();
			if (ImGui::MenuItem("Show hello world window", NULL, &show_hello_world_window)) {}
			if (ImGui::MenuItem("Show demo window", NULL, &show_demo_window)) {}
			ImGui::Separator();
			if (ImGui::MenuItem("Software information", NULL, &show_software_information_window)) {}
			ImGui::EndMenu();
		}
		ImGui::SameLine(ImGui::GetWindowWidth() - fps_ui_right_margin); // Right align
		ImGui::Text("%.2f FPS (%.2f ms)", ImGui::GetIO().Framerate, 1000.0f / ImGui::GetIO().Framerate);
		ImGui::EndMainMenuBar();
	}

	// 2. Show geometry modifier window
	if (show_geometry_modifier_window)
	{
		ImGui::Begin("Geometry modifier", &show_geometry_modifier_window);
		//ImGui::Unindent(); // no arrow for collapse

		static int switch_geometry_modifier_tabs = 1;

		ImGui::SameLine(0.0, 0.0f);
		if (ImGui::Button("Leaf", ImVec2(120.0f, 25.0f))) { switch_geometry_modifier_tabs = 1; }
		ImGui::SameLine(0.0, 5.0f);
		if (ImGui::Button("Branch", ImVec2(120.0f, 25.0f))) { switch_geometry_modifier_tabs = 2; }

		ImGui::Separator();

		ImGui::Text("General");
		{
			ImGui::InputInt("Iteration", &m_iteration, 1);
			ImGui::SliderFloat("Tree size", &m_tree_size, 0.0f, 4.0f);
		}

		ImGui::Separator();

		if (switch_geometry_modifier_tabs == 1)
		{
			ImGui::Text("Leaf");
			{
				ImGui::SliderInt("Height", &m_leaf_height, 0, 20);
				ImGui::SliderFloat("Density", &m_leaf_density, 0.0f, 1.0f);
			}
		}
		else if (switch_geometry_modifier_tabs == 2)
		{
			ImGui::Text("Branch");
			{
				ImGui::InputInt("Divergence", &m_branch_number_of_new_branches_spawned_by_one_trunk, 1);
				ImGui::InputInt("Branch counter", &m_branch_number_of_new_branches, 1);
				ImGui::SliderFloat("Counter fluctuation", &m_branch_number_of_new_branches_fluctuation, 0.0f, 1.0f);
				ImGui::SliderFloat("Tallness", &m_branch_tallness, 0.0f, 10.0f);
				ImGui::SliderFloat("Shrinkage", &m_branch_shrinkage, 0.0f, 1.0);
				ImGui::SliderInt("Max angle", &m_branch_max_angle, 0, 180);
				ImGui::SliderInt("Angle turbulence", &m_branch_angle_turbulence, 0, 180);
			}
		}

		ImGui::Separator();

		ImGui::Text("Randomness");
		{
			ImGui::InputInt("Seed value", &m_tree_random_seed, 1);
		}

		ImGui::Separator();

		if (ImGui::Button("Re-Generate!", ImVec2(245.0f, 25.0f)))
		{
			m_need_to_regenerate = true; // Set flag true to re-generate L-system
		}

		ImGui::Separator();

		ImGui::End();
	}

	// 3. Show text browser window
	if (show_texture_browser_window)
	{
		// If you start loading textures right away, there is a problem loading before the notification UI is displayed, so I added an interval of 3 frames | 바로 텍스쳐 로딩을 시작하면 알림 UI가 표시되기 전에 로딩이 진행되는 문제가 있어서 3프레임의 간격 추가
		// Do we need to load leaf and bark textures?
		if (is_texture_browser_prepared == 3)
		{
			PrepareTextureBrowserPalette(); // Load leaf and bark images
			++is_texture_browser_prepared;
		}
		else if (is_texture_browser_prepared < 10)
		{
			++is_texture_browser_prepared;
		}

		ImGui::Begin("Texture browser", &show_texture_browser_window);

		if (0 < is_texture_browser_prepared && is_texture_browser_prepared < 5)
		{
			ImGui::Text("Loading textures...\nPlease wait...");
		}
		else // If texture was already loaded
		{
			static int switch_texture_browser_tabs = 1;

			ImGui::SameLine(0.0, 0.0f);
			if (ImGui::Button("Leaf", ImVec2(120.0f, 25.0f))) { switch_texture_browser_tabs = 1; }
			ImGui::SameLine(0.0, 5.0f);
			if (ImGui::Button("Bark", ImVec2(120.0f, 25.0f))) { switch_texture_browser_tabs = 2; }

			ImGui::Separator();

			if (switch_texture_browser_tabs == 1)
			{
				ImGui::Text("Leaf");
				ImGui::Separator();

				for (int i = 1; i <= (NUMBER_OF_LEAF_TEXTURES); i++)
				{
					if (ImGui::ImageButton((void*)(intptr_t)m_leaf_texture_list[i], ImVec2(256, 256))) // If image button clicked
					{
						Debugger::GetInstance()->WriteMessage(std::to_string(i) + " th leaf image clicked!");
						m_leaf_texture_selected_texture_ID = m_leaf_texture_list[i];
					}
				}
			}
			else if (switch_texture_browser_tabs == 2)
			{
				ImGui::Text("Bark");
				ImGui::Separator();

				for (int i = 1; i <= (NUMBER_OF_BARK_TEXTURES); i++)
				{
					if (ImGui::ImageButton((void*)(intptr_t)m_bark_texture_list[i], ImVec2(256, 256))) // If image button clicked
					{
						Debugger::GetInstance()->WriteMessage(std::to_string(i) + " th bark image clicked!");
						m_bark_texture_selected_texture_ID = m_bark_texture_list[i];
					}
				}
			}
		}

		ImGui::End();
	}

	// 4. Show custom light window
	if (show_custom_light_window)
	{
		ImGui::Begin("Custom light", &show_custom_light_window);

		static int switchTabs = 1;

		ImGui::SameLine(0.0, 0.0f);
		if (ImGui::Button("Intensity", ImVec2(120.0f, 25.0f))) { switchTabs = 1; }
		ImGui::SameLine(0.0, 5.0f);
		if (ImGui::Button("Color", ImVec2(120.0f, 25.0f))) { switchTabs = 2; }

		ImGui::Separator();

		if (switchTabs == 1)
		{
			ImGui::Text("Intensity");
			ImGui::Separator();
			ImGui::SliderFloat("Multiplier", &light_intensity, 1.0f, 1000.0f);
			ImGui::SliderFloat("Attenuation", &light_attenuation, 1.0f, 100.0f);

			ImGui::Separator();
			ImGui::Text("Position");
			ImGui::Separator();
			ImGui::InputFloat("Position X", &light_position[0], 10);
			ImGui::InputFloat("Position Y", &light_position[1], 10);
			ImGui::InputFloat("Position Z", &light_position[2], 10);
			ImGui::Separator();
		}
		else if (switchTabs == 2)
		{
			ImGui::Text("Color");
			ImGui::Separator();
			ImGui::ColorEdit3("Ambient", ambient_color);
			ImGui::ColorEdit3("Diffuse", diffuse_color);
			ImGui::ColorEdit3("Specular", specular_color);
			ImGui::Separator();
		}

		ImGui::End();
	}



	// 7. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!)
	if (show_demo_window)
	{
		ImGui::ShowDemoWindow(&show_demo_window);
	}

	// 8. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window
	if (show_hello_world_window)
	{
		static float f = 0.0f;
		static int counter = 0;

		ImGui::Begin("Hello, world!");                          // Create a window called "Hello, world!" and append into it.

		ImGui::Text("This is some useful text.");               // Display some text (you can use a format strings too)
		ImGui::Checkbox("Demo Window", &show_demo_window);      // Edit bools storing our window open/close state
		ImGui::Checkbox("Another Window", &show_another_window);

		ImGui::SliderFloat("float", &f, 0.0f, 1.0f);            // Edit 1 float using a slider from 0.0f to 1.0f
		ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color

		if (ImGui::Button("Button"))                            // Buttons return true when clicked (most widgets return true when edited/activated)
		{
			counter++;
		}
		ImGui::SameLine();
		ImGui::Text("counter = %d", counter);

		ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
		ImGui::End();
	}

	// 9. Show another simple window
	if (show_another_window)
	{
		ImGui::Begin("Another Window", &show_another_window);   // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked)
		ImGui::Text("Hello from another window!");
		if (ImGui::Button("Close Me")) { show_another_window = false; }
		ImGui::End();
	}

	// 10. Show software information
	if (show_software_information_window)
	{
		ImGui::OpenPopup("Software information");
		if (ImGui::BeginPopupModal("Software information", NULL, ImGuiWindowFlags_AlwaysAutoResize))
		{
			ImGui::Text("All these inventive L-system generator & camera made by");
			ImGui::Text("- Zian Wang");

			ImGui::Text("All these cool 3D model generator & OBJ exporter made by");
			ImGui::Text("- Han Zhang");

			ImGui::Text("All these beautiful renderer & shader & UI made by");
			ImGui::Text("- Jungmin Suh");

			ImGui::Text("We would like to give special thanks to");
			ImGui::Text("- Ulrich Neumann \n\n");

			ImGui::Text("APP version - 1.2 (Alpha) ");
			ImGui::Text("Debugger version - 3.8 \n\n");
			ImGui::Separator();

			if (ImGui::Button("Copyright information", ImVec2(400, 25)))
			{
				
			}

			if (ImGui::Button("Close", ImVec2(400, 25)))
			{
				show_software_information_window = false;
				ImGui::CloseCurrentPopup();
			}
			ImGui::SetItemDefaultFocus();
			ImGui::EndPopup();
		}
	}


	ImGui::Render();
	ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}


void GuiManager::DeleteGui()
{
	// ImGui cleanup
	ImGui_ImplOpenGL3_Shutdown();
	ImGui_ImplGlfw_Shutdown();
	ImGui::DestroyContext();
}


void GuiManager::PrepareTextureBrowserPalette()
{
	Debugger::GetInstance()->WriteMessage("Loading leaf textures... ");
	for (unsigned int i = 1; i <= NUMBER_OF_LEAF_TEXTURES; i++)
	{
		Debugger::GetInstance()->WriteMessage("[Leaf texture item : " + std::to_string(i) + "] " + std::to_string((float)i / NUMBER_OF_LEAF_TEXTURES * 100) + "%");
		unsigned int temp_leaf_ID = LoadGuiTexture(Debugger::GetInstance()->GetProgramPath() + "\\580_Rendering_Project\\Resources\\Textures\\Leaf\\" + std::to_string(i) + ".png");

		// Save IDs to Map
		m_leaf_texture_list.insert(std::pair<unsigned int, unsigned int>(i, temp_leaf_ID));
	}

	Debugger::GetInstance()->WriteMessage("Loading bark textures... ");
	for (unsigned int i = 1; i <= NUMBER_OF_BARK_TEXTURES; i++)
	{
		Debugger::GetInstance()->WriteMessage("[Bark texture item : " + std::to_string(i) + "] " + std::to_string((float)i / NUMBER_OF_BARK_TEXTURES * 100) + "%");
		unsigned int temp_bark_ID = LoadGuiTexture(Debugger::GetInstance()->GetProgramPath() + "\\580_Rendering_Project\\Resources\\Textures\\Bark\\" + std::to_string(i) + ".png");

		// Save IDs to Map
		m_bark_texture_list.insert(std::pair<unsigned int, unsigned int>(i, temp_bark_ID));
	}
}


unsigned int GuiManager::LoadGuiTexture(const std::string& filepath)
{
	unsigned int renderer_ID = 0;
	unsigned char* local_buffer = nullptr;
	int width = 0, height = 0, bits_per_pixel = 0;

	stbi_set_flip_vertically_on_load(false); // we need to filp vertically because OpenGL (0, 0) is bottom left
	local_buffer = stbi_load(filepath.c_str(), &width, &height, &bits_per_pixel, 4); // (Image location, X size, Y size, how many bits in pixel, RGBA)

	// Generate the openGL texture object
	GLCALL(glGenTextures(1, &renderer_ID));

	// Bind the texture object
	GLCALL(glBindTexture(GL_TEXTURE_2D, renderer_ID));

	// 임시
	//glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);

	// Set texture rendering mode
	GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); // minification filter
	GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); // magnification filter
	GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)); // horizontal clamp (we do not want tiling)
	GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)); // vertical clamp (we do not want tiling) // GL_CLAMP_TO_EDGE = do not repeat

	// Upload the pixels to the texture
	GLCALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, local_buffer));

	// Generate the mipmaps
	GLCALL(glGenerateMipmap(GL_TEXTURE_2D));

	// Unbind the texture
	GLCALL(glBindTexture(GL_TEXTURE_2D, 0));

	if (local_buffer) // m_local_buffer != nullptr
	{
		stbi_image_free(local_buffer);
	}

	return renderer_ID;
}

