/*****
 NAME
	cidarray.m - source codee for CIdArray class
 VERSION
	$Id$
 CHANGELOG
	$Log$
 */

#include <coconut/cidarray.h>
#include <coconut/csystem.h>
#include <coconut/cerror.h>
#include <coconut/ptext.h>

typedef struct {
	id 	obj ;
} array_elm_t ;

#define	FIRST_PTR	((array_elm_t *) array_body->data)
#define	END_PTR		(&(FIRST_PTR[array_body->len]))

@implementation CIdArray

- init
{
	array_body = g_array_new(FALSE, FALSE, sizeof(array_elm_t)) ;
	[CSystem checkPtr: array_body] ;
	return [super init] ;
}

- p_clear
{
	array_elm_t *	p ;
	array_elm_t *	endp ;
	p = FIRST_PTR ; endp = END_PTR ;
	for( ; p<endp ; p++)
		[p->obj release] ;
	g_array_free(array_body, TRUE) ;
	return nil ;
}

- (void) dealloc
{
	[self p_clear] ;
	[super dealloc] ;
}

- (u_int) count
{
	return array_body->len ;
}

- clear
{
	[self p_clear] ;
	array_body = g_array_new(FALSE, FALSE, sizeof(array_elm_t)) ;
	[CSystem checkPtr: array_body] ;
	return nil ;
}

- foreach: (SEL) msg with: p1 with: p2
{
	array_elm_t *	p ;
	array_elm_t *	endp ;
	id		result ;

	p = FIRST_PTR ; endp = END_PTR ;
	for( ; p<endp ; p++){
		result = [p->obj perform: msg with: p1 with: p2] ;
		if(result)
			return result ;	
	}
	return nil ;
}

- foreach: (id) obj message: (SEL) msg with: p1 
{
	array_elm_t *	p ;
	array_elm_t *	endp ;
	id		result ;

	p = FIRST_PTR ; endp = END_PTR ;
	for( ; p<endp ; p++){
		result = [obj perform: msg with: p->obj with: p1] ;
		if(result)
			return result ;	
	}
	return nil ;
}

- append: (id) obj
{
	array_elm_t	elm ;
	[obj retain] ; elm.obj = obj ;
	g_array_append_vals(array_body, &elm, 1) ;
	return nil ;
}

- prepend: (id) obj
{
	array_elm_t	elm ;
	[obj retain] ; elm.obj = obj ;
	g_array_prepend_vals(array_body, &elm, 1) ;
	return nil ;
}

- (id <PError>) setItem: (id) obj to: (u_int) idx 
{
	array_elm_t *	p ;
	guint		len = array_body->len ;

	if(idx < len){
		p = FIRST_PTR ; 
		[p[idx].obj release] ;
		p[idx].obj = obj ;
		return nil ;
	} else
		return [CError illegal_range] ;
}

- (id) item: (u_int) idx 
{
	guint		len = array_body->len ;
	array_elm_t *	p = FIRST_PTR ;

	return idx<len ? (p[idx]).obj : NULL ;
}

- (id) first
{
	array_elm_t *	p ;
	if(array_body->len > 0){
		p = FIRST_PTR ;
		return p->obj ;
	} else
		return nil ;
}

- (id) last
{
	array_elm_t *	p ;
	guint		len ;
	if(array_body->len > 0){
		p = FIRST_PTR ; len = array_body->len ;
		return (p[len-1]).obj ;
	} else
		return nil ;
}

- (id) search: (u_int *) idx by: (id) obj
{
	array_elm_t *	p ;
	array_elm_t *	endp ;
	u_int		i ;

	p = FIRST_PTR ; endp = END_PTR ;
	for(i=0 ; p<endp ; p++, i++){
		if([p->obj compare: obj] == 0){
			*idx = i ;
			return p->obj ;
		}
	}
	return nil ;
}

- (id <PError>) removeItem: (u_int) idx
{
	array_elm_t *	p ;
	id <PError>	result ;

	if(idx < array_body->len){
		p = FIRST_PTR ;
		[(p[idx]).obj release] ;
		g_array_remove_index(array_body, idx) ;
		result = nil ;
	} else
		result = [CError not_exist] ;
	return result ;
}

- print: (id <PIndentStream>) stream
{
	array_elm_t *	p ;
	array_elm_t *	endp ;

	[stream putPtr: "(array\n"] ;
	[stream incLevel] ;
	  p = FIRST_PTR ; endp = END_PTR ;
	  for( ; p<endp ; p ++){
	  	[p->obj print: stream] ;
		[stream putChar: '\n'] ;
	  }
	[stream decLevel] ;
	[stream putPtr: ")\n"] ;
	return nil ;
}

@end

