#include "Pandora Heap.h"

pdra_heap::pdra_heap(char* baseAddr,unsigned long heapSize)
{
	free = (pdra_block*)baseAddr;
	allocated = nil;
	
	free->len = heapSize;
	free->logicalLen = heapSize;
	free->next = nil;
}

pdra_heap::~pdra_heap()
{
}

char* pdra_heap::newPtr(unsigned long len)
{
	// Disable interrupts here
	
	pdra_block	*p = free;
	pdra_block	*next = nil;
	pdra_block	*prev = nil;
	pdra_block	*predecessor = nil;
	pdra_block	*retVal = nil;
	unsigned long	reqdLen = len + sizeof(pdra_block);
	
	// Make it a multiple of 16 bytes in length.
	if(reqdLen % 16)
		reqdLen += (16 - (reqdLen % 16));
	
	// Amalgamate all free blocks
	defragmentHeap();
	
	// Search the heap for the smallest free block that will fit us in
	while(p)
	{
		if(p->len >= reqdLen)
		{
			if(retVal)
			{
				if(p->len < retVal->len)
				{
					predecessor = prev;
					retVal = p;
				}
			}
			else
			{
				predecessor = prev;
				retVal = p;
			}
		}
		prev = p;
		p = p->next;
	}
	
	// See if we found a block.
	if(retVal)
	{
		// Remove this block from the free list
		if(predecessor)
			predecessor->next = retVal->next;
		else
			free = retVal->next;	// This is the first block
		
		// See if we can split the block into 2 smaller blocks
		if(retVal->len - reqdLen > sizeof(pdra_block))
		{
			// Calculate the address of the next block
			pdra_block*	next = (pdra_block*)( (unsigned long)retVal + reqdLen);
			
			// Set up the free block
			next->len = retVal->len - reqdLen;
			next->logicalLen = next->len;
			next->next = free;
			
			// Put the free block on the queue
			free = next;
			
			// Fix our returned block
			retVal->len = reqdLen;
		}
		
		retVal->logicalLen = len;
		
		// Add this block to the allocated list
		retVal->next = allocated;
		allocated = retVal;
	}
	
	// Enable interrupts here
	
	return retVal->data;
}

void pdra_heap::disposePtr(char* ptr)
{
	// Disable interrupts here
	pdra_block*	p = allocated;
	pdra_block*	prev = nil;
	
	while(p)
	{
		if(p->data == ptr)
		{
			if(prev)
				prev->next = p->next;
			else
				allocated = p->next;
			
			p->next = free;
			free = p;
			break;
		}
		prev = p;
		p = p->next;
	}
	
	// Enable interrupts here
}

void pdra_heap::defragmentHeap(void)
{
}
