''
'' generic double-linked list
''
'' chng: jan/2005 written [v1ctor]
''

#Include Once "inc\list.bi"

'':::::
Function listNew( ByVal list As TLIST Ptr, _
				  ByVal nodes As Integer, _
				  ByVal nodelen As Integer, _
				  ByVal doclear As Integer, _
				  ByVal relink As Integer ) As Integer

	'' fill ctrl struct
	list->tbhead 	= NULL
	list->tbtail 	= NULL
	list->nodes 	= 0
	list->nodelen	= nodelen
	list->head		= NULL
	list->tail		= NULL
	list->clear		= doclear

	'' allocate the initial pool
	Return listAllocTB( list, nodes, relink )

End Function

'':::::
Function listDel( ByVal list As TLIST Ptr ) As Integer
	Dim As TLISTTB Ptr tb, nxt

	'' for each pool, free the mem block and the pool ctrl struct
	tb = list->tbhead
	Do While( tb <> NULL )
		nxt = tb->nxt
		DeAllocate( tb->nodetb )
		DeAllocate( tb )
		tb = nxt
	Loop

	list->tbhead 	= NULL
	list->tbtail 	= NULL
	list->nodes		= 0

	Return TRUE

End Function

'':::::
Function listAllocTB( ByVal list As TLIST Ptr, _
					  ByVal nodes As Integer, _
					  ByVal relink As Integer = TRUE ) As Integer Static
	Dim As Integer i
	Dim As TLISTNODE Ptr nodetb, node, prv
	Dim As TLISTTB Ptr tb


	If ( nodes <= 1 ) Then
		Return FALSE
	EndIf

	'' allocate the pool
	If ( list->clear ) Then
		nodetb = Callocate( nodes * list->nodelen )
	Else
		nodetb = Allocate( nodes * list->nodelen )
	EndIf
	If ( nodetb = NULL ) Then
		Return FALSE
	EndIf

	'' and the pool ctrl struct
	tb = Allocate( Len( TLISTTB ) )
	If ( tb = NULL ) Then
		DeAllocate( nodetb )
		Return FALSE
	EndIf

	'' add the ctrl struct to pool list
	If ( list->tbhead = NULL ) Then
		list->tbhead = tb
	EndIf
	If ( list->tbtail <> NULL ) Then
		list->tbtail->nxt = tb
	EndIf
	list->tbtail = tb

	tb->nxt 	= NULL
	tb->nodetb 	= nodetb
	tb->nodes 	= nodes

	'' add new nodes to the free list
	list->fhead = nodetb
	list->nodes += nodes

	''
	If ( relink ) Then
		prv = NULL
		node = list->fhead

		For i = 1 To nodes-1
			node->prv	= prv
			node->nxt	= Cast(TLISTNODE Ptr, Cast(Byte Ptr, node) + list->nodelen)

			prv 	   	= node
			node 		= node->nxt
		Next

		node->prv = prv
		node->nxt = NULL
	EndIf

	''
	Return TRUE

End Function

'':::::
Function listNewNode( ByVal list As TLIST Ptr ) As TLISTNODE Ptr Static
	Dim As TLISTNODE Ptr node, tail

	'' alloc new node list if there are no free nodes
	If ( list->fhead = NULL ) Then
		listAllocTB( list, list->nodes \ 2 )
	EndIf

	'' take from free list
	node = list->fhead
	list->fhead = node->nxt

	'' add to used list
	tail = list->tail
	list->tail = node
	If ( tail <> NULL ) Then
		tail->nxt = node
	Else
		list->head = node
	EndIf

	node->prv	= tail
	node->nxt	= NULL

	''
	Return node

End Function

'':::::
Function listDelNode( ByVal list As TLIST Ptr, _
					  ByVal node As TLISTNODE Ptr ) As Integer Static
	Dim As TLISTNODE Ptr prv, nxt

	If ( node = NULL ) Then
		Return 0
	EndIf

	'' remove from used list
	prv = node->prv
	nxt = node->nxt
	If ( prv <> NULL ) Then
		prv->nxt = nxt
	Else
		list->head = nxt
	EndIf

	If ( nxt <> NULL ) Then
		nxt->prv = prv
	Else
		list->tail = prv
	EndIf

	'' add to free list
	node->nxt = list->fhead
	list->fhead = node

	'' node can contain strings descriptors, so, erase it..
	If ( list->clear ) Then
		Clear( ByVal Cast(Any Ptr Ptr, node) + 2, 0, list->nodelen - (Len( Any Ptr ) * 2) )
	EndIf
	
	Return 0

End Function

'':::::
Function listGetFirstNode( ByVal list As TLIST Ptr ) As TLISTNODE Ptr

	Return list->head

End Function

'':::::
Function listGetLastNode( ByVal list As TLIST Ptr ) As TLISTNODE Ptr

	Return list->tail

End Function

'':::::
Function listGetPrevNode( ByVal node As TLISTNODE Ptr ) As TLISTNODE Ptr

	If ( node = NULL ) Then
		Return NULL
	EndIf
		
	Return node->prv

End Function

'':::::
Function listGetNextNode( ByVal node As TLISTNODE Ptr ) As TLISTNODE Ptr

	If ( node = NULL ) Then
		Return NULL
	EndIf
		
	Return node->nxt

End Function
