extends "res://addons/gut/compare_result.gd"
const INDENT = "    "
enum { DEEP, SHALLOW, SIMPLE }

var _utils = load("res://addons/gut/utils.gd").get_instance()
var _strutils = _utils.Strutils.new()
var _compare = _utils.Comparator.new()
var DiffTool = load("res://addons/gut/diff_tool.gd")

var _value_1 = null
var _value_2 = null
var _total_count = 0
var _diff_type = null
var _brackets = null
var _valid = true
var _desc_things = "somethings"


# -------- comapre_result.gd "interface" ---------------------
func set_are_equal(val):
	_block_set("are_equal", val)


func get_are_equal():
	return are_equal()


func set_summary(val):
	_block_set("summary", val)


func get_summary():
	return summarize()


func get_different_count():
	return differences.size()


func get_total_count():
	return _total_count


func get_short_summary():
	var text = str(
		_strutils.truncate_string(str(_value_1), 50),
		" ",
		_compare.get_compare_symbol(are_equal()),
		" ",
		_strutils.truncate_string(str(_value_2), 50)
	)
	if !are_equal():
		text += str(
			"  ",
			get_different_count(),
			" of ",
			get_total_count(),
			" ",
			_desc_things,
			" do not match."
		)
	return text


func get_brackets():
	return _brackets


# -------- comapre_result.gd "interface" ---------------------


func _invalidate():
	_valid = false
	differences = null


func _init(v1, v2, diff_type = DEEP):
	_value_1 = v1
	_value_2 = v2
	_diff_type = diff_type
	_compare.set_should_compare_int_to_float(false)
	_find_differences(_value_1, _value_2)


func _find_differences(v1, v2):
	if _utils.are_datatypes_same(v1, v2):
		if typeof(v1) == TYPE_ARRAY:
			_brackets = {"open": "[", "close": "]"}
			_desc_things = "indexes"
			_diff_array(v1, v2)
		elif typeof(v2) == TYPE_DICTIONARY:
			_brackets = {"open": "{", "close": "}"}
			_desc_things = "keys"
			_diff_dictionary(v1, v2)
		else:
			_invalidate()
			_utils.get_logger().error("Only Arrays and Dictionaries are supported.")
	else:
		_invalidate()
		_utils.get_logger().error("Only Arrays and Dictionaries are supported.")


func _diff_array(a1, a2):
	_total_count = max(a1.size(), a2.size())
	for i in range(a1.size()):
		var result = null
		if i < a2.size():
			if _diff_type == DEEP:
				result = _compare.deep(a1[i], a2[i])
			else:
				result = _compare.simple(a1[i], a2[i])
		else:
			result = _compare.simple(a1[i], _compare.MISSING, "index")

		if !result.are_equal:
			differences[i] = result

	if a1.size() < a2.size():
		for i in range(a1.size(), a2.size()):
			differences[i] = _compare.simple(_compare.MISSING, a2[i], "index")


func _diff_dictionary(d1, d2):
	var d1_keys = d1.keys()
	var d2_keys = d2.keys()

	# Process all the keys in d1
	_total_count += d1_keys.size()
	for key in d1_keys:
		if !d2.has(key):
			differences[key] = _compare.simple(d1[key], _compare.MISSING, "key")
		else:
			d2_keys.remove(d2_keys.find(key))

			var result = null
			if _diff_type == DEEP:
				result = _compare.deep(d1[key], d2[key])
			else:
				result = _compare.simple(d1[key], d2[key])

			if !result.are_equal:
				differences[key] = result

	# Process all the keys in d2 that didn't exist in d1
	_total_count += d2_keys.size()
	for i in range(d2_keys.size()):
		differences[d2_keys[i]] = _compare.simple(_compare.MISSING, d2[d2_keys[i]], "key")


func summarize():
	var summary = ""

	if are_equal():
		summary = get_short_summary()
	else:
		var formatter = load("res://addons/gut/diff_formatter.gd").new()
		formatter.set_max_to_display(max_differences)
		summary = formatter.make_it(self)

	return summary


func are_equal():
	if !_valid:
		return null
	else:
		return differences.size() == 0


func get_diff_type():
	return _diff_type


func get_value_1():
	return _value_1


func get_value_2():
	return _value_2