/*****
 NAME
 	cexpvar.m - source code for CExpVar class
 VERSION
 	$Id$
 CHANGELOG
 	$Log$
 */

#include <coconut/cexpvar.h>
#include <coconut/cmessage.h>
#include <coconut/cstring.h>
#include <coconut/ptext.h>
#include <coconut/dconststr.h>

@implementation CExpVar

- initExpVar: (boolean) isconst name: (id <PConstStr>) name
    value: (id <PNumber>) value ;
{
	expvar_name = name ;
	if(isconst)
		expvar_status = obj_status_constant ;
	else if(value)
		expvar_status = obj_status_modified ;
	else
		expvar_status = obj_status_uninit ;
	expvar_value = value ;
	return [super init] ;
}

- init
{
	return [self initExpVar: FALSE name: nil value: nil] ;
}

- (void) dealloc
{
	[expvar_name release] ;
	[expvar_value release] ;
	[super dealloc] ;
}

- (exp_t) type
{
	return variable_exp ;
}

- (obj_status_t) status
{
	return expvar_status ;
}

- (id <PConstStr>) name
{
	return expvar_name ;
}

- (id <PNumber>) eval
{
	return expvar_value ;
}

- setName: (id <PConstStr>) name
{
	[expvar_name release] ;
	[(expvar_name = name) retain] ;
	return nil ;
}

- setValue: (id <PNumber>) value
{
	if(expvar_status == obj_status_constant){
		[CMessage message: warning_message code: read_only_err
		  format: "can not assign value to constant"] ;
	} else if(value != nil){
		[expvar_value release] ;
		[(expvar_value = value) retain] ;
		expvar_status = obj_status_modified ;
	} else {
		expvar_status = obj_status_uninit ;
	}
	return nil ;
}

- (u_int) hashkey
{
	u_int	stat ;
	u_int	name ;
	u_int	val ;

	stat = (int) expvar_status ;
	name = [expvar_name hashkey] ;
	val = [expvar_value hashkey] ;
	return stat + (name << 2) + (val << 4) ;
}

#define	INT(V)	((int) V)
- (int) compare: (id <PExpVar>) var
{
	int	diff ;

	if((diff = INT(expvar_status) - INT([var status])) != 0)
		return diff ;
	else if((diff = [expvar_name compare: [var name]]) != 0)
		return diff ;
	else 
		return [expvar_value compare: [var eval]] ;
}

- (id <PString>) toString
{
	id <PString>	str ;
	id <PString>	varstr ;
	const char *	name ;

	if(expvar_name)
		name = [expvar_name ptr] ;
	else
		name = UNKNOWN_NAME_STR ;
	str = [[CString alloc] init] ;
	if(HAS_VALUE_OBJ_STATUS(expvar_status)){
		varstr = [expvar_value toString] ;
		[str setFormat: "(expvar: (stat: '%c') (name: \"%s\") "
		  "(value: %s))", OBJSTATUS2CHAR(expvar_status), name, 
		  [varstr ptr]] ;
		[varstr release] ;
	} else {
		[str setFormat: "(expvar: (stat: '%c') (name: \"%s\"))", 
		  OBJSTATUS2CHAR(expvar_status), name] ;
	}
	return str ;
}

- print: (id <PIndentStream>) stream
{	
	id <PString>	str ;

	str = [self toString] ;
	  [stream putStr: str] ;
	[str release] ;
	return nil ;
}

@end

