/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

#pragma once

#include "Node.hpp"
#include "Camera.hpp"
#include "Base/Logger.hpp"
#include "Base/Utils.hpp"

namespace OpenVulkano
{
	namespace Scene
	{
		class Scene : public ICloseable
		{
		public:
			Node* root;
			std::vector<Drawable*> shapeList;
			Camera* camera;

		public:
			Scene() : root(nullptr) {}

			virtual ~Scene()
			{
				if (root) Scene::Close();
			}

			void Init()
			{
				Node* newRoot = new Node();
				newRoot->Init();
				Init(newRoot);
			}

			void Init(Node* root)
			{
				if (root->GetParent()) throw std::runtime_error("Node has a parent! Only nodes without a parent may be a root node!");
				root->SetScene(this);
				root->SetParent(root);
				this->root = root;
			}

			void Close() override
			{
				//TODO
			}

			Node* GetRoot() const
			{
				return root;
			}

			void RegisterDrawable(Drawable* drawable)
			{
				if (drawable->GetScene() != this) drawable->SetScene(this);
				if (Utils::Contains(shapeList, drawable)) return; // Prevent duplicate entries
				shapeList.push_back(drawable);
				if (shapeList.size() > 1 && shapeList[shapeList.size() - 2]->GetDrawPhase() < drawable->GetDrawPhase())
				{
					std::sort(shapeList.begin(), shapeList.end(),
							  [](Drawable* a, Drawable* b) { return a->GetDrawPhase() > b->GetDrawPhase(); });
				}
			}

			void RemoveDrawable(Drawable* drawable)
			{
				Utils::Remove(shapeList, drawable);
				drawable->SetScene(nullptr);
			}

			virtual void SetCamera(Camera* camera)
			{
				this->camera = camera;
			}

			Camera* GetCamera() const
			{
				return camera;
			}
			
			/**
			 * \brief Checks if the scene is valid and attempts to fix problems.
			 */
			void Validate()
			{
				for (Drawable* drawable : shapeList)
				{
					if(drawable->GetScene() != this)
					{
						if (!drawable->GetScene()) drawable->SetScene(this);
						else Logger::SCENE->error("Scene is linked with drawable from different scene!!!"); //TODO handle
					}
				}
				//TODO check node tree
			}
		};
	}
}
