## Input representing angle changes between two fingers. 
@tool
class_name GUIDEInputTouchAngle
extends GUIDEInput

## Unit in which the angle should be provided
enum AngleUnit {
	## Angle is provided in radians
	RADIANS = 0,
	## Angle is provided in degrees.
	DEGREES = 1
}

## The unit in which the angle should be provided
@export var unit:AngleUnit = AngleUnit.RADIANS

var _initial_angle:float = INF

# We use the reset call to calculate the angle for this frame
# so it can serve as reference for the next frame
func _needs_reset() -> bool:
	return true

func _reset():
	var angle = _calculate_angle()
	# update initial angle when input is actuated or stops being actuated
	if is_finite(_initial_angle) != is_finite(angle):
		_initial_angle = angle

func _begin_usage() -> void:
	# subscribe to relevant input events
	_state.touch_state_changed.connect(_refresh)
	_refresh()
	
func _end_usage() -> void:
	# unsubscribe from input events
	_state.touch_state_changed.disconnect(_refresh)
	
func _refresh():
	var angle := _calculate_angle()
	# if either current angle or initial angle is not set,
	# we are zero
	if not is_finite(angle) or not is_finite(_initial_angle):
		_value = Vector3.ZERO
		return
		
	# we assume that _initial_distance is never 0 because
	# you cannot have two fingers physically at the same place
	# on a touch screen (unless you're a ghost, which raises
	# the question how you are using a touch screen in the first place)
	var final_angle:float = angle - _initial_angle
	if unit == AngleUnit.DEGREES:
		final_angle = rad_to_deg(final_angle)
	
	_value = Vector3(final_angle, 0, 0)
		
	
func _calculate_angle() -> float:
	var pos1:Vector2 = _state.get_finger_position(0, 2)
	# if we have no position for first finger, we can immediately abort
	if not pos1.is_finite():
		return INF
		
	var pos2:Vector2 = _state.get_finger_position(1, 2)
	# if there is no second finger, we can abort as well
	if not pos2.is_finite():
		return INF
		
	# calculate distance for the fingers
	return -pos1.angle_to_point(pos2)
	
 		
func is_same_as(other:GUIDEInput):
	return other is GUIDEInputTouchAngle and \
		other.unit == unit


func _to_string():
	return "(GUIDEInputTouchAngle unit=" + ("radians" if unit == AngleUnit.RADIANS else "degrees") + ")"


func _editor_name() -> String:
	return "Touch Angle"

	
func _editor_description() -> String:
	return "Angle changes of two touching fingers."


func _native_value_type() -> GUIDEAction.GUIDEActionValueType:
	return GUIDEAction.GUIDEActionValueType.AXIS_1D
