#pragma once
#include "field.h"
#include "view.h"
#include "meta.h"
namespace refl {
	enum ClassFlag :uint32_t {
		CLASS_NONE_FLAG = 0,
		CLASS_TRIVIAL_FLAG = 1 << 0,
		CLASS_POINTER_FLAG = 1 << 1,
		CLASS_ARRAY_FLAG   = 1 << 2,
	};
	using enum ClassFlag;
	struct vtable_uclass
	{
		//class
		const FieldPtr* (*GetField)(const UClass*, const Name&, int);
		//function
		sarray<const UClass*>(*GetParams)(const UClass*);
		//function
		void (*Call)(const FieldPtr*, const sarray<Any>& ArgsList);

		//object
		void (*InitObject)(void*);
		void (*CopyObject)(void*, const void*);
		void (*DestObject)(void*);
	};
	class UClass{
	public:
		Name name;
		uint32_t size;
		uint32_t flag{0};
		const UClass* parent;
		Meta* meta{nullptr};
		vtable_uclass vtable{};
	public:
		constexpr UClass(std::string_view name, uint32_t size, const UClass* parent = nullptr)
			:name(name), size(size), parent(parent){}
		AnyView New(void* ptr = nullptr) const{
			if (ptr == nullptr) {
				ptr = malloc(size);
				InitObject(ptr);
			}
			return { ptr , this };
		}
		template<typename T>
		T* New(T* ptr = nullptr) const{
			if (!IsChildOf<T>()) {
				return nullptr;
			}
			if (ptr == nullptr) {
				ptr = (T*)malloc(size);
			}
			InitObject(ptr);
			return ptr;
		}
		bool IsChildOf(const UClass* cls) const {
			const UClass* _parent = parent;
			while (_parent != nullptr) {
				if (_parent == cls) {
					return true;
				}
				_parent = _parent->parent;
			}
			return false;
		}
		template<typename T>
		bool IsChildOf(bool bthis = false) const {
			return IsChildOf(&TypeInfo<T>::StaticClass);
		}
	public:
		const FieldPtr* GetField(const Name& name, int index)const {
			if (vtable.GetField) {
				return vtable.GetField(this, name, index);
			}
			return nullptr; 
		}
		void InitObject(void* ptr)const {
			if (vtable.InitObject) {
				vtable.InitObject(ptr);
			}
			else {
				memset(ptr, 0, size);
			}
		}
		void CopyObject(void* dst, const void* src)const {
			if (vtable.CopyObject) {
				vtable.CopyObject(dst, src);
			}
			else {
				memcpy(dst, src, size);
			}
		}
		void DestObject(void* ptr)const {
			if (vtable.DestObject) {
				vtable.DestObject(ptr);
			}
		}
	public:
		template<_ReflCheck_Ctor T>
		static void InitObject(void* ptr) {
			T obj{};
			std::construct_at((T*)ptr, obj);
		}
		template<typename T>
		static void CopyObject(void* dst, const void* src) {
			*(T*)dst = *(T*)src;
		}
		template<_ReflCheck_Ctor T, int N>
		static void InitObject(void* ptr) {
			T* tptr = (T*)ptr;
			T obj{};
			for (int i = 0; i < N; i++) {
				std::construct_at(tptr++, obj);
			}
		}
		template<typename T, int N>
		static void CopyObject(void* dst, const void* src) {
			T* tdst = (T*)dst;
			const T* tsrc = (const T*)src;
			for (int i = 0; i < N; i++) {
				*tdst++ = *tsrc++;
			}
		}
	};
}