@tool
class_name ScatterBaseModifier
extends Resource

# Modifiers place transforms. They create, edit or remove transforms in a list,
# before the next Modifier in the stack does the same.
# All Modifiers must inherit from this class.
# Transforms in the provided transforms list must be in global space.


signal warning_changed
signal modifier_changed

const TransformList = preload("../common/transform_list.gd")
const Domain = preload("../common/domain.gd")
const DocumentationInfo = preload("../documentation/documentation_info.gd")

@export var enabled := true
@export var override_global_seed := false
@export var custom_seed := 0
@export var restrict_height := false # Tells the modifier whether to constrain transforms to the local XY plane or not
@export var reference_frame := 0

var display_name: String = "Base Modifier Name"
var category: String = "None"
var documentation := DocumentationInfo.new()
var warning: String = ""
var warning_ignore_no_transforms := false
var warning_ignore_no_shape := true
var expanded := false
var can_override_seed := false
var can_restrict_height := true
var global_reference_frame_available := true
var local_reference_frame_available := false
var individual_instances_reference_frame_available := false
var use_edge_data := false
var deprecated := false
var deprecation_message: String
var interrupt_update: bool = false


func get_warning() -> String:
	return warning


func process_transforms(transforms: TransformList, domain: Domain, global_seed: int) -> void:
	if not domain.get_root().is_inside_tree():
		return

	if Engine.is_editor_hint():
		_clear_warning()

		if deprecated:
			warning += "This modifier is deprecated.\n"
			warning += deprecation_message + "\n"

		if not enabled:
			warning_changed.emit()
			return

		if domain.is_empty() and not warning_ignore_no_shape:
			warning += """The Scatter node does not have a shape.
			Add at least one ScatterShape node as a child.\n"""

		if transforms.is_empty() and not warning_ignore_no_transforms:
			warning += """There's no transforms to act on.
			Make sure you have a Create modifier before this one.\n
			"""

	var random_seed: int = global_seed
	if can_override_seed and override_global_seed:
		random_seed = custom_seed
	interrupt_update = false

	@warning_ignore("redundant_await") # Not redundant as child classes could use the await keyword here.
	await _process_transforms(transforms, domain, random_seed)

	warning_changed.emit()


func get_copy():
	var script: Script = get_script()
	var copy = script.new()
	for p in get_property_list():
		var value = get(p.name)
		copy.set(p.name, value)
	return copy


## Notify the modifier it should stop updating as soon as it can.
func interrupt() -> void:
	interrupt_update = true


func is_using_global_space() -> bool:
	return reference_frame == 0


func is_using_local_space() -> bool:
	return reference_frame == 1


func is_using_individual_instances_space() -> bool:
	return reference_frame == 2


func use_global_space_by_default() -> void:
	reference_frame = 0


func use_local_space_by_default() -> void:
	reference_frame = 1


func use_individual_instances_space_by_default() -> void:
	reference_frame = 2


func _clear_warning() -> void:
	warning = ""
	warning_changed.emit()


# Override in inherited class
func _process_transforms(_transforms: TransformList, _domain: Domain, _seed: int) -> void:
	pass
