#pragma once
#include "refl/detail/uclass.inl"
#include <iostream>
namespace refl {
	class Container {
		const void* ptr;
		const UClass_Container* cls;
		friend class Any;
		Container(const void* ptr, const UClass_Container* cls) :ptr(ptr), cls(cls) {}
	public:
		void construct() {
			cls->Construct((void*)ptr);
		}
		void destruct() {
			cls->Destruct((void*)ptr);
		}
		void try_free(const Any& any, int size) {
			if (any.cls == cls->parent && any.Size() > size) {
				free((void*)any.ptr);
			}
		}
		Any try_malloc(void* memory, int size) {
			if (cls->parent->size <= size) {
				return { memory, cls->parent };
			}
			void* ptr = malloc(cls->parent->size);
			return { ptr, cls->parent };
		}
		void insert(const Any& any) {
			if(any.cls == cls->parent)
				cls->vinsert(ptr, any.ptr);
		}
		int size() {
			return cls->vsize(ptr);
		}
		auto begin() {
			Container::iterator it(cls);
			cls->vbegin(it, ptr);
			return it;
		}
		auto end() {
			Container::iterator it(cls);
			cls->vend(it, ptr);
			return it;
		}
		// Iterator class
		class iterator : public UClass_Container::iterator{
		private:
			const UClass_Container* cls;
		public:
			iterator(const UClass_Container* cls)
				: cls(cls) {}
			iterator& operator++() noexcept {
				cls->viterator_add(this);
				return *this;
			}
			iterator operator++(int) noexcept {
				iterator tmp = *this;
				cls->viterator_add(this);
				return tmp;
			}
			iterator& operator--() noexcept {
				cls->viterator_sub(this);
				return *this;
			}
			iterator operator--(int) noexcept {
				iterator tmp = *this;
				cls->viterator_sub(this);
				return tmp;
			}
			Any operator->() noexcept {
				return { val , cls->parent };
			}
			Any operator*() noexcept {
				return { val , cls->parent };
			}
			constexpr bool operator!=(const iterator& other) const noexcept {
				return  cls != other.cls || ptr != other.ptr;
			}
			constexpr bool operator==(const iterator& other) const noexcept {
				return ptr == other.ptr && cls == other.cls;
			}
		};
	};
	inline Container refl::Any::ToContainer() const
	{
		return Container{ptr, (const UClass_Container*)cls};
	}
}