## Small helper tool to work with Godot Arrays
class_name GdArrayTools
extends RefCounted


const max_elements := 32
const ARRAY_TYPES := [
	TYPE_ARRAY,
	TYPE_PACKED_BYTE_ARRAY,
	TYPE_PACKED_INT32_ARRAY,
	TYPE_PACKED_INT64_ARRAY,
	TYPE_PACKED_FLOAT32_ARRAY,
	TYPE_PACKED_FLOAT64_ARRAY,
	TYPE_PACKED_STRING_ARRAY,
	TYPE_PACKED_VECTOR2_ARRAY,
	TYPE_PACKED_VECTOR3_ARRAY,
	TYPE_PACKED_COLOR_ARRAY
]


static func is_array_type(value) -> bool:
	return is_type_array(typeof(value))


static func is_type_array(type :int) -> bool:
	return  type in ARRAY_TYPES


## Filters an array by given value[br]
## If the given value not an array it returns null, will remove all occurence of given value.
static func filter_value(array, value :Variant) -> Variant:
	if not is_array_type(array):
		return null
	var filtered_array = array.duplicate()
	var index :int = filtered_array.find(value)
	while index != -1:
		filtered_array.remove_at(index)
		index = filtered_array.find(value)
	return filtered_array


## Erases a value from given array by using equals(l,r) to find the element to erase
static func erase_value(array :Array, value) -> void:
	for element in array:
		if GdObjects.equals(element, value):
			array.erase(element)


## Scans for the array build in type on a untyped array[br]
## Returns the buildin type by scan all values and returns the type if all values has the same type.
## If the values has different types TYPE_VARIANT is returend
static func scan_typed(array :Array) -> int:
	if array.is_empty():
		return TYPE_NIL
	var actual_type := GdObjects.TYPE_VARIANT
	for value in array:
		var current_type := typeof(value)
		if not actual_type in [GdObjects.TYPE_VARIANT, current_type]:
			return GdObjects.TYPE_VARIANT
		actual_type = current_type
	return actual_type


## Converts given array into a string presentation.[br]
## This function is different to the original Godot str(<array>) implementation.
## The string presentaion contains fullquallified typed informations.
##[br]
## Examples:
## 	[codeblock]
##		# will result in PackedString(["a", "b"])
## 		GdArrayTools.as_string(PackedStringArray("a", "b"))
##		# will result in PackedString(["a", "b"])
##		GdArrayTools.as_string(PackedColorArray(Color.RED, COLOR.GREEN))
## 	[/codeblock]
static func as_string(elements :Variant, encode_value := true) -> String:
	if not is_array_type(elements):
		return "ERROR: Not an Array Type!"
	var delemiter = ", "
	if elements == null:
		return "<null>"
	if elements.is_empty():
		return "<empty>"
	var prefix := _typeof_as_string(elements) if encode_value else ""
	var formatted := ""
	var index := 0
	for element in elements:
		if max_elements != -1 and index > max_elements:
			return prefix + "[" + formatted + delemiter + "...]"
		if formatted.length() > 0 :
			formatted += delemiter
		formatted += GdDefaultValueDecoder.decode(element) if encode_value else str(element)
		index += 1
	return prefix + "[" + formatted + "]"


static func _typeof_as_string(value :Variant) -> String:
	var type := typeof(value)
	# for untyped array we retun empty string
	if type == TYPE_ARRAY:
		return ""
	return GdObjects.typeof_as_string(value)
