ConceptionTestApp::ConceptionTestApp(InputManager & InputManager)
	: App(InputManager),
	  m_CurrentProject(),
	  m_TypingModule()
	  /*OverlayCanvas(Vector2n(0, 0), false),
	  SystemInputListener(),
	  ControlModuleMapping0(),
	  ControlModuleMapping1(),
	  WidgetManager(),
	  WidgetModule(WidgetManager),
	  UnrealCameraModule(MainCanvas),
	  UnrealCameraModule2TEST(MainCanvas2TEST),
	  TypingModule(),*/
{
	/*{
		{ auto Widget = new ButtonWidget(Vector2n(10, 10)); WidgetManager.Add(Widget); Widget->SetOwnerCanvas(OverlayCanvas); }
		{ auto Widget = new ButtonWidget(Vector2n(50, 10)); WidgetManager.Add(Widget); Widget->SetOwnerCanvas(OverlayCanvas); }
		{ auto Widget = new TextFieldWidget(Vector2n(10, 50)); WidgetManager.Add(Widget); Widget->SetOwnerCanvas(OverlayCanvas); }

		{ auto Widget = new ListWidget(Vector2n(-200, -292), CurrentProject.GetStdIncludes()); WidgetManager.Add(Widget); Widget->SetOwnerCanvas(MainCanvas); }
	}

	{
		std::vector<InputManager::InputId> ButtonMappings; ButtonMappings.push_back(InputManager::InputId(1000, GLFW_MOUSE_BUTTON_LEFT));
		std::vector<InputManager::InputId> SliderMappings;
		std::vector<InputManager::InputId> AxisMappings; AxisMappings.push_back(InputManager::InputId(1000, 0)); AxisMappings.push_back(InputManager::InputId(1000, 1));
		std::vector<InputManager::InputId> PositiveConstraints;
		std::vector<InputManager::InputId> NegativeConstraints;
		ControlModuleMapping0.AddMapping(&WidgetModule, 0, ButtonMappings, SliderMappings, AxisMappings, PositiveConstraints, NegativeConstraints);
		WidgetModule.SetOwnerCanvas(OverlayCanvas);
	}
	{
		std::vector<InputManager::InputId> ButtonMappings; ButtonMappings.push_back(InputManager::InputId(1000, GLFW_MOUSE_BUTTON_LEFT));
		std::vector<InputManager::InputId> SliderMappings; SliderMappings.push_back(InputManager::InputId(1000, 0)); SliderMappings.push_back(InputManager::InputId(1000, 1)); SliderMappings.push_back(InputManager::InputId(1000, 2));
		std::vector<InputManager::InputId> AxisMappings; AxisMappings.push_back(InputManager::InputId(1000, 0)); AxisMappings.push_back(InputManager::InputId(1000, 1));
		std::vector<InputManager::InputId> PositiveConstraints;
		std::vector<InputManager::InputId> NegativeConstraints;
		ControlModuleMapping0.AddMapping(&UnrealCameraModule2TEST, 0, ButtonMappings, SliderMappings, AxisMappings, PositiveConstraints, NegativeConstraints);
		UnrealCameraModule2TEST.SetOwnerCanvas(MainCanvas2TEST);
	}
	{
		std::vector<InputManager::InputId> ButtonMappings; ButtonMappings.push_back(InputManager::InputId(1000, GLFW_MOUSE_BUTTON_LEFT));
		std::vector<InputManager::InputId> SliderMappings; SliderMappings.push_back(InputManager::InputId(1000, 0)); SliderMappings.push_back(InputManager::InputId(1000, 1)); SliderMappings.push_back(InputManager::InputId(1000, 2));
		std::vector<InputManager::InputId> AxisMappings; AxisMappings.push_back(InputManager::InputId(1000, 0)); AxisMappings.push_back(InputManager::InputId(1000, 1));
		std::vector<InputManager::InputId> PositiveConstraints;
		std::vector<InputManager::InputId> NegativeConstraints;
		ControlModuleMapping0.AddMapping(&UnrealCameraModule, 0, ButtonMappings, SliderMappings, AxisMappings, PositiveConstraints, NegativeConstraints);
		UnrealCameraModule.SetOwnerCanvas(MainCanvas);
	}
	ControlModuleMapping0.DoneAdding();

	g_TypingModuleTEST = &TypingModule;
	{
		std::vector<InputManager::InputId> ButtonMappings; ButtonMappings.push_back(InputManager::InputId(0, GLFW_KEY_BACKSPACE));
		std::vector<InputManager::InputId> SliderMappings;
		std::vector<InputManager::InputId> AxisMappings; AxisMappings.push_back(InputManager::InputId(1000, 0)); AxisMappings.push_back(InputManager::InputId(1000, 1));
		std::vector<InputManager::InputId> PositiveConstraints;
		std::vector<InputManager::InputId> NegativeConstraints;
		ControlModuleMapping1.AddMapping(&TypingModule, 0, ButtonMappings, SliderMappings, AxisMappings, PositiveConstraints, NegativeConstraints);
		TypingModule.SetOwnerCanvas(OverlayCanvas);
	}
	ControlModuleMapping1.DoneAdding();

	m_InputManager.RegisterListener(&SystemInputListener);
	m_InputManager.RegisterListener(&ControlModuleMapping0);
	m_InputManager.RegisterListener(&ControlModuleMapping1);*/

	/*{
		MainCanvas.RenderBackground();

		MainCanvas.SetupTransform();
		{
			CurrentProject.Render();

			WidgetManager.Render(MainCanvas);
		}
		MainCanvas.EndTransform();
	}

	{
		MainCanvas2TEST.RenderBackground();

		MainCanvas2TEST.SetupTransform();
		{
			CurrentProject.Render();

			WidgetManager.Render(MainCanvas2TEST);
		}
		MainCanvas2TEST.EndTransform();
	}

	{
		OverlayCanvas.SetupTransform();
		{
			WidgetManager.Render(OverlayCanvas);

			g_TypingModuleTEST->Render();
		}
		OverlayCanvas.EndTransform();
	}*/

	{
		auto MainCanvas = new Canvas(Vector2n(50, 50), true, true);

		MainCanvas->AddWidget(new ButtonWidget(Vector2n(0, 0), []() {} ));
		MainCanvas->AddWidget(new ButtonWidget(Vector2n(10, 10), []() {} ));
		//MainCanvas->AddWidget(new ListWidget<ConceptId>(Vector2n(-200, -292), m_CurrentProject.GetStdIncludes()));
		MainCanvas->AddWidget(new TextFieldWidget(Vector2n(-400, -100), m_TypingModule));

		m_Widgets.push_back(std::unique_ptr<Widget>(MainCanvas));
	}

	{
		auto MainCanvas2TEST = new Canvas(Vector2n(800, 100), true, true);

		m_Widgets.push_back(std::unique_ptr<Widget>(MainCanvas2TEST));
	}

	{
		auto OverlayCanvas = new Canvas(Vector2n(0, 0), false, false);

		OverlayCanvas->AddWidget(new ButtonWidget(Vector2n(10, 10), []() {} ));
		OverlayCanvas->AddWidget(new ButtonWidget(Vector2n(50, 10), []() {} ));
		//OverlayCanvas->AddWidget(new TextFieldWidget(Vector2n(10, 50)));
		//OverlayCanvas->AddWidget(new TextFieldWidget(Vector2n(10, 100)));
		//OverlayCanvas->AddWidget(new TextFieldWidget(Vector2n(10, 150)));

		m_Widgets.push_back(std::unique_ptr<Widget>(OverlayCanvas));
	}

	{
		PopulateConcepts();

		// Load program
		m_CurrentProject.LoadSampleGenProgram(*static_cast<Canvas *>(m_Widgets[0].get()));		// HACK, TEST: Should use MainCanvas or something
	}
}
ConceptionApp::ConceptionApp(InputManager & InputManager)
    : App(InputManager),
      m_CurrentProject(),
      m_TypingModule(new TypingModule())		// Gets cleaned up via unique_ptr when pushed back to m_Widgets
{
    PopulateConcepts();

    {
        auto MainCanvas = new Canvas(Vector2n(0, 0), true, true);
        //MainCanvas->MoveView(0, 336);
        MainCanvas->MoveView(1, -64);

#if 1
        {
            auto StdIncludesList = new ListWidget<ConceptId>(Vector2n::ZERO, m_CurrentProject.GetStdIncludes(), *m_TypingModule);
            StdIncludesList->m_TapAction = [=](Vector2n LocalPosition, std::vector<ConceptId> & m_List)
            {
                auto Entry = m_TypingModule->TakeString();

                if (!Entry.empty())
                {
                    auto ConceptId = FindOrCreateConcept(Entry);

                    //Insert(ConceptId);

                    // TEST
                    auto Spot = m_List.begin() + (LocalPosition.Y() / lineHeight);
                    m_List.insert(Spot, ConceptId);
                }
                else
                {
                    auto ListEntry = static_cast<decltype(m_List.size())>(LocalPosition.Y() / lineHeight);

                    if (ListEntry < m_List.size())
                    {
                        m_TypingModule->SetString(GetConcept(m_List[ListEntry]).GetContent());
                        m_List.erase(m_List.begin() + ListEntry);
                    }
                }
            };

            auto LabelledStdIncludesList = new FlowLayoutWidget(Vector2n(-280, -250), { std::shared_ptr<Widget>(new LabelWidget(Vector2n::ZERO, std::string("#include <"), LabelWidget::Background::None)),
                    std::shared_ptr<Widget>(StdIncludesList),
                    std::shared_ptr<Widget>(new LabelWidget(Vector2n::ZERO, std::string(">"), LabelWidget::Background::None))
                                                                                      }, {});
            LabelledStdIncludesList->AddBehavior(std::shared_ptr<Behavior>(new DraggablePositionBehavior(*LabelledStdIncludesList)));
            MainCanvas->AddWidget(LabelledStdIncludesList);
        }
#endif

        MainCanvas->AddWidget(new ButtonWidget(Vector2n(-100, -350), []() {
            std::cout << "Hi from anon func.\n";
        } ));
        MainCanvas->AddWidget(new ButtonWidget(Vector2n(-60, -350), []() {
            std::cout << "Second button.\n";
        } ));
        MainCanvas->AddWidget(new ToggleWidget(Vector2n(-20, -350), [](bool State) {
            std::cout << "Testing this toggle widget! It's now set to " << State << ".\n";
        }, true));
        MainCanvas->AddWidget(new LiveFunctionWidget(Vector2n(-100, 100), *m_TypingModule, m_CurrentProject));
        MainCanvas->AddWidget(new LiveProgramWidget(Vector2n(-100, -300), *m_TypingModule, m_CurrentProject));
        MainCanvas->AddWidget(new LiveProgramWidget(Vector2n(-100, -100), *m_TypingModule, m_CurrentProject));
        MainCanvas->AddWidget(new LiveGofmtWidget(Vector2n(-460, 200), *m_TypingModule, m_CurrentProject));
        MainCanvas->AddWidget(new TextFieldWidget(Vector2n(-460, 160), *m_TypingModule));
        MainCanvas->AddWidget(new ShellWidget(Vector2n(-460, 60), *m_TypingModule));
        MainCanvas->AddWidget(new SayWidget(Vector2n(-460, -100), *m_TypingModule));

        MainCanvas->AddWidget(new ConceptStringBoxWidget(Vector2n(-400, 100 + 400), *m_TypingModule));

        // TEST: Modify some Concept
        {
            auto Widget = new TextFieldWidget(Vector2n(-320, 470), *m_TypingModule);
            Widget->SetContent(GetConcept(47).GetContent());
            Widget->m_OnChange = [=]() {
                static_cast<ConceptBasic &>(ModifyConcept(47)).SetContentTEST(Widget->GetContent());
            };
            Widget->AddBehavior(std::shared_ptr<Behavior>(new DraggablePositionBehavior(*Widget)));
            MainCanvas->AddWidget(Widget);
        }

        // Label resizing test
        {
            auto SourceWidget = new TextFieldWidget(Vector2n::ZERO, *m_TypingModule);

            auto Content = [=]() -> std::string {
                return SourceWidget->GetContent();
            };
            auto LabelWidget = new class LabelWidget(Vector2n::ZERO, Content, LabelWidget::Background::Normal);

            MainCanvas->AddWidget(new FlowLayoutWidget(Vector2n(-100, -450), { std::shared_ptr<Widget>(SourceWidget), std::shared_ptr<Widget>(LabelWidget) }, {}));
        }

        // Time widget
        {
            auto Content = []() -> std::string {
                auto now = std::chrono::system_clock::now();

                auto duration = now.time_since_epoch();

                auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration).count();

                return std::to_string(seconds);
            };
            auto LabelWidget = new class LabelWidget(Vector2n(360, -340), Content, LabelWidget::Background::Normal);
            LabelWidget->AddBehavior(std::shared_ptr<Behavior>(new DraggablePositionBehavior(*LabelWidget)));

            MainCanvas->AddWidget(LabelWidget);
        }

        MainCanvas->AddWidget(new TimeWidget(Vector2n(360, -360)));		// Time widget

#if 0
        // "./GenProgram.go" file contents displayed (in real-time) in this Label Widget
        {
            auto Content = []() -> std::string {
                //return FromFileToString("./GenProgram.go");
                return FromFileToString("/Users/Dmitri/Desktop/goproj_play/src/gist.github.com/4670289.git/gistfile1.go");
            };
            auto LabelWidget = new class LabelWidget(Vector2n(-546, -186), Content, LabelWidget::Background::Normal);
            LabelWidget->AddBehavior(std::shared_ptr<Behavior>(new DraggablePositionBehavior(*LabelWidget)));

            MainCanvas->AddWidget(LabelWidget);
        }
#endif

#if 1
        {
            MainCanvas->AddWidget(new ListWidget<Concept *>(Vector2n(-730 - 450, -250), Concepts, *m_TypingModule));
        }
#endif

        m_Widgets.push_back(std::unique_ptr<Widget>(m_TypingModule));

        m_Widgets.push_back(std::unique_ptr<Widget>(MainCanvas));

        m_Widgets.push_back(std::unique_ptr<Widget>(new DebugOverlayWidget()));		// DEBUG: Print debug info
    }

    // Prepare and start the thread
    {
        m_CurrentProject.StartBackgroundThread();
    }

    {
        // Load program
        m_CurrentProject.LoadSampleGenProgram(*static_cast<Canvas *>(m_Widgets[0].get()));
    }
}