/*
 * Copyright 2015 - 2025 gary@drinkingtea.net
 *
 * 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

#if __has_include(<vector>)
#include <vector>
#endif

#if __has_include(<array>)
#include <array>
#endif

#if __has_include(<QVector>)
#include <QVector>
#endif

#include <ox/std/array.hpp>
#include <ox/std/istring.hpp>
#include <ox/std/string.hpp>
#include <ox/std/strops.hpp>
#include <ox/std/types.hpp>
#include <ox/std/typetraits.hpp>
#include <ox/std/vector.hpp>

namespace ox {

namespace types {
constexpr StringLiteral BasicString = "net.drinkingtea.ox.BasicString";
constexpr StringLiteral IString     = "net.drinkingtea.ox.IString";
constexpr StringLiteral String      = "B.string";
constexpr StringLiteral Bool        = "B.bool";
constexpr StringLiteral Uint8       = "B.uint8";
constexpr StringLiteral Uint16      = "B.uint16";
constexpr StringLiteral Uint32      = "B.uint32";
constexpr StringLiteral Uint64      = "B.uint64";
constexpr StringLiteral Int8        = "B.int8";
constexpr StringLiteral Int16       = "B.int16";
constexpr StringLiteral Int32       = "B.int32";
constexpr StringLiteral Int64       = "B.int64";
}

template<typename T>
consteval bool isBasicString(const T*) noexcept {
	return false;
}

template<std::size_t SmallVecSize>
consteval bool isBasicString(const BasicString<SmallVecSize>*) noexcept {
	return true;
}

template<typename T>
constexpr bool isBasicString_v = isBasicString(static_cast<const T*>(nullptr));

static_assert(isBasicString_v<ox::BasicString<0ul>>);
static_assert(isBasicString_v<ox::BasicString<8ul>>);
static_assert(isBasicString_v<ox::String>);

template<typename T>
consteval bool isIString(const T*) noexcept {
	return false;
}

template<std::size_t SmallVecSize>
consteval bool isIString(const BasicString<SmallVecSize>*) noexcept {
	return true;
}

template<typename T>
constexpr bool isIString_v = isIString(static_cast<const T*>(nullptr));

static_assert(isBasicString_v<ox::BasicString<0ul>>);
static_assert(isBasicString_v<ox::BasicString<8ul>>);
static_assert(isBasicString_v<ox::String>);

template<typename T>
consteval bool isOxVector(const T*) noexcept {
	return false;
}

template<typename T, std::size_t SmallVecSize>
consteval bool isOxVector(const Vector<T, SmallVecSize>*) noexcept {
	return true;
}

template<typename T>
constexpr bool isOxVector_v = isVector(static_cast<const T*>(nullptr));

template<typename T>
consteval bool isVector(const T*) noexcept {
	return false;
}

template<typename T, std::size_t SmallVecSize>
consteval bool isVector(const Vector<T, SmallVecSize>*) noexcept {
	return true;
}

#if __has_include(<vector>)
template<typename T>
consteval bool isVector(const std::vector<T>*) noexcept {
	return true;
}
#endif

#if __has_include(<QVector>)
template<typename T>
constexpr bool isVector(const QVector<T>*) noexcept {
	return true;
}
#endif

template<typename T>
constexpr bool isVector_v = isVector(static_cast<const T*>(nullptr));

static_assert(isVector_v<ox::Vector<unsigned int, 0ul>>);

template<typename T>
constexpr bool isBareArray_v = false;

template<typename T>
constexpr bool isBareArray_v<T[]> = true;

template<typename T, std::size_t sz>
constexpr bool isBareArray_v<T[sz]> = true;

template<typename T>
consteval bool isArray(T*) noexcept {
	return false;
}

template<typename T>
constexpr bool isArray_v = isArray(static_cast<T*>(nullptr));

template<typename T>
constexpr bool isArray_v<T[]> = true;

template<typename T, std::size_t sz>
constexpr bool isArray_v<T[sz]> = true;

template<typename T, std::size_t sz>
constexpr bool isArray_v<Array<T, sz>> = true;

template<typename T, std::size_t sz>
consteval bool isArray(T[sz]) noexcept {
	return true;
}

template<typename T, std::size_t sz>
consteval bool isArray(Array<T, sz>) noexcept {
	return true;
}

template<typename T>
constexpr bool isSmartPtr_v = false;

template<typename T>
constexpr bool isSmartPtr_v<::ox::UPtr<T>> = true;

#if __has_include(<array>)
template<typename T>
constexpr bool isSmartPtr_v<::std::unique_ptr<T>> = true;
#endif


template<typename Union, bool force = false> requires(force || is_union_v<Union>)
class UnionView {

	protected:
		int m_idx = -1;
		Union *m_union = nullptr;

	public:
		constexpr UnionView(Union *u, int idx) noexcept: m_idx(idx), m_union(u) {
		}

		[[nodiscard]]
		constexpr auto idx() const noexcept {
			return m_idx;
		}

		[[nodiscard]]
		constexpr const Union *get() const noexcept {
			return m_union;
		}

		[[nodiscard]]
		constexpr Union *get() noexcept {
			return m_union;
		}

};

}
