#pragma once
#include "uclass.h"
#include "view.h"
#include "convert.h"
namespace refl {
	using enum ClassFlag;
	bool Any::Check(const UClass* toClass) const{
		if (cls == toClass) {
			return true;
		}
		auto p1 = cls->parent;
		auto p2 = toClass->parent;
		assert(p1 && p2);
		//子类转父类
		if (p1->IsChildOf(p2)) {
			return true;
		}
		if (p1->flag & CLASS_TRIVIAL_FLAG && p2->flag & CLASS_TRIVIAL_FLAG && p1->size >= p2->size) {
			return true;
		}
		return false;
	}
	inline constexpr int Any::Size()const
	{
		return cls->parent->size;
	}
	inline constexpr const UClass* Any::Parent()const
	{
		return cls->parent;
	}
	AnyArgs::AnyArgs(const sarray<Any>& args, const sarray<const UClass*>& params, void* memory)
		: data(memory), num(args.size()), size(GetArgsSize(args, params))
	{
		assert(size > 0);
		if (!memory) {
			isMemoryOwner = true;
			data = malloc(size);
		}
		Any* any = (Any*)data;
		assert(any != nullptr);
		char* pData = ((char*)data) + num * sizeof(Any);
		auto uptr = params.at(params.size() - args.size());
		for (auto& arg : args) {
			any->cls = *uptr;
			any->ptr = pData;
			assert(Convert::Construct(*any, arg));
			any++;
			pData += (*uptr)->parent->size;
		}
	}
	inline AnyArgs::~AnyArgs()
	{
		if (num == 0 || !data) {
			return;
		}
		if (isMemoryOwner) {
			Any* any = (Any*)data;
			for (int i = 0; i < num; i++) {
				any->cls->DestObject((void*)any->ptr);
				any++;
			}
			free(data);
		}
		num = 0;
		data = nullptr;
	}
	inline int AnyArgs::Size()
	{
		return size;
	}
	inline const sarray<Any> AnyArgs::ToSArray()
	{
		return sarray<Any>((Any*)data, num);
	}
	inline constexpr Offset AnyArgs::GetArgsSize(const sarray<Any>& args,const sarray<const UClass*>& params)
	{	//这里空间换时间，Any多占用了一个数据指针
		if (args.size() == 0 || params.size() < args.size() + 1) {
			return 0;
		}
		Offset offset = args.size() * sizeof(Any);
		auto uptr = params.at(params.size() - args.size());
		for (auto uend = params.back(); uptr < uend; uptr++) {
			offset += (*uptr)->parent->size;//数据大小
		}
		return offset;
	}
	template<typename T>
	inline bool AnyView::Get(const Name& name, T& t)
	{
		if (cache && cache->name == name) {
		_cache_get: bool isChild = cache->type->IsChildOf<T>();
			if (isChild) {
				t = *(T*)((const char*)ptr + cache->data.member.offset);
			}
			return isChild;
		}
		auto field = cls->GetField(name, 0);
		if (field) {
			cache = field;
			goto _cache_get;
		}
		if (cls->parent) {
			return Parent().Get(name, t);
		}
		return false;
	}
	template<typename T>
	inline bool AnyView::Set(const Name& name, const T& t)
	{
		if (cache && cache->name == name) {
		_cache_set: bool isChild = cache->type->IsChildOf<T>();
			if (isChild) {
				*(T*)((const char*)ptr + cache->data.member.offset) = t;
			}
			return isChild;
		}
		auto field = cls->GetField(name, 0);
		if (field) {
			cache = field;
			goto _cache_set;
		}
		if (cls->parent) {
			return Parent().Set(name, t);
		}
		return false;
	}
	bool AnyView::Invoke(const Name& name,const sarray<Any>& ArgsList)
	{
		auto field = cls->GetField(name, 0);
		if (!field) {
			if (cls->parent) {
				return Parent().Invoke(name, ArgsList);
			}
			return false;
		}
		return field->Invoke(ArgsList);
	}
	bool AnyView::Invoke(const Name& name, svector<Any>& ArgsList)
	{
		auto field = cls->GetField(name, 0);
		if (!field) {
			if (cls->parent) {
				return Parent().Invoke(name, ArgsList);
			}
			return false;
		}
		return field->Invoke(ArgsList);
	}
	AnyView AnyView::Parent() {
		return { ptr, cls ? cls->parent : nullptr };
	}
}