#include "object_header.h"

#include <stdint.h>

#include "collector.h"
#include "globals.h"
#include "gcpointers.h"

void ctor(gc_object_header* const this, size_t inSize)
{
	#ifndef NDEBUG
		this->canary_start = CANARY_VALUE;
	#endif

	this->size = inSize;
	this->root_chain = NULL;
	this->type_chain = NULL;
	this->forward = NULL;
	this->is_forwarded = false;

	#ifndef NDEBUG
		this->canary_end = CANARY_VALUE;
	#endif
}

void copy_ctor(gc_object_header* const this, const gc_object_header* const other)
{
	#ifndef NDEBUG
		this->canary_start = CANARY_VALUE;
	#endif

	this->size = other->size;
	this->root_chain = other->root_chain;
	this->type_chain = NULL;
	this->forward = NULL;
	this->is_forwarded = false;

	#ifndef NDEBUG
		this->canary_end = CANARY_VALUE;
	#endif

	gcpointer_t* root = this->root_chain;
	while(root)
	{
		check(gc_get_object_ptr( (void*)root->ptr ) == other);
		root->ptr = ((intptr_t)this) + sizeof(gc_object_header);

		check(gc_get_object_ptr( (void*)root->ptr ) == this);
		root = root->next;
	}

	gcpointer_t* type = other->type_chain;

	while(type)
	{
		check((intptr_t)type < (intptr_t)((intptr_t)other + other->size));

		size_t offset = (intptr_t)type - (intptr_t)other;
		check(offset < this->size);

		gcpointer_t* member_ptr = (gcpointer_t*)( (intptr_t)this + offset );

		if(!this->type_chain) this->type_chain = member_ptr;

		size_t next_offset = type->next ? (intptr_t)type->next - (intptr_t)other : 0;
		check(next_offset < this->size);

		gcpointer_t* next_ptr = type->next ? (gcpointer_t*)((intptr_t)this + next_offset) : NULL;

		member_ptr->ptr = type->ptr;
		member_ptr->next = next_ptr;

		type = type->next;
	}

	check(is_valid(this));
}

#ifndef NDEBUG
	bool is_valid(const gc_object_header* const this)
	{
		check((intptr_t)this->canary_start == (intptr_t)CANARY_VALUE);
		check((intptr_t)this->canary_end == (intptr_t)CANARY_VALUE);

		check(this->is_forwarded == ( (intptr_t)this->forward != (intptr_t)NULL));

		check(this->size < POOL_SIZE_BYTES);

		gcpointer_t* root = this->root_chain;
		while(root)
		{
			checkf(gc_get_object_ptr( (void*)root->ptr ) == this, (const char*)"Expected %lX got %lX\n", gc_get_object_ptr( (void*)root->ptr ), this);

			root = root->next;
		}

		gcpointer_t* type = this->type_chain;
		while(type)
		{
			check((intptr_t)type > (intptr_t)this);
			check((intptr_t)type < (intptr_t)(((intptr_t)this) + this->size));

			type = type->next;
		}

		return true;
	}
	#else
	#error blarg
#endif
