/*
Copyright (C) 2003-2006 Andrey Nazarov

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

//
// list.c - simple double-linked list management
//

#include "q_shared.h"
#include "com_public.h"
#include "q_list.h"

/*
================
List_LinkElemAfter
================
*/
static void List_LinkElemAfter( listElem_t *after, listElem_t *elem ) {
	elem->prev = after;
	elem->next = after->next;

	if( after->next ) {
		after->next->prev = elem;
	}
	after->next = elem;
	if( after == after->parent->last ) {
		after->parent->last = elem;
	}
}

/*
================
List_LinkElemBefore
================
*/
static void List_LinkElemBefore( listElem_t *before, listElem_t *elem ) {
	elem->prev = before->prev;
	elem->next = before;

	if( before->prev ) {
		before->prev->next = elem;
	}
	before->prev = elem;
	if( before == before->parent->first ) {
		before->parent->first = elem;
	}
}

/*
================
List_UnlinkElem
================
*/
static void List_UnlinkElem( listElem_t *elem ) {
	if( elem->prev ) {
		elem->prev->next = elem->next;
	}
	if( elem->next ) {
		elem->next->prev = elem->prev;
	}
	if( elem == elem->parent->first ) {
		elem->parent->first = elem->next;
	}
	if( elem == elem->parent->last ) {
		elem->parent->last = elem->prev;
	}
}

/*
================
List_Append
================
*/
listElem_t *List_Append( list_t *list, void *data ) {
	listElem_t *elem;

	elem = ( listElem_t * )data;
	elem->parent = list;
	elem->prev = list->last;
	elem->next = NULL;

	if( list->last ) {
		list->last->next = elem;
	}

	list->last = elem;
	if( !list->first ) {
		list->first = elem;
	}

	return elem;
}

/*
================
List_Insert
================
*/
listElem_t *List_Insert( list_t *list, void *data ) {
	listElem_t *elem;

	elem = ( listElem_t * )data;
	elem->parent = list;
	elem->prev = NULL;
	elem->next = list->first;

	if( list->first ) {
		list->first->prev = elem;
	}

	list->first = elem;
	if( !list->last ) {
		list->last = elem;
	}

	return elem;
}

/*
================
List_InsertAfter
================
*/
listElem_t *List_InsertAfter( listElem_t *after, void *data ) {
	listElem_t *elem;

	elem = ( listElem_t * )data;
	elem->parent = after->parent;
	List_LinkElemAfter( after, elem );

	return elem;
}



/*
================
List_InsertBefore
================
*/
listElem_t *List_InsertBefore( listElem_t *before, void *data ) {
	listElem_t *elem;

	elem = ( listElem_t * )data;
	elem->parent = before->parent;
	List_LinkElemBefore( before, elem );

	return elem;
}

/*
================
List_MoveAfter
================
*/
void List_MoveAfter( listElem_t *after, listElem_t *elem ) {
	List_UnlinkElem( elem );
	List_LinkElemAfter( after, elem );
}

/*
================
List_MoveBefore
================
*/
void List_MoveBefore( listElem_t *before, listElem_t *elem ) {
	List_UnlinkElem( elem );
	List_LinkElemBefore( before, elem );
}

/*
================
List_DeleteElem
================
*/
void List_DeleteElem( void *data ) {
	List_UnlinkElem( ( listElem_t * )data );
}

/*
================
List_Clear
================
*/
void List_Clear( list_t *list ) {
	list->first = NULL;
	list->last = NULL;
}

/*
================
List_Free
================
*/
void List_Free( list_t *list ) {
	listElem_t *elem, *next;

	for( elem = list->first; elem; elem = next ) {
		next = elem->next;
		com.Free( elem );
	}

	list->first = NULL;
	list->last = NULL;
}

int List_CountElems( list_t *list ) {
	listElem_t *elem;
	int count;

	count = 0;
	for( elem = list->first; elem; elem = elem->next ) {
		count++;
	}

	return count;
}



