#pragma once
#include "uclass.h"
#include "view.h"
namespace refl {
	/*平凡对象的转化要支持吗
	* 比如同大小的安全转化
	* 对象从小到大
	* 对象从大到小
	*/
	using enum ClassFlag;
	bool ArgsView::ConvertTo(const UClass* toClass) {
		//子类转父类
		if (cls->IsChildOf(toClass)) {
			cls = toClass;
			return true;
		}
		if (cls->flag & CLASS_TRIVIAL_FLAG && toClass->flag & CLASS_TRIVIAL_FLAG) {
			cls = toClass;
			return true;
		}
		return false;
	}
	ArgsValueList::ArgsValueList(const sarray<ArgsValue>& args, void* memory)
		: ptr((ArgsView*)memory),data(memory), num(args.size())
	{
		if (!memory) {
			isMemoryOwner = true;
			data = malloc(GetArgsSize(args));
			ptr = (ArgsView*)data;
		}
		char* pData = ((char*)data) + num * sizeof(ArgsView);
		for (auto& arg : args) {
			arg.type->InitObject(pData);
			arg.type->CopyObject(pData, arg.val);
			ptr->val = pData;
			ptr->cls = arg.cls;
			ptr++;
			pData += arg.cls->size;
		}
		ptr = (ArgsView*)data;
	}
	inline ArgsValueList::~ArgsValueList()
	{
		if (num == 0 || !data) {
			return;
		}
		for (int i = 0; i < num; i++) {
			ptr->cls->DestObject((void*)ptr->val);
		}
		if (isMemoryOwner) {
			free(data);
		}
		num = 0;
		data = nullptr;
	}
	inline constexpr int ArgsValueList::GetArgsSize(const sarray<ArgsValue>& args)
	{
		int size = args.size() * sizeof(ArgsView);
		for (auto& arg : args) {
			size += arg.type->size;
		}
		return size;
	}
	template<typename T>
	inline bool ObjectView::Get(const Name& name, T& t)
	{
		if (cache && cache->name == name) {
		_cache_get: bool isChild = cache->type->IsChildOf<T>(true);
			if (isChild) {
				t = *(T*)((const char*)ptr + cache->data.offset);
			}
			return isChild;
		}
		auto field = cls->GetField(name, false);
		if (field) {
			cache = field;
			goto _cache_get;
		}
		if (cls->parent) {
			return Parent().Get(name, t);
		}
		return false;
	}
	template<typename T>
	inline bool ObjectView::Set(const Name& name, const T& t)
	{
		if (cache && cache->name == name) {
		_cache_set: bool isChild = cache->type->IsChildOf<T>(true);
			if (isChild) {
				*(T*)((const char*)ptr + cache->data.offset) = t;
			}
			return isChild;
		}
		auto field = cls->GetField(name, false);
		if (field) {
			cache = field;
			goto _cache_set;
		}
		if (cls->parent) {
			return Parent().Set(name, t);
		}
		return false;
	}
	bool ObjectView::Invoke(const Name& name,const sarray<ArgsView>& ArgsList)
	{
		auto field = cls->GetField(name, true);
		if (!field) {
			if (cls->parent) {
				return Parent().Invoke(name, ArgsList);
			}
			return false;
		}
		return field->Invoke(ArgsList);
	}
	bool ObjectView::Invoke(const Name& name, std::vector<ArgsView>& ArgsList)
	{
		auto field = cls->GetField(name, true);
		if (!field) {
			if (cls->parent) {
				return Parent().Invoke(name, ArgsList);
			}
			return false;
		}
		return field->Invoke(ArgsList);
	}
	ObjectView ObjectView::Parent() {
		return { ptr, cls ? cls->parent : nullptr };
	}
}