/*******************************************************************************
 * Copyright (c) 2005, 2009 Intel Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Andy Kaylor, Intel - Initial API and Implementation
 * $Id: TPTPList.c,v 1.7 2009/07/10 00:11:29 jwest Exp $
 *******************************************************************************/ 

#include "tptp/TPTPUtils.h"
#include <stdio.h>
#include <stdlib.h>

void tptp_list_init( tptp_list_t* list )
{
	list->head = 0;
	list->tail = 0;
	list->count = 0;
	list->destroyNode = 0;
	list->copyNode = 0;
}

int tptp_list_add( tptp_list_t* list, void *data )
{
	tptp_node_t* newNode = tptp_malloc( sizeof(tptp_node_t) );

	if ( newNode == 0 )
		return -1;

	newNode->data = data;
	newNode->next = 0;

	if ( list->head == 0 )
	{
		list->head = newNode;
		list->tail = newNode;
	}
	else
	{
		list->tail->next = newNode;
		list->tail = newNode;
	}
	list->count++;
	return 0;
}

int tptp_list_remove( tptp_list_t* list, void *data )
{
	tptp_node_t*  node;
	tptp_node_t*  prev;

	node = list->head;
	if ( node->data == data )
	{
		/* Appoint the new head (may be null) */
		list->head = list->head->next;

		/* if the head was also the tail, clear that too */
		if ( list->tail == node )
			list->tail = 0;

		/* Free our memory */
		if ( list->destroyNode != 0 )
			list->destroyNode( node );
		else
			tptp_free( node->data );
		tptp_free( node );
		list->count--;
		return 0;
	}

	for ( prev = node, node = prev->next; node != 0; node = node->next )
	{
		if ( node->data == data )
		{
			/* Keep the list linked */
			prev->next = node->next;

			/* if we were at the tail, update that too */
			if ( list->tail == node )
				list->tail = prev;

			/* Free our memory */
			if ( list->destroyNode != 0 )
				list->destroyNode( node );
			else
				tptp_free( node->data );
			tptp_free( node );
			list->count--;
			return 0;
		}
		else
		{
			prev = node;
		}
	}

	/* If we get here, we didn't find it */
	return -1;
}

/*
 * Clears the data from the list, but does not
 * clear the destroy and copy functions.
 */
void tptp_list_clear( tptp_list_t* list )
{
	tptp_node_t* node;
	tptp_node_t* next;

	node = list->head;
	
	while ( node != 0 )
	{
		next = node->next;
		if ( list->destroyNode != 0 )
			list->destroyNode( node );
		else
			tptp_free( node->data );
		tptp_free( node );
		node = next;		
	}

	list->head = 0;
	list->tail = 0;
	list->count = 0;
}


tptp_int32 tptp_list_clone( tptp_list_t* copy, const tptp_list_t* orig )
{
	tptp_node_t* node;
	tptp_node_t* newNode;
	tptp_node_t* prevNode;

	if ( !copy )
		return -1;	/*Can't do anything with a null copy ptr.*/

	tptp_list_init( copy );

	if ( orig->copyNode == 0 )
		return -1; /* TODO: make this a return code indicating no copy function */
	
	copy->destroyNode = orig->destroyNode;
	copy->copyNode = orig->copyNode;
	
	node = orig->head;
	
	prevNode = 0;
	while ( node != 0 )
	{
		newNode = tptp_malloc( sizeof(tptp_node_t) );
		if ( newNode == 0 )
		{
			tptp_list_clear( copy );
			return -1; /* TODO: make this a return code indicating out of memory */
		}
		orig->copyNode( node, newNode );
		if ( prevNode == 0 )
		{
			copy->head = newNode;
			copy->tail = newNode;
			copy->count = 1;
		}
		else
		{
			prevNode->next = newNode;
			copy->tail = newNode;
			copy->count++;
		}
		newNode->next = 0;
		prevNode = newNode;
		node = node->next;
	}

	return 0;
}

void tptp_list_setNodeDestructor( tptp_list_t* list, tptp_node_destructor_ptr_t destructorFunc )
{
	list->destroyNode = destructorFunc;
}

void tptp_list_setNodeCopier(  tptp_list_t* list, tptp_node_copy_ptr_t copyFunc )
{
	list->copyNode = copyFunc;
}




