# $Header$

function is_boolean( const x )	type_name(x) == "boolean"
function is_byte( const x )	type_name(x) == "byte"
function is_short( const x )	type_name(x) == "short"
function is_integer( const x )	type_name(x) == "integer"
function is_float( const x )	type_name(x) == "float"
function is_double( const x )	type_name(x) == "double"
function is_complex( const x )	type_name(x) == "complex"
function is_dcomplex( const x )	type_name(x) == "dcomplex"
function is_string( const x )	type_name(x) == "string"
function is_record( const x )	type_name(x) == "record"
function is_function( const x )	type_name(x) == "function"

function is_agent( const x )
	type_name(x) == "agent" || (is_record(x) && has_field(x, "*agent*"))

function is_numeric( const x )
	sum(type_name(x) ==
		"boolean byte short integer float double complex dcomplex") > 0

function min(...)		range(...)[1]
function max(...)		range(...)[2]

function abs(val x)
	{
	if ( is_complex(x) || is_dcomplex(x) )
		return sqrt(real(x)^2 + imag(x)^2)

	else
		{
		local mask := x < 0
		x[mask] := -x[mask]
		return x
		}
	}

function conj(x)
	{
	if ( is_complex(x) || is_dcomplex(x) )
		return complex(real(x), -imag(x))
	else
		return x
	}
		
function arg(x)
	{
	if ( is_complex(x) || is_dcomplex(x) )
		return atan(as_double(imag(x)) / as_double(real(x)))
	else
		return as_double(0)
	}
		
function all(x) sum(!x) == 0
function any(x) sum(as_boolean(x)) > 0

len := length

function ind(x) 1:len(x)

function paste(...,sep=' ')
	internal_paste(sep, ...)

function spaste(...)
	paste(...,sep='')

function has_field( const x, const field )
	{
	if ( is_record(x) )
		sum(field_names(x) == field) > 0
	else
		F
	}

function shell( ..., id=F, host=F, async=F, ping=F, suspend=F, input=F )
 	create_task( id, host, F, async, ping, suspend, input, ... )

function client( ..., id=F, host=F, async=F, ping=F, suspend=F, input=F )
 	create_task( id, host, T, async, ping, suspend, input, ... )

function full_type_name( const x )
	{
	if ( type_name(x) == "record" )
		{
		local f

		local full_name := 'record ['
		local first_field := field_names(x)[1]
		for ( f in field_names(x) )
			{
			if ( f != first_field )
				full_name := spaste(full_name, ', ')
			full_name := spaste(full_name, f, "=",
						full_type_name(x[f]))
			}

		spaste(full_name, "]")
		}
	else
		{
		if ( length(x) != 1 )
			spaste(type_name(x), ' [', length(x), "]" )
		else
			type_name(x)
		}
	}

function relay( src, src_name, ref dest, dest_name="*" )
	{
	if ( dest_name == "*" )
		link src->[src_name] to dest->*
	else
		link src->[src_name] to dest->[dest_name]
	}

function relay_event( src, ref dest, name )
	{
	relay( src, name, dest, "*" )
	}

function relay_all( src, ref dest )
	{
	whenever src->* do
		dest->[$name]( $value )
	}

function birelay_event( ref agent1, ref agent2, name )
	{
	relay( agent1, name, agent2 )
	relay( agent2, name, agent1 )
	}

function birelay_all( ref agent1, ref agent2 )
	{
	relay_all( agent1, agent2 )
	relay_all( agent2, agent1 )
	}

function sort(x)
	{
	if ( len(x) <= 1 )
		return x
	else
		{
		local pivot := x[1]
		local below := x[x < pivot]
		local equal := x[x == pivot]
		local above := x[x > pivot]

		return [sort(below), equal, sort(above)]
		}
	}

function sort_pair(x, y)
	{
	if ( len(x) <= 1 )
		return y
	else
		{
		local pivot := x[1]
		local below := x < pivot
		local equal := x == pivot
		local above := x > pivot

		return [sort_pair(x[below], y[below]), y[equal],
			sort_pair(x[above], y[above])]
		}
	}

function order(x)	sort_pair(x, 1:len(x))

function sync(ref c)	request c->["*sync*"]()

function array(init, ...)
	{
	if ( num_args(...) == 0 )
		return init

	if ( length(init) <= 0 && ! is_string(init) )
		{
		print "bad initializer"
		return F
		}

	if ( ! all(length(...) == 1) )
		{
		print "error non scalar parameter"
		return F
		}

	if ( min(...) <= 0 )
		{
		print "error 0 or negative parameter"
		return F
		}

	local p := prod(...)
	local value := []

	if ( length(init) > 0 )
		{
		if ( p % length(init) != 0 )
			value := [rep(init, as_integer(p / length(init))),
					init[1:(p % length(init))]]
		else
			value := rep(init, as_integer(p / length(init)))
		}
	else
		value := rep(init, p);

	if ( num_args(...) > 1 )
		value::shape := [...]

	return value
	}


# Given an ASCII table in "tbl" with the same number of columns in
# each row, returns a record of arrays with the given names, each
# array corresponding to a column in the table.
func table_to_arrays(tbl, array_names)
	{
	local num_elements, num_arrays, arrays, mask, result, i

	num_elements := len(tbl)
	num_arrays := len(split(tbl[1]))

	if ( num_arrays != len(array_names) )
		{
		print "mismatch between", len(array_names), "array names and",
			num_arrays, "arrays in table_to_arrays()"
		exit
		}

	arrays := as_double(split(tbl))
	mask := seq(0, len(arrays)-1, num_arrays)
	result := [=]

	for ( i in 1:num_arrays )
		result[array_names[i]] := arrays[mask + i]

	return result
	}
