## Abstract class representing a range of notes in some kind of array,
## expressed by a beginning index and an ending index: [begin, end).
@abstract class_name View extends Node

## Get the array this View refers to.
@abstract func get_data() -> Variant

## Update the view to be relative to beat.
## Can be connected to a beat update signal.
@abstract func update_current_beat(beat: float) -> void

## Beginning of the range relative to te current beat where notes will be visible.
## Any notes where (hit_beat < current_beat + offset_begin) will NOT be visible.
@export var offset_begin: float = -4.0

## End of the range relative to the current beat where notes will be visible.
## Any notes where (hit_beat > current_beat + offset_end) will NOT be visible.
@export var offset_end: float = 4.0

## Return the index to the first element.
func begin() -> int:
	return _begin

## Return the index after the last element (equal to last index + 1).
func end() -> int:
	return _end

## Size of the range encompassed by begin() and end().
func size() -> int:
	return int(_begin >= 0) * _end - _begin

# ======= IMPLEMENETATION ======= #
var _begin: int = -1
var _end: int = -1

var _current_beat: float = -999
var _previous_beat: float = -999

func _reset_view() -> void:
	_begin = -1
	_end = -1
	_current_beat = -999
	_previous_beat = -999

## Update the view to match _current_beat.
func _update_view_relative_to_notes(notes: NoteArray) -> void:
	var new_begin = _begin
	var new_end = _end
	if _current_beat > _previous_beat:
		# Update forward.
		while(new_begin < notes.size()) and (notes.beat_at(new_begin) < _current_beat + offset_begin):
			new_begin += 1
		while(new_end < notes.size()) and (notes.beat_at(new_end) <= _current_beat + offset_end):
			new_end += 1
	elif _current_beat < _previous_beat:
		# Update backward.
		while(new_begin >= 0) and (notes.beat_at(new_begin) >= _current_beat + offset_begin):
			_begin -= 1
		while(new_end >= 0) and (notes.beat_at(new_end) > _current_beat + offset_end):
			new_end -= 1
		if(new_begin != _begin):
			new_begin += 1
		if(new_end != _end):
			new_end += 1
	
	_begin = new_begin
	_end = new_end
	_previous_beat = _current_beat
