#pragma once
#include "text.h"
namespace YAML
{
	template<typename T>
	inline string TextSerialize<T>::Serialize(const Any& any)
	{
		if constexpr (Check_IsString<T>) {
			return string(*any.CastTo<T*>());
		}
		else if constexpr(Check_ToString<T>){
			return std::to_string(*any.CastTo<T*>());
		}
		else {
			return string(any.cls->name.GetView());
		}
	}
	template<typename T>
	inline bool TextSerialize<T>::Unserialize(const string& val, const Any& any)
	{
		if constexpr (Check_IsString<T>) {
			return new (any.CastTo<T*>())T(val);
		}
		else if constexpr (std::is_arithmetic_v<T>) {
			if constexpr (std::is_integral_v<T>) {
				*any.CastTo<T*>() = std::stoul(val);
				return true;
			}
			else if constexpr (std::is_floating_point_v<T>) {
				*any.CastTo<T*>() = std::stold(val);
				return true;
			}
		}
		else {
			return false;
		}
	}
	inline StringFuncMap TextArchive::BuildStringMap()
	{
		StringFuncMap funcMap;
#define RegisterAny(T) funcMap.emplace(&TypeInfo<T>::StaticClass, std::make_pair(&TextSerialize<T>::Serialize, &TextSerialize<T>::Unserialize))
#include "register.inl"
#undef RegisterAny
		return funcMap;
	}
	template<typename T>
	inline void TextArchive::Register()
	{
		FuncMap.emplace(&TypeInfo<T>::StaticClass, std::make_pair(&TextSerialize<T>::Serialize, &TextSerialize<T>::Unserialize));
	}
	inline Node TextArchive::Serialize(const Any& any)
	{
		if (!any) {
			return {};
		}
		auto it = FuncMap.find(any.cls);
		if (it != FuncMap.end()) {
			return Node{ it->second.first(any)};
		}
		Node result;
		if (any.IsContainer()) {
			auto docker = any.ToContainer();
			for (auto obj : docker) {
				result.push_back(Serialize(obj));
			}
			return result;
		}
		if (any.IsArray()) {
			int n = any.ArraySize();
			for (int i = 0; i < n; i++) {
				result.push_back(Serialize(any.Member(i)));
			}
			return result;
		}
		if (Any p = any.Parent()) {
			result["__parent__"] = Serialize(p);
		}
		auto fieldList = any.cls->GetFields(refl::FIND_ALL_MEMBER, FName(""));
		for (auto& field : fieldList) {
			Node child = Serialize(any.Member(field));
			result[field.name.GetView()] = child;
		}
		return result;
	}
	inline bool TextArchive::Unserialize(const Node& res, const Any& any)
	{
		if (!any) {
			return false;
		}
		if (res.IsNull()) {
			const string& str = "";
			return any.Construct(Any{ &str, &TypeInfo<string>::StaticClass });
		}
		auto it = FuncMap.find(any.cls);
		if (it != FuncMap.end()) {
			return it->second.second(res.as<string>(),any);
		}
		if (res.IsSequence() && any.IsContainer()) {
			auto docker = any.ToContainer();
			docker.construct();
			char memory[STACK_MEMORY_SIZE];
			Any any = docker.try_malloc(&memory, STACK_MEMORY_SIZE);
			for (std::size_t i = 0; i < res.size(); i++) {
				Unserialize(res[i], any);
				docker.insert(any);
				any.Destruct();
			}
			docker.try_free(any, STACK_MEMORY_SIZE);
			return true;
		}
		if (res.IsSequence() && any.IsArray()) {
			for (std::size_t i = 0; i < res.size(); i++) {
				Unserialize(res[i], any.Member(i));
			}
			return true;
		}
		if (res.IsMap() && any.IsObject()) {
			auto fieldList = any.cls->GetFields(refl::FIND_ALL_MEMBER, FName(""));
			auto rt = res.begin();
			int diff = res.size() - fieldList.size();
			if (diff == 1 && any.CheckParent()) {
				diff = 0;
				Unserialize(rt++->second, any.Parent());
			}
			else if (diff != 0) {
				return false;
			}
			auto ft = fieldList.begin();
			for (; ft != fieldList.end() && rt != res.end(); ++ft,++rt) {
				if (ft->name != Name(rt->first.as<string>())) {
					return false;
				}
				Unserialize(rt->second, any.Member(*ft));
			}
			return true;
		}
		if (res.IsScalar() && any.IsObject()) {
			const string& str = res.as<string>();
			return any.Construct(Any{&str, &TypeInfo<string>::StaticClass});
		}
		return false;
	}
}