# AVSLib :: 'array' package :: 'operators' module
# Copyright (c) 2005 George Zarkadas (gzarkadas@users.sourceforge.net)

# This program is free software; you can redistribute it and/or modify it under the terms of 
# the GNU General Public License as published by the Free Software Foundation; either 
# version 2 of the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
# PURPOSE.  See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along with this program; 
# if not, write to the "Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
# MA  02111-1307  USA"

DefineModule("avslib", "array", "operators")

global __load__ = Eval("""
	LoadModule("avslib", "string", "core")
	LoadModule("avslib", "array", "core")
	""")

# Array operator functions

# array_first controls whether array elements will be before the operator 
# (default) or after (false). This is relevant only for division, modulo 
# and comparison operations. Note that you can use function with 
#    'operation' -> "=" and 'array_first' -> true 
# or not specified to assign 'scalar' to all array elements .
#
Function ArrayOpValue(string array, val scalar, string operation, \
	bool "array_first")
{
	arrlen = array.ArrayLen()
	array_first = Default(array_first, true)
	elm = QuoteNoexpr(array.ArrayGetString(0))
	sca = QuoteNoexpr(Apply(ArraySetValueHandler, scalar))
	new_val = Eval((array_first) \
		? elm + operation + sca \
		: sca + operation + elm) 
	# call handler function to return the appropriate 
	# string representation of new_val
	return Apply(ArraySetValueHandler, new_val) + \
		(arrlen > 1 ? __ARRAY_DLM + ArrayOpValue(array.ArrayDelete(0), \
		scalar, operation, array_first) : "")
}

Function ArrayOpArray(string array1, string array2, string operation)
{
	arrlen = array1.ArrayLen()
	Assert(arrlen == array2.ArrayLen(), \
		"ArrayOpArray: arrays must be of the same size")
	elm1 = QuoteNoexpr(array1.ArrayGetString(0))
	elm2 = QuoteNoexpr(array2.ArrayGetString(0))
	new_val = Eval(elm1 + operation + elm2) 
	# call handler function to return the appropriate 
	# string representation of new_val
	return Apply(ArraySetValueHandler, new_val) + \
		(arrlen > 1 ? __ARRAY_DLM + ArrayOpArray(array1.ArrayDelete(0), \
		array2.ArrayDelete(0), operation) : "")
}

# If args contains any string arguments, they must be quoted, 
# else the function will fail
#
Function ArrayOpFunc(string array, string func, string "args")
{
	arrlen = array.ArrayLen()
	extra_args = Defined(args) ? "," + args : "" 
	elm = QuoteNoexpr(array.ArrayGetString(0))
	new_val = Eval( func + "(" + elm + extra_args + ")" )
	# call handler function to return the appropriate 
	# string representation of new_val
	return Apply(ArraySetValueHandler, new_val) + \
		(arrlen > 1 \
			? __ARRAY_DLM + ArrayOpFunc(array.ArrayDelete(0), func, args) \
			: "")
}

# If args contains any string arguments, they must be quoted, 
# else the function will fail
#
Function ArrayOpArrayFunc(string array1, string array2, string func, string "args")
{
	arrlen = array1.ArrayLen()
	extra_args = Defined(args) ? "," + args : "" 
	Assert(arrlen == array2.ArrayLen(), \
		"ArrayOpArrayFunc: arrays must be of the same size")
	elm1 = QuoteNoexpr(array1.ArrayGetString(0))
	elm2 = QuoteNoexpr(array2.ArrayGetString(0))
	new_val = Eval(func + "(" + elm1 + "," + elm2 + extra_args + ")")
	# call handler function to return the appropriate 
	# string representation of new_val
	return Apply(ArraySetValueHandler, new_val) + \
		(arrlen > 1 ? __ARRAY_DLM + ArrayOpArrayFunc(array1.ArrayDelete(0), \
		array2.ArrayDelete(0), func, args) : "")
}

# Returns the sum of the results of elm_func over the entire array, using sum_func.
# if elm_func or sum_func need the entire array (for example to include previous 
# or next values to calculation) you must code them such that they accept an extra 
# array argument and pass the array inside elm_args or/and sum_args
#
Function ArraySum(string array, string "elm_func", string "elm_args", \
	string "sum_func", string "sum_args")
{
	arrlen = array.ArrayLen()
	xe_args = Defined(elm_args) ? "," + elm_args : "" 
	xs_args = Defined(sum_args) ? "," + sum_args : "" 
	elm_func = Default(elm_func, "__self")
	sum_func = Default(sum_func, "__sum2")
	elm = QuoteNoexpr(array.ArrayGetString(0))
	new_val = Eval(elm_func + "(" + elm + xe_args + ")")
	# Do not use handler function here; it is not necessary 
	# (this also avoids the creation of excess clip auto-globals).
	# Note that ArraySum arguments must be quoted (in order to get interpreted 
	# as strings from Eval), while sum_func arguments should not.
	evstr = sum_func + "(new_val, ArraySum(array.ArrayDelete(0), " \
		+ StrQuote(elm_func) \
		+ (xe_args == "" ? ",sum_func=" : "," + StrQuote(elm_args) + ",") \
		+ StrQuote(sum_func) \
		+ (xs_args == "" ? "" : \
			((xe_args == "" ? ",sum_args=" : ",") + StrQuote(sum_args)) ) \
		+ ")"+ xs_args +")"
	# The branches above deal with missing intermediate arguments. 
	# If this happens, rest arguments must be specified with the 
	# positional notation.
	return arrlen > 1 ? Eval(evstr) : new_val
}
