/*****
 NAME
 	cidstack.m - source code for CIdStack class
 VERSION
 	$Id$
 CHANGELOG
 	$Log$
 */

#include <coconut/cidstack.h>
#include <coconut/csystem.h>
#include <coconut/ptext.h>

typedef struct {
	id	obj ;
} stack_elm_t ;

#define	STACK(PTR)	((stack_elm_t *) PTR)

#define	UNITSIZE	16
#define	TMP_CALCNUM(n)	((u_int) ((n + UNITSIZE) / UNITSIZE))
#define	CALCNUM(n)	(TMP_CALCNUM(n) * UNITSIZE)

@implementation CIdStack

- init
{
	current_num = 0 ; 
	this_array = g_array_new(FALSE, FALSE, CALCNUM(0)) ;
	[CSystem checkPtr: this_array] ;
	return [super init] ;
}

- (void) dealloc
{
	g_array_free(this_array, TRUE) ;
	return [super dealloc] ;
}

- (u_int) count
{
	return current_num ;
}

- clear
{
	g_array_set_size(this_array, 0) ;
	current_num = 0 ;
	return nil ;
}

- foreach: (SEL) msg with: p1 with: p2
{
	stack_elm_t *	bottom ;
	stack_elm_t *	top ;
	id		result ;

	bottom = STACK(this_array->data) ;
	if(bottom){
		top = bottom + current_num - 1 ;
		for( ; top>=bottom ; top--){
			result = [top->obj perform: msg with: p1 with: p2] ;
			if(result)
				return result ;
		}
	}
	return nil ;
}

- foreach: (id) obj message: (SEL) msg with: p1 
{
	stack_elm_t *	bottom ;
	stack_elm_t *	top ;
	id		result ;

	bottom = STACK(this_array->data) ;
	if(bottom){
		top = bottom + current_num - 1 ;
		for( ; top>=bottom ; top--){
			result = [obj perform: msg with: top->obj with: p1] ;
			if(result)
				return result ;
		}
	}
	return nil ;
}

- push: (id) obj
{
	stack_elm_t *	ptr ;

	if(current_num >= this_array->len)
		 g_array_set_size(this_array, CALCNUM(current_num+1));
	ptr = STACK(this_array->data) ;
	[CSystem checkPtr: ptr] ;
	ptr[current_num++].obj = obj ;
	return nil ;
}

- (id) pop
{
	stack_elm_t *	ptr ;
	int		newlen ;

	if(current_num > 0){
		ptr = STACK(this_array->data) ;
		ptr += current_num-1 ;

		/* keep the content pointed by "data" */
		newlen = CALCNUM(current_num) ;
		if(newlen < this_array->len)
			g_array_set_size(this_array, newlen);
		current_num-- ;
		return ptr->obj ;
	} else
		return nil ;
}

- (id) peek: (u_int) idx
{
	stack_elm_t *	ptr ;
	if(current_num > idx){
		ptr = STACK(this_array->data) ;
		return ptr[idx].obj ;
	} else
		return nil ;
}

- (id) peekTop
{
	stack_elm_t *	ptr ;
	if(current_num > 0){
		ptr = STACK(this_array->data) ;
		return ptr[current_num-1].obj ;
	} else
		return nil ;
}

- print: (id <PIndentStream>) stream
{
	stack_elm_t *	bottom ;
	stack_elm_t *	top ;

	[stream putPtr: "(stack\n"] ;
	  bottom = STACK(this_array->data) ;
	  if(bottom){
		top = bottom + current_num - 1 ;
		for( ; top>=bottom ; top--)
			[top->obj print: stream] ;
	  }
	[stream putPtr: ")\n"] ;
	return nil ;
}

@end

