#pragma once

#include <psemek/util/hstring.hpp>
#include <psemek/util/hash_table.hpp>

#include <vector>
#include <string>
#include <string_view>
#include <cstdint>
#include <optional>

namespace psemek::util
{

	template <typename T, typename Index = std::uint32_t>
	struct resource_container
	{
		using object_id = Index;
		using iterator = T *;
		using const_iterator = T const *;

		struct object
		{
			std::string const name;
			T value;

			object(std::string name, T value)
				: name(std::move(name))
				, value(std::move(value))
			{}
		};

		object & operator[] (Index id)
		{
			return objects_[id];
		}

		object const & operator[] (Index id) const
		{
			return objects_[id];
		}

		Index add(std::string name, T value)
		{
			Index id = objects_.size();
			name_map_[name] = id;
			objects_.emplace_back(std::move(name), std::move(value));
			return id;
		}

		std::optional<object_id> find(std::string_view const & name) const
		{
			if (auto it = name_map_.find(name); it != name_map_.end())
				return it->second;
			return std::nullopt;
		}

		std::size_t size() const
		{
			return objects_.size();
		}

		T * begin()
		{
			return objects_.data();
		}

		T * end()
		{
			return begin() + size();
		}

		T const * begin() const
		{
			return objects_.data();
		}

		T const * end() const
		{
			return begin() + size();
		}

	private:
		std::vector<object> objects_;
		util::hash_map<util::hstring, Index> name_map_;
	};

}
