/*
 * 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 "Base/ICloseable.hpp"
#include "Base/Render/RenderResource.hpp"
#include "Math/AABB.hpp"
#include "Base/Utils.hpp"
#include "Vertex.hpp"
#include <string>

namespace OpenVulkano
{
	namespace Scene
	{
		enum class VertexIndexType
		{
			UINT16 = sizeof(uint16_t), UINT32 = sizeof(uint32_t)
		};

		class Geometry : public RenderResourceHolder<Geometry>, public ICloseable
		{
			friend class MeshLoader;
		public:
			uint32_t vertexCount = 0, indexCount = 0;
			Vertex* vertices = nullptr;
			void* indices = nullptr;
			VertexIndexType indexType = VertexIndexType::UINT16;
			bool ownsMemory = true, freeAfterUpload = true;
			Math::AABB aabb;
		public:
			Geometry() = default;
			Geometry(const Geometry& other);
			Geometry& operator=(const Geometry& other);
			Geometry(Geometry&& other) noexcept;
			Geometry& operator=(Geometry&& other) noexcept;
			~Geometry();

			/**
			 * \brief Creates the arrays for the vertices and indices. They will not be filled!
			 * \param vertexCount The amount of vertices that will be used
			 * \param indexCount The amount of indices that will be used
			 */
			void Init(uint32_t vertexCount, uint32_t indexCount);

			void SetIndices(const uint32_t* data, uint32_t size, uint32_t dstOffset = 0) const;

			void Close() override;
			
			void Free();

			Vertex* GetVertices() const { return vertices; }
			void* GetIndices() const { return indices; }
			uint16_t* GetIndices16() const { return static_cast<uint16_t*>(indices); }
			uint32_t* GetIndices32() const { return static_cast<uint32_t*>(indices); }
			uint32_t GetIndexCount() const { return indexCount; }
			uint32_t GetVertexCount() const { return vertexCount; }
			bool OwnsMemory() const { return ownsMemory; }
			void SetOwnsMemory(bool val) { ownsMemory = val; }
			bool FreeAfterUpload() const { return freeAfterUpload; }
			void SetFreeAfterUpload(bool val) { freeAfterUpload = val; }
			void CalculateAABB();
		private:
			void Swap(Geometry& other) noexcept;
		};
	}
}
