#pragma once

#include "style.h"

class MemoryBlockHeader
{
public:
	#if defined(USE_SIGNATURE)
		friend int Is_Signature_Bad(const volatile MemoryBlockHeader *p);
	#endif

	MemoryBlockHeader *nextBlock;
	size_t blockSize;

	Logical TestInstance();
};

class MemoryBlockBase SIGNATURED
{
public:
	Logical TestInstance()	{ return blockMemory != NULL; }

	static void UsageReport();
	static void Collapse();

protected:
	const char *blockName;

	MemoryBlockHeader *blockMemory;

	size_t blockSize, recordSize, deltaSize;

	Byte *firstHeaderRecord, *freeRecord, *deletedRecord;

	MemoryBlockBase(size_t rec_size, size_t start, size_t delta, const char* name = NULL);
	~MemoryBlockBase();

	void *Grow();

private:
	static MemoryBlockBase *firstBlock;
	MemoryBlockBase *nextBlock, *previousBlock;

	static void SortDeletions();
};

class MemoryBlock : public MemoryBlockBase
{
public:
	static Logical TestClass();

	MemoryBlock(size_t rec_size, size_t start, size_t delta, const char *name = NULL)
		: MemoryBlockBase(rec_size, start, delta, name)
	{
	}

	void *New();
	void Delete(void *Where);

	void *operator[](size_t Index);
};

template <class T> class MemoryBlockOf : public MemoryBlock
{
public:
	MemoryBlockOf(size_t start, size_t delta, const char *name = NULL)
		: MemoryBlock(sizeof(T), start, delta, name)
	{
	}

	T* New()	{ return (T*)MemoryBlock::New(); }
	void Delete(void *where)	{ MemoryBlock::Delete(where); }

	T* operator[](size_t index)	{ return (T*)MemoryBlock::operator [](index); }
};

class MemoryStack : public MemoryBlockBase
{
public:
	static Logical TestClass();

protected:
	Byte *topOfStack;

	MemoryStack(size_t rec_size, size_t start, size_t delta, const char* name = NULL)
		: MemoryBlockBase(rec_size, start, delta, name)
	{
		topOfStack = NULL;
	}

	void *Push(const void *What);
	void *Push();
	void *Peek() { return (void*)topOfStack; }
	void Pop();
};

template <class T> class MemoryStackOf : public MemoryStack
{
public:
	MemoryStackOf(size_t start, size_t delta, const char *name)
		: MemoryStack(sizeof(T), start, delta, nome)
	{
	}

	T *Push(const T *what)	{ return (T*)MemoryStack::Push(what); }
	T *Peek()				{ return (T*)MemoryStack::Peek(); }
	void Pop()				{ MemoryStack::Pop(); }
};