@tool

extends Panel

## Основной скрипт для режима "Работа"

@export var Bip:              PackedScene  ## Индикатор излучения цели
@export var col_grey:         Color        ## Второй цвет для фона
@export var col_red:          Color        ## Первый цвет для фона
@export var drag_scale_band:  float        ## Масштаб изменения параметра от движения мыши для строба по радиальному размеру
@export var drag_scale_width: float        ## Масштаб изменения параметра от движения мыши для строба по угловому размеру
@export var freq_high:        float        ## Верхняя рабочая частота, МГЦ.
@export var freq_low:         float        ## Нижняя рабочая частота, МГЦ.
@export var radius_center:    Vector2      ## Координаты центра диаграммы пеленг-частота
@export var radius_internal:  float        ## Внутренний радиус диаграммы пеленг-частота
@export var radius_outter:    float        ## Внешний радиус диаграммы пеленг-частота
@export var strob_max_band:   float        ## Максимальная ширина строба по углу
@export var strob_max_width:  float        ## Максимальная ширина строба по углу
@export var strob_min_band:   float        ## Минимальная ширина строба по частоте
@export var strob_min_width:  float        ## Минимальная ширина строба по углу
@export var window_0_id:      int          ## Идетификатор окна. Присваивается godot от 0 до количества созданных окон


var drag_button: MouseButton          ## Кнопка мыши нажатая при перетаскивании
var drag_fsm: DragFSM = DragFSM.IDLE  ## Текущее состояние перетаскивания
var drag_pos_begin: Vector2           ## Точка начала перетаскивания
var max_zoom: int                     ## Максимальный уровень детализации
var min_zoom: int                     ## Минимальный уровень детализации
var shift_pressed: bool               ## Кнопка SHIFT нажата
var strob_band_begin: float           ## Ширина строба в момент начала перетаскивания
var strob_dir_begin: float            ## Направление антенны в момент начала перетаскивания
var strob_width_begin: float          ## Ширина строба по углу в момент начала перетаскивания


signal drag_begin     ## Вызывается в момент начала перетаскивания
signal drag_continue  ## Вызывается во время продолжения перетаскивания
signal drag_end       ## Вызывается в момент завершения перетаскивания


## Состояние перетаскивания
enum DragFSM {
    DRAG,  ## В процессе
    IDLE,  ## Не активно, ожидание
    OFF    ## Выключено
    }


## Обработчик сигнала изменения списка целей
func on_threats_resized(threats: Dictionary): $count_all_pad/count_all.text = '%02d' % threats.size()


func on_threat_selected(th, ecm_btns): on_rto_threat_sel(th.id, ecm_btns)


func on_button_view_toggled(toggled: bool): signaller.emit_signal('map_mode_changed', int(toggled))


##
func _enter_tree() -> void:
    var timer1 = Timer.new()
    timer1.name = 'timer1'
    add_child(timer1)
    timer1.one_shot = true
    timer1.connect('timeout', Callable(self, 'on_enter_tree'))
    timer1.start(1.0)


func _exit_tree() -> void:
    var timer1 = get_node('timer1')
    remove_child(timer1)
    timer1.queue_free()


## Производит инициализацию
func _ready():
    min_zoom = ProjectSettings.get_setting('application/config/map_minimum_zoom', 5)
    max_zoom = ProjectSettings.get_setting('application/config/map_maximum_zoom', 19)
    drag_fsm = DragFSM.OFF
    $btn_zoom.set_meta('zoom', min_zoom - 1)
    $btn_strob.button_connect('pressed', Callable(self, 'on_button_strobe_pressed'))
    $btn_view.button_connect('toggled', Callable(self, 'on_button_view_toggled'))
    var nodes: Array = get_tree().get_nodes_in_group('группа-режим-помехи')
    nodes.any(func(btn): btn.button_connect('pressed', Callable(self, 'on_button_pressed').bind(btn, nodes)))
    threats.connect('threat_new',          Callable(self, 'on_threat_new'))
    threats.connect('threat_lost',         Callable(self, 'on_threat_lost'))
    threats.connect('threats_resized',     Callable(self, 'on_threats_resized'))
    threats.connect('threat_update',       Callable(self, 'on_threat_update'))
    signaller.connect('zoom_complete',     Callable(self, '_on_zoom_complete'))
    signaller.connect('rto_threat_sel',    Callable(self, 'on_rto_threat_sel').bind(nodes))
    signaller.connect('rto_threat_unsel',  Callable(self, 'on_rto_threat_unsel').bind(nodes))
    signaller.connect('threat_selected',   Callable(self, 'on_threat_selected').bind(nodes))
    signaller.connect('interfer_selected', Callable(self, 'on_interfer_selected').bind(nodes))
    signaller.connect('interfer_new',      Callable(self, 'on_interfer_new'))
    signaller.connect('interfer_off_all',  Callable(self, 'interfer_off_all'))
    interfer.connect('interfer_update',    Callable(self, 'on_interfer_new'))

func on_enter_tree() -> void:
    call_deferred('_on_btn_scale_pressed')
    call_deferred('on_button_strobe_pressed')
    $tilemap.position = $canvas.get_strob_center()


## Производит отображение цели на диаграмму
func map_threat_to_bip(th: threats.Threat, bip: Control):
    bip.position = tools.pos_calc(
        th.freq,
        th.aoa,
        radius_center,
        radius_internal,
        radius_outter,
        freq_low,
        freq_high)


## Обработчик сигнала обновления цели
func on_threat_update(th):
    var bip = get_node('%d' % th.id)
    map_threat_to_bip(th, bip)


## Обработчик выбора помехи для цели
func on_interfer_new(ecm):
    if interfer.thrs.has(ecm.ispp):
        var th_id = interfer.thrs[ecm.ispp]
        var bip = get_node('%d' % th_id)
        if ecm.krp != interfer.INTERFER_OFF:
            bip.set_track_visible(true)
            if ecm.svk == 1:
                bip.set_ecm_visible(true)
            else: bip.set_ecm_visible(false)
        else:
            print_debug()
            bip.set_ecm_visible(false)
            bip.set_track_visible(false)


func interfer_off_all():
    var bips: Array = get_children().filter(func(item): return item.name.is_valid_int())
    for bip in bips:
        bip.set_ecm_visible(false)
        bip.set_track_visible(false)


## Обработчик сигнала обнаружения цели
func on_threat_new(th) -> void:
    var bip = Bip.instantiate()
    bip.name = '%d' % th.id
    map_threat_to_bip(th, bip)
    add_child(bip)


## Обработчик сигнала потери цели
func on_threat_lost(th) -> void:
    var bip = get_node('%d' % th.id)
    remove_child(bip)
    bip.free()


## Обработчик выбора РТО цели
func on_rto_threat_sel(th_id, ecm_btns):
    var bips: Array = get_children().filter(func(item): return item.name.is_valid_int())
    for item in bips:
        if th_id == item.name.to_int():
            item.set_sel_visible(true)
        else:
            item.set_sel_visible(false)
    for btn in ecm_btns:
        btn.set_disabled(false)


## Обработчик снятия выбора РТО цели
func on_rto_threat_unsel(th_id, ecm_btns):
    var bips: Array = get_children().filter(func(item): return item.name.is_valid_int())
    for item in bips:
        if th_id == item.name.to_int():
            item.set_sel_visible(false)
            break
    for btn in ecm_btns:
        btn.set_pressed(false)
        btn.set_disabled(true)


## Обработчик нажатия кнопки "Строб". Управляет отображением строба
func on_button_strobe_pressed() -> void:
    drag_fsm = DragFSM.IDLE if $btn_strob.is_pressed() else DragFSM.OFF
    $canvas.set_strob_visible(drag_fsm == DragFSM.IDLE)


## Поведение радиокнопок в группе. Управляет состоянием кнопок в радиогруппе
func on_button_pressed(btn_this, btn_others) -> void:
    for btn_other in btn_others: btn_other.set_pressed(btn_this == btn_other)
    signaller.emit_signal('interfer_init', btn_this)


## Управляет состоянием кнопок в радиогруппе при выборе помехи
func on_interfer_selected(ecm, btns) -> void:
    var ecm_name: String
    if ecm != null:
        ecm_name = ecm.krp
    else:
        ecm_name = interfer.INTERFER_OFF
    for btn in btns:
        btn.set_disabled(false)
        btn.get_meta('rfi_name')
        if ecm_name == btn.get_meta('rfi_name'):
            btn.set_pressed(true)
        else:
            btn.set_pressed(false)


## Возвращает ширину строба по направлению
func get_strob_width(pos: Vector2, prev: float) -> float:
    var strob_dir_width: float = prev + (drag_pos_begin.y - pos.y) * drag_scale_width
    strob_dir_width = tools.clip_value(strob_dir_width, strob_min_width, strob_max_width)
    return strob_dir_width


## Возвращает ширину строба по частоте
func get_strob_band(pos: Vector2, prev: float) -> float:
    var strob_dir_band: float = prev - (drag_pos_begin.y - pos.y) * drag_scale_band
    strob_dir_band = tools.clip_value(strob_dir_band, strob_min_band, strob_max_band)
    return strob_dir_band


## Устанавливает центр строба по частоте и направлению
func set_strob(pos: Vector2) -> void:
    var radp: Vector2 = tools.map_dec_to_rad(radius_center, pos)
    if radp.y < $canvas.get_radius_outter():
        $canvas.set_strob_dir(radp.x)
        $canvas.set_strob_radius(radp.y)


## Обработка движения мыши для управления стробом. Вызывается во время движения мыши
func _on_drag_continue(event) -> void:
    if drag_button == MOUSE_BUTTON_RIGHT:
        if shift_pressed:
            var strob_width: float = get_strob_width(event.position, strob_width_begin)
            $canvas.set_strob_width(strob_width)
        else:
            var strob_band: float = get_strob_band(event.position, strob_band_begin)
            $canvas.set_strob_band(strob_band)
    elif drag_button == MOUSE_BUTTON_LEFT:
        set_strob(event.position)


## Обработка движения мыши для управления стробом. Вызывается при нажатии мыши
func _on_drag_begin(event) -> void:
    drag_pos_begin = event.position
    if drag_button == MOUSE_BUTTON_LEFT:
        set_strob(event.position)
    elif drag_button == MOUSE_BUTTON_RIGHT:
        strob_width_begin = $canvas.get_strob_width()
        strob_band_begin = $canvas.get_strob_band()


## Обработчик событий ввода. Вызывается godot
func _input(event) -> void:
    if not is_visible_in_tree(): return
    if event is InputEventMouseMotion:
        if drag_fsm == DragFSM.DRAG:
            emit_signal('drag_continue', event)
    elif event is InputEventMouseButton:
        drag_button = event.button_index
        if event.pressed:
            if drag_fsm == DragFSM.IDLE:
                drag_fsm = DragFSM.DRAG
                emit_signal('drag_begin', event)
        else:
            drag_fsm = DragFSM.IDLE
            emit_signal('drag_end', event)
    elif event is InputEventKey:
        if event.physical_keycode == KEY_SHIFT:
            shift_pressed = event.pressed


## Вызывается по нажатию кнопки "Детализация"
func _on_btn_scale_pressed() -> void:
    var zoom = $btn_zoom.get_meta('zoom')
    zoom = zoom + 1 if zoom < max_zoom else min_zoom
    signaller.emit_signal('zoom_changed', zoom)


## Вызывается по завершению изменения детализации карты
func _on_zoom_complete(zoom: int) -> void:
    var prefix = $btn_zoom.get_meta('prefix')
    $btn_zoom/lbl.text = '%s %d' % [prefix, zoom]
    $btn_zoom.set_meta('zoom', zoom)
