#include "RawScanMemoryBlockNodeProtected.h"
#include <crtdbg.h>
#include <memory.h>
#include "RawScanPools.h"
#include "MemoryFactory.h"

NDTS_Boolean CALL_CONV RawScan_AllocMemoryBlockNode(unsigned long size, RawScan_MemoryBlockNode **ppMemoryBlockNode)
{
	void *pMemoryBlock ;
	RawScan_MemoryBlockNode *pMemoryBlockNode ;
	size_t memoryBlockListSize ;

	// Preconditions.
	_ASSERTE(size > 0) ;
	_ASSERTE(ppMemoryBlockNode) ;

	// Alloc memory block node.
	pMemoryBlock = MemoryFactory_AllocFromPool(RawScan_ReturnRawScanMemoryBlockNodeMemoryPool()) ;
	if(!pMemoryBlock) 
		return NDTS_BFalse ; 

	pMemoryBlockNode = (RawScan_MemoryBlockNode *)pMemoryBlock ;

	pMemoryBlockNode->pList = 0 ; // The RawScan_Alloc might fail below.
	pMemoryBlockNode->size = size ;
	pMemoryBlockNode->pNext = 0 ;

	memoryBlockListSize = sizeof(RawScan_MemoryHandle) * size ;

	// Alloc memory block list.
	pMemoryBlock = MemoryFactory_Alloc(memoryBlockListSize) ;
	if(!pMemoryBlock) 
		return NDTS_BFalse ; 

	// Clear memory block list.
	memset(pMemoryBlock, 0, memoryBlockListSize) ;

	pMemoryBlockNode->pList = (RawScan_MemoryHandle *)pMemoryBlock ;

	*ppMemoryBlockNode = pMemoryBlockNode ;

	return NDTS_BTrue ;
}

NDTS_Boolean CALL_CONV RawScan_FreeMemoryBlockNode(RawScan_MemoryBlockNode *pMemoryBlockNode)
{
	RawScan_MemoryBlockNode *pNextNode ;
	RawScan_MemoryHandle *pList ;
	NDTS_Boolean isOK ;

	// Preconditions.
	_ASSERTE(pMemoryBlockNode) ;

	// Memory block nodes can be chained.
	while(pMemoryBlockNode != 0)
	{
		// Iterate through the memory block list, freeing memory blocks as we go.
		isOK = RawScan_GetMemoryBlockList(pMemoryBlockNode, &pList) ;
		if(!isOK) 
			return NDTS_BFalse ; 

		if(pList != 0)
			MemoryFactory_Free(pList) ;

		pNextNode = pMemoryBlockNode->pNext ;

		// Free memory block node.
		MemoryFactory_FreeToPool(RawScan_ReturnRawScanMemoryBlockNodeMemoryPool(), pMemoryBlockNode) ;

		// Move to the next memory block node in the chain.
		pMemoryBlockNode = pNextNode ;
	}

	return NDTS_BTrue ;
}

NDTS_Boolean CALL_CONV RawScan_GetMemoryBlockNodeTail(RawScan_MemoryBlockNode *pMemoryBlockNode, RawScan_MemoryBlockNode **ppLast)
{
	RawScan_MemoryBlockNode *p ;
	
	// Preconditions.
	_ASSERTE(pMemoryBlockNode) ;
	_ASSERTE(ppLast) ;

	p = pMemoryBlockNode ;
	while(p->pNext != 0)
		p = p->pNext ;

	*ppLast = p ;

	return NDTS_BTrue ;
}

NDTS_Boolean CALL_CONV RawScan_JoinMemoryBlockNodes(RawScan_MemoryBlockNode *pLHS, RawScan_MemoryBlockNode *pRHS)
{
	RawScan_MemoryBlockNode *pTail ;
	NDTS_Boolean isOK ;

	// Preconditions.
	_ASSERTE(pLHS) ;
	_ASSERTE(pRHS) ;

	isOK = RawScan_GetMemoryBlockNodeTail(pLHS, &pTail) ;
	if(!isOK) 
		return NDTS_BFalse ; 

	pTail->pNext = pRHS ;

	return isOK ;
}

RAW_SCAN_API NDTS_Boolean CALL_CONV RawScan_GetMemoryBlockList(RawScan_MemoryBlockNode *pMemoryBlockNode, RawScan_MemoryHandle **ppList)
{
	// Preconditions.
	_ASSERTE(pMemoryBlockNode) ;
	_ASSERTE(ppList) ;

	*ppList = pMemoryBlockNode->pList ;

	return NDTS_BTrue ;
}
