/*
 * 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 <magic_enum.hpp>

namespace OpenVulkano::AR
{
	class ArTrackingState final
	{
		static inline constexpr std::string_view ALT_NAMES[] = {
				"unknown", "notAvailable", "limitedInitializing",
				"limitedRelocalizing", "limitedExcessiveMotion",
				"limitedInsufficientFeatures", "normal", "paused"
		};

	public:
		enum State : uint8_t
		{
			UNKNOWN,
			UNAVAILABLE,
			INITIALIZING,
			RELOCALIZING,
			EXCESSIVE_MOTION,
			INSUFFICIENT_FEATURES,
			NORMAL,
			PAUSED
		};

		ArTrackingState() : ArTrackingState(UNKNOWN) {}

		ArTrackingState(State state) : m_state(state) {}

		[[nodiscard]] constexpr bool IsLimited() const
		{
			return m_state > UNAVAILABLE && m_state < NORMAL;
		}

		[[nodiscard]] constexpr bool IsUnavailable() const
		{
			return m_state == PAUSED || m_state == UNAVAILABLE;
		}

		[[nodiscard]] constexpr bool IsGood() const
		{
			return m_state == NORMAL;
		}

		[[nodiscard]] constexpr bool IsPaused() const
		{
			return m_state == PAUSED;
		}

		[[nodiscard]] constexpr std::string_view GetName() const
		{
			return magic_enum::enum_name(m_state);
		}

		[[nodiscard]] constexpr std::string_view GetAltName() const
		{
			return ALT_NAMES[m_state];
		}

		[[nodiscard]] constexpr bool operator ==(State rhs)
		{
			return m_state == rhs;
		}

		[[nodiscard]] constexpr bool operator !=(State rhs)
		{
			return m_state != rhs;
		}

		[[nodiscard]] constexpr bool operator ==(const ArTrackingState& rhs)
		{
			return m_state == rhs.m_state;
		}

		[[nodiscard]] constexpr bool operator !=(const ArTrackingState& rhs)
		{
			return m_state != rhs.m_state;
		}

		[[nodiscard]] constexpr operator State()
		{
			return m_state;
		}

		[[nodiscard]] constexpr operator uint8_t()
		{
			return m_state;
		}

		static ArTrackingState GetFromName(std::string_view name)
		{
			auto result = magic_enum::enum_cast<State>(name);
			if (result.has_value()) return ArTrackingState(result.value());
			return GetFromAltName(name);
		}

		static ArTrackingState GetFromAltName(std::string_view name)
		{
			uint8_t i = 0;
			for(const std::string_view& n : ALT_NAMES)
			{
				if (n == name) return static_cast<State>(i);
				i++;
			}
			return UNKNOWN;
		}

	private:
		State m_state;
	};
}