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

////////////////////////////////////////////////////////////////////////////////////
//	Text Editor View

#include "TextEditorView.h"
#include "IUiSystem.h"
#include "imgui.h"
#include <fstream>
#include <streambuf>

namespace GameEngine {

TextEditorView::TextEditorView(const ApplicationFramework::IApplication& app)
    : m_application(app)
{
}

void TextEditorView::AddShowMenuItem()
{
    ImGui::MenuItem("Show Text Editor", NULL, &m_open);
}

void TextEditorView::Initialize()
{
	auto lang = TextEditor::LanguageDefinition::CPlusPlus();

	// set your own known preprocessor symbols...
	static const char* ppnames[] = {
		"NULL", "PM_REMOVE",
		"ZeroMemory", "DXGI_SWAP_EFFECT_DISCARD", "D3D_FEATURE_LEVEL", "D3D_DRIVER_TYPE_HARDWARE", "WINAPI","D3D11_SDK_VERSION", "assert"
	};
	// ... and their corresponding values
	static const char* ppvalues[] =
	{ 
		"#define NULL ((void*)0)", 
		"#define PM_REMOVE (0x0001)",
		"Microsoft's own memory zapper function\n(which is a macro actually)\nvoid ZeroMemory(\n\t[in] PVOID  Destination,\n\t[in] SIZE_T Length\n); ", 
		"enum DXGI_SWAP_EFFECT::DXGI_SWAP_EFFECT_DISCARD = 0", 
		"enum D3D_FEATURE_LEVEL", 
		"enum D3D_DRIVER_TYPE::D3D_DRIVER_TYPE_HARDWARE  = ( D3D_DRIVER_TYPE_UNKNOWN + 1 )",
		"#define WINAPI __stdcall",
		"#define D3D11_SDK_VERSION (7)",
		" #define assert(expression) (void)(                                                  \n"
        "    (!!(expression)) ||                                                              \n"
        "    (_wassert(_CRT_WIDE(#expression), _CRT_WIDE(__FILE__), (unsigned)(__LINE__)), 0) \n"
        " )"
	};

	for (int i = 0; i < sizeof(ppnames) / sizeof(ppnames[0]); ++i)
	{
		TextEditor::Identifier id;
		id.mDeclaration = ppvalues[i];
		lang.mPreprocIdentifiers.insert(std::make_pair(std::string(ppnames[i]), id));
	}

	// set your own identifiers
	static const char* identifiers[] = {
		"HWND", "HRESULT", "LPRESULT","D3D11_RENDER_TARGET_VIEW_DESC", "DXGI_SWAP_CHAIN_DESC","MSG","LRESULT","WPARAM", "LPARAM","UINT","LPVOID",
		"ID3D11Device", "ID3D11DeviceContext", "ID3D11Buffer", "ID3D11Buffer", "ID3D10Blob", "ID3D11VertexShader", "ID3D11InputLayout", "ID3D11Buffer",
		"ID3D10Blob", "ID3D11PixelShader", "ID3D11SamplerState", "ID3D11ShaderResourceView", "ID3D11RasterizerState", "ID3D11BlendState", "ID3D11DepthStencilState",
		"IDXGISwapChain", "ID3D11RenderTargetView", "ID3D11Texture2D", "TextEditor"
	};

	static const char* idecls[] = 
	{
		"typedef HWND_* HWND", "typedef long HRESULT", "typedef long* LPRESULT", "struct D3D11_RENDER_TARGET_VIEW_DESC", "struct DXGI_SWAP_CHAIN_DESC",
		"typedef tagMSG MSG\n * Message structure","typedef LONG_PTR LRESULT","WPARAM", "LPARAM","UINT","LPVOID",
		"ID3D11Device", "ID3D11DeviceContext", "ID3D11Buffer", "ID3D11Buffer", "ID3D10Blob", "ID3D11VertexShader", "ID3D11InputLayout", "ID3D11Buffer",
		"ID3D10Blob", "ID3D11PixelShader", "ID3D11SamplerState", "ID3D11ShaderResourceView", "ID3D11RasterizerState", "ID3D11BlendState", "ID3D11DepthStencilState",
		"IDXGISwapChain", "ID3D11RenderTargetView", "ID3D11Texture2D", "class TextEditor"
	};

	for (int i = 0; i < sizeof(identifiers) / sizeof(identifiers[0]); ++i)
	{
		TextEditor::Identifier id;
		id.mDeclaration = std::string(idecls[i]);
		lang.mIdentifiers.insert(std::make_pair(std::string(identifiers[i]), id));
	}

	m_textEditor.SetLanguageDefinition(lang);

	// "Son of Obsidian" palette
    TextEditor::Palette palette = { {
			0xFFF3F2F1,	 // Default
			0xFF63C793,	 // Keyword	
			0xFF22CDFF,	 // Number
			0xFF0076EC,	 // String
			0xFF0076EC,  // Char literal
			0xFFF3F2F1, // Punctuation
			0xFFC2CFCF,  // Preprocessor
			0xFFB18C67,  // Identifier
			0xFF0076EC,  // Known identifier
			0xFFBEA281,  // Preproc identifier
			0xFF7B7466,  // Comment (single line)
			0xFF7B7466,  // Comment (multi line)
			0xFF2A2822,  // Background
			0xFFADAFAE,  // Cursor
			0xFF64614F,  // Selection
			0xFF463a96,  // ErrorMarker
			0x4000f080, // Breakpoint
			0xFFF3F2F1,  // Line number
			0xFF4C4642,  // Current line fill
			0xFF3C3632,  // Current line fill (inactive)
			0xFF4C4642,  // Current line edge
            //0xFF554E4B   // invisibles (not supported by ImGuiTextEditor)
    } };

    m_textEditor.SetPalette(palette);

	// error markers
	TextEditor::ErrorMarkers markers;
	//markers.insert(std::make_pair<int, std::string>(6, "Example error here:\nInclude file not found: \"TextEditor.h\""));
	//markers.insert(std::make_pair<int, std::string>(41, "Another example error"));
	m_textEditor.SetErrorMarkers(markers);

	// "breakpoint" markers
	TextEditor::Breakpoints bpts;
	//bpts.insert(24);
	//bpts.insert(47);
	m_textEditor.SetBreakpoints(bpts);

	static const char* fileToEdit = ".modules/ImGuiColorTextEdit/TextEditor.cpp";

	{
		std::ifstream t(fileToEdit);
		if (t.good())
		{
			std::string str((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
			m_textEditor.SetText(str);
		}
	}
}

void TextEditorView::Shutdown()
{
}

void TextEditorView::Update()
{
    if (m_open)
    {
		const uint32_t bgColor = 0xFF2A2822;
		ImGui::PushStyleColor(ImGuiCol_WindowBg, ImGui::ColorConvertU32ToFloat4(bgColor));
        if (ImGui::Begin("Text Editor", &m_open))
		{
			ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[m_application.UiSystem()->FixedFontIndex()]);
			m_textEditor.SetImGuiChildIgnored(true);
			m_textEditor.Render("TextEditor");
			ImGui::PopFont();
		}
        ImGui::End();
		ImGui::PopStyleColor();	
    }
}

} // GameEngine namespace
