#include "stdafx.h"
#include "apr_strings.h"
#include "apr_pools.h"

static apr_pool_t *context;
static apr_pool_t *subMemoryPool, *subSubMemoryPool;

static apr_status_t StringClear(void *data)
{
	// This function is called when apr_pool_destroy is called
	printf( "The data to manipulate is (%s)\n", (char *)data);
    return APR_SUCCESS;
}

void TstSubDataSetting() {
	char *buffer;
	char *retBuffer;

	if(( apr_pool_create( &subMemoryPool, context)) != APR_SUCCESS) {
		printf( "Could not create memory sub-pool\n");
		exit( -1);
	}
    buffer = apr_pstrdup(subMemoryPool, "Hello World");
	
	// Create a buffer reference that corresponds to a specific index
    apr_pool_userdata_set( buffer, "TEST", StringClear, subMemoryPool);    
    apr_pool_userdata_get((void **)&retBuffer, "TEST", subMemoryPool);
	apr_pool_destroy( subMemoryPool);
}

void TstSubStringAllocation() {
	if(( apr_pool_create( &subMemoryPool, context)) != APR_SUCCESS) {
		printf( "Could not create memory sub-pool\n");
		exit( -1);
	}
	
	// Example routines to show how to manipulate strings
	char *buffer;
	char *newBuffer;

    buffer = apr_pstrdup( subMemoryPool, "Hello world");
	newBuffer = apr_pstrcat( subMemoryPool, buffer, " and yet more data", NULL);

	apr_pool_destroy( subMemoryPool);
	return;
}

void TstSubMemoryAllocation() {
	// This function calls the above function, but also copies 
	// the parent properties, which is context, this calls the function
	// apr_pool_sub_make and sets the parent attributes as default
	if(( apr_pool_create( &subMemoryPool, context)) != APR_SUCCESS) {
		printf( "Could not create memory sub-pool\n");
		exit( -1);
	}

	// Lets start by allocating memory
	char *buffer;

	// QUESTION...  Is this thread safe???? No lock on block splitting
	// Flag ALLOC_USE_MALLOC uses malloc which would be thread safe
	if(( buffer = (char *)apr_palloc( subMemoryPool, 100)) == NULL) {
		printf( "Could not allocate memory\n");
		exit( -1);
	}
	strcpy( buffer, "Hello world");

	char *buffer2;

	// Lets play with the pool memory, by first "clearing" the pool
	apr_pool_clear( subMemoryPool);
	if(( buffer2 = (char *)apr_palloc( subMemoryPool, 100)) == NULL) {
		printf( "Could not allocate memory\n");
		exit( -1);
	}
	if( buffer == buffer2) {
		printf( "wow they match (but we expected this)\n");
	}

	// Now lets actually delete the pool memory, note that the above
	// function is called, but the memory is actually yanked
	apr_pool_destroy( subMemoryPool);

	// *********************************************************************
	// WARNING by default this will work as APR is installed
	// Open up aprpools.h and uncomment the flags ALLOC_DEBUG and APR_POOL_DEBUG
	// Then the following function call will properly fail
	//if(( buffer2 = (char *)apr_palloc( subMemoryPool, 100)) == NULL) {
	//	printf( "Could not allocate memory\n");
	//	exit( -1);
	//}
	// *********************************************************************

	if(( apr_pool_create( &subMemoryPool, context)) != APR_SUCCESS) {
		printf( "Could not create memory sub-pool\n");
		exit( -1);
	}

	// *********************************************************************
	apr_pool_clear( context);
	// The next function only works if APR_POOL_DEBUG is enabled
	// The next set of functions do not work because apr_pool_clear actually
	// destroys the sub pools
	//if( apr_pool_is_ancestor( context, subMemoryPool) != false) {
	//	printf( "Yes the pool have a parent child relationship\n");
	//}
	// Now lets allocate from the sub pool
	//if(( buffer = (char *)apr_palloc( subMemoryPool, 100)) == NULL) {
	//	printf( "Could not allocate memory\n");
	//	exit( -1);
	//}
	// *********************************************************************
}

void TstSimpleMemoryAllocation() {
	char *buffer;

	if(( buffer = (char *)apr_palloc( context, 100)) == NULL) {
		printf( "Could not allocate memory\n");
		exit( -1);
	}
	strcpy( buffer, "Hello world");
}

void APRMemory() {
	// Create the pool context
    if (apr_pool_create(&context, NULL) != APR_SUCCESS) {
		printf( "Could not allocate context\n");
		exit( -1);
    }

	TstSimpleMemoryAllocation();
	TstSubMemoryAllocation();
	TstSubStringAllocation();
	TstSubDataSetting();

	// Clear the pool
	apr_pool_destroy( context);
	return;
}

