#pragma once
#include "type.h"
#include "field.h"
#include "view.h"
namespace refl {
	enum ClassFlag :uint32_t {
		CLASS_NONE_FLAG = 0,
		CLASS_TRIVIAL_FLAG = 1 << 0,
	};
	struct vtable_uclass
	{
		//class
		const FieldPtr* (*GetField)(const UClass*, const Name&, bool);
		//function
		std::vector<const UClass*>(*GetParams)(const UClass*);
		//function
		void (*Call)(const FieldPtr*, const sarray<ArgsView>& ArgsList);

		//object
		void (*InitObject)(void*);
		void (*CopyObject)(void*, const void*);
		void (*DestObject)(void*);
	};
	class UClass{
	public:
		using enum FieldFlag;
		using enum ClassFlag;
		Name name;
		uint32_t size;
		uint32_t flag{0};
		const UClass* parent;
		vtable_uclass vtable{};
	public:
		constexpr UClass(std::string_view name, uint32_t size, const UClass* parent = nullptr)
			:name(name), size(size), parent(parent){}
		ObjectView 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 {
			constexpr UClass* cls = &TypeInfo<T>::StaticClass;
			if (bthis) {
				return cls == this;
			}
			const UClass* _parent = this;
			while (_parent != nullptr) {
				if (_parent == cls) {
					return true;
				}
				_parent = _parent->parent;
			}
			return false;
		}
	public:
		const FieldPtr* GetField(const Name& name, bool isMethod)const {
			if (vtable.GetField) {
				return vtable.GetField(this, name, isMethod);
			}
			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;
		}
	};
}