class_name work 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 до количества созданных окон.

const SVK_EMIT = 1                      ## Код состояния выполнения помехи - выполняется

var drag_button: MouseButton            ## Кнопка мыши нажатая при перетаскивании.
var drag_fsm: DragFSM = DragFSM.IDLE    ## Текущее состояние перетаскивания.
var btn_select: BtnSel = BtnSel.SECTOR  ## Текущее состояние кнопки выбора цели.
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            ## Ширина строба по углу в момент начала перетаскивания.
var view_mode: MapViewMode              ## Режим отображения карты
var thrs_dict: Dictionary               ## Ссылка на словарь целей
var gos_flag = true                     ## Флаг работать по своим целям
var color_ecm: Color
var color_select: Color
var color_emit: Color
var color_emit_sel: Color
var color_closed: Color
var col_btn_act: Color = Color.WHITE
var color_closed_emit: Color
var signal_conections: Array

var course = 0.0                        ## Курс корабля

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


## Размеры карты для разных режимов РТО и РЛС соответственно
const map_sizes = [
    Rect2i(360, 360, 400, 400),
    Rect2i(82, 82, 955, 955)]
var fs_band = prd.FS_BAND_RTO    ## Текущий режим блоков ФС по частоте
var fs_selected: Dictionary      ## Словарь выбранных секторов
var fs_active: Dictionary        ## Словарь секторов назначенных на подавление
var fs_emit: Dictionary          ## Словарь секторов назначенных на подавление
var fs_closed: Dictionary        ## Словарь для секторов запрета
var fs_failed: PackedInt32Array  ## Индикация сломанных секторов (модули ФС). AntBandState.ANT_BAND_READY - исправен, AntBandState.ANT_BAND_FAILURE - сломан.

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

## Режим выбора
enum BtnSel {
    SECTOR,  ## Выбор сектора.
    THREAT,  ## Выбор цели.
    FS       ## Выбор стробом.
    }


## Режим отображения карты
enum MapViewMode {
    RTO = 0,  ## Режим приоритет РТО (малая карта, широкие секторы)
    RLS = 1   ## Режим приоритет РЛС (большая карта, узкие секторы)
    }


enum AntBandState {
    ANT_BAND_FAILED = 0,
    ANT_BAND_READY = 1,
    ANT_BAND_ASSIGNED = 2
}

const VAL_TO_EVENT = {
    false: 'manual_control',  ## Выбор целей и установка помех вручную.
    true: 'full_auto' }       ## Выбор целей и установка помех автоматически.


var SIGNALS_CONNECTIONS = [
    [interfer,  'interfer_update',        'on_interfer_new'],
    [signaller, 'bip_pressed',            'on_bip_pressed'],
    [signaller, 'clear_klaster',          'clear_all_klaster'],
    [signaller, 'fs_selected',            'on_fs_selected'],
    [signaller, 'fs_update_color',        'set_fs_color'],
    [signaller, 'fs_update_state',        'on_fs_update_state'],
    [signaller, 'interfer_new',           'on_interfer_new'],
    [signaller, 'interfer_off_all',       'on_interfer_off_all'],
    [signaller, 'interfer_prinuditelno',  'on_chk_interfer_prinuditelno'],
    [signaller, 'interfer_prinuditelno',  'on_interfer_prinuditelno'],
    [signaller, 'interfer_selected',      'on_interfer_selected'],
    [signaller, 'map_user_panning',       'on_user_panning'],
    [signaller, 'prog_ecm_off',           'on_interfer_new'],
    [signaller, 'rto_threat_sel',         'on_rto_threat_sel'],
    [signaller, 'rto_threat_unsel',       'on_rto_threat_unsel'],
    [signaller, 'sector_klaster',         'sector_klaster'],
    [signaller, 'th_aoa_update',          'on_th_aoa_update'],
    [signaller, 'threat_selected',        'on_threat_selected'],
    [signaller, 'update_coordinates_map', 'on_update_coordinates_label'],
    [signaller, 'update_scale_map',       'on_update_scale_label'],
    [threats,   'threat_lost',            'on_threat_lost'],
    [threats,   'threat_new',             'on_threat_new'],
    [threats,   'threat_update',          'on_threat_update'],
    [threats,   'threats_resized',        'on_threats_resized'] ]


## Обработчик выбора цели.
func on_threat_selected(th): on_rto_threat_sel(th.id)


## Встроенный обратный вызов.
func on_enter_tree() -> void: call_deferred('on_button_strobe_pressed')


func clear_all_klaster(): $canvas.clear_all_seczap()


func on_user_panning(): $btn_center.button_pressed = false


func on_settings_changed():
    var json_col = ProjectSettings.get_setting('application/config/%s' % 'Цвет кнопки \"Подавление\"', '[1.0, 1.0, 1.0, 1.0]')
    var arr_col = JSON.parse_string(json_col)
    col_btn_act = Color(arr_col[0], arr_col[1], arr_col[2], arr_col[3]) if arr_col else Color.WHITE

    gos_flag = ProjectSettings.get_setting('application/config/Включить работу по своим целям', true)
    color_emit = Color(arr_col[0], arr_col[1], arr_col[2], 1.0)
    color_ecm = Color(arr_col[0], arr_col[1], arr_col[2], 1.0)
    color_select = ProjectSettings.get_setting('application/interfer/select_color', Color(1.0, 1.0, 1.0, 1.0))
    color_closed = ProjectSettings.get_setting('application/interfer/closed_sectors', Color(0.0, 0.0, 0.0, 1.0))
    min_zoom = ProjectSettings.get_setting('application/config/map_minimum_zoom', 5)
    max_zoom = ProjectSettings.get_setting('application/config/map_maximum_zoom', 19)
    color_emit_sel = color_select
    color_closed_emit = color_closed

    color_select *= Color(1.0, 1.0, 1.0, 0.0)
    color_ecm *= Color(1.0, 1.0, 1.0, 0.0)
    color_emit_sel *= Color(1.0, 1.0, 1.0, 0.2)
    color_closed *= Color(1.0, 1.0, 1.0, 0.0)
    color_closed_emit *= Color(1.0, 1.0, 1.0, 1.0)


## Обработчик сигнала изменения списка целей.
func on_threats_resized(ths: Dictionary):
    count_threats(ths)
    thrs_dict = ths


## Обработчик нажатия на кнопку вид.
func on_button_view_toggled(toggled: bool):
    signaller.emit_signal('map_mode_changed', int(toggled))
    fs_band = prd.FS_BAND_RLS if toggled else prd.FS_BAND_RTO
    var s = map_sizes[int(toggled)]
    $tilemap.size = s.size
    $tilemap.position = s.position
    view_mode = MapViewMode.RLS if toggled else  MapViewMode.RTO
    if view_mode != MapViewMode.RTO:
        fs_selected.clear()
    $btns_select/btn_strob.disabled = toggled
    $btns_select/btn_fs_sector.disabled = toggled
    $'canvas/строб'.visible = $btns_select/btn_strob.pressed and (not 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 init_fs_failed():
    var sectors_count = $canvas.fs_default_colors.size()
    fs_failed.resize(sectors_count)
    for i in fs_failed.size():
        fs_failed[i] = AntBandState.ANT_BAND_FAILED


## Производит инициализацию.
func _ready():
    ProjectSettings.connect('settings_changed', on_settings_changed)
    on_settings_changed()
    init_fs_failed()
    drag_fsm = DragFSM.OFF
    var btns_select: Array = get_tree().get_nodes_in_group('группа-режим-выбора')
    btns_select.any(func(btn): btn.button_connect('pressed', Callable(self, 'on_button_select').bind(btn, btns_select)))
    on_button_select($btns_select/btn_fs_sector, btns_select)
    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)))
    $btn_close.button_connect('pressed', on_btn_close)
    $btn_work.button_connect('pressed', on_btn_work)
    var unit_nav = network.get_unit_instance('навигация')
    unit_nav.connect('data_received', on_navi_data_received)
    on_btn_center_toggled(true)
    on_btn_activate_toggled(true)
    signaller.connect('режим_работа', connect_all)
    signaller.connect('режим_контроль', disconnect_all)
    signaller.connect('режим_журнал', disconnect_all)
    signaller.connect('режим_эмс', disconnect_all)
    signaller.connect('режим_эмс2', disconnect_all)
    signaller.connect('режим_настройки', disconnect_all)
    connect_all()


func connect_all() -> void:
    signal_conections.clear()
    for item in SIGNALS_CONNECTIONS:
        var proc = Callable(self, item[2])
        var rc = item[0].connect(item[1], proc)
        if rc == Error.OK:
            signal_conections.append([item[0], item[1], proc])
        else:
            var ers = error_string(rc)
            push_error('%s: %s %s %s' % [ers, item[0], item[1], item[2]])
    signaller.emit_signal('connect_work_signal')
    for th in thrs_dict.values():
        var bip = Bip.instantiate()
        bip.name = '%d' % th.id
        map_threat_to_bip(th, bip)
        add_child(bip)


func disconnect_all() -> void:
    for item in signal_conections:
        item[0].disconnect(item[1], item[2])
    signal_conections.clear()
    var bips: Array = get_children().filter(func(item): return item.name.is_valid_int())
    for bip in bips:
        remove_child(bip)
        bip.free()


func sector_klaster(sector_data):
    if sector_data['draw']:
        var rect: Rect2 = sector_data['rect']
        var color: Color = sector_data['color']
        var id: int = sector_data['index']
        $canvas.add_seczap(id, Vector4(rect.position.x, rect.position.y, rect.size.x, rect.size.y))
        $canvas.set_seczap_color(id, color)


func on_navi_data_received(data: Dictionary):
    var k = data.get('k', 0.0)
    $canvas.set_canvas_rotation(k)
    course = k


func on_chk_interfer_prinuditelno(_interfer_sectors):
    $chk_auto.set_pressed_no_signal(false)
    on_value_changed(false)


func on_value_changed(val: bool):
    signaller.emit_signal(VAL_TO_EVENT[val])


func get_all_nodes(root):
    var nodes = []
    nodes.append(root)
    for child in root.get_children():
        nodes.append_array(get_all_nodes(child))
    return nodes


## Производит отображение цели на диаграмму.
func map_threat_to_bip(th: threats.Threat, bip: Control) -> bool:
    var freq = th.freq
    var sector_key = null
    var sector_width = 50.0
    for key in prd.FS_FREQ:
        var freq_range = prd.FS_FREQ[key]
        var _num_values = (freq_range[1] - freq_range[0]) / sector_width
        if freq_range[0] <= freq and freq <= freq_range[1]:
            sector_key = key
            break
    if sector_key != null:
        radius_internal = fs_band[sector_key][0]
        radius_outter = fs_band[sector_key][1]
        freq_low = prd.FS_FREQ[sector_key][0]
        freq_high = prd.FS_FREQ[sector_key][1]
        bip.position = tools.pos_calc(
            th.freq,
            th.aoa,
            radius_center,
            radius_internal,
            radius_outter,
            freq_low,
            freq_high) - bip.size / 2
    return sector_key != null


## Обработчик сигнала обновления цели.
func on_threat_update(th: threats.Threat):
    var bip = get_node('%d' % th.id)
    bip.update(th.tick_rx)
    if th.gos:
        bip.set_bip_color(Color.GREEN)
    else:
        bip.set_bip_color(Color.CORAL if th.proto else Color.WHITE)
    bip.visible = map_threat_to_bip(th, bip)


## Обработчик выбора помехи для цели.
func on_interfer_new(ecm):
    if not interfer.thrs.has(ecm.ispp): return
    var th_id = interfer.thrs[ecm.ispp]
    var bip = get_node_or_null('%d' % th_id)
    if bip != null:
        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:
            bip.set_ecm_visible(false)
            bip.set_track_visible(false)
    else:
        update_fs_colors()


## Обработчик выключения всех помех.
func on_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)
    fs_active.clear()
    fs_emit.clear()
    update_fs_colors()


## Обработчик сигнала обнаружения цели.
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_bip_pressed(th_id):
    if btn_select == BtnSel.THREAT:
        signaller.emit_signal('rto_threat_sel', th_id)


## Обработчик выбора РТО цели.
func on_rto_threat_sel(th_id):
    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)
            unsel_fs_all(false)
        else:
            item.set_sel_visible(false)
    var th = thrs_dict[th_id]
    var krp = interfer.get_krp(th)
    var ecm_btns: Array = get_tree().get_nodes_in_group('группа-режим-помехи')
    for btn in ecm_btns:
        set_btns_disabled(false, btn)
        var btn_meta = btn.get_meta('rfi_name')
        if krp == btn_meta:
            btn.set_rec_visible(true)
        else:
            btn.set_rec_visible(false)


## Обработчик снятия выбора РТО цели.
func on_rto_threat_unsel(th_id):
    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
    set_ecm_btns_state(true)
    var ecm_btns: Array = get_tree().get_nodes_in_group('группа-режим-помехи')
    for btn in ecm_btns:
        btn.set_rec_visible(false)


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


## Поведение радиокнопок в группе. Управляет состоянием кнопок выбора целей.
func on_button_select(btn_this, btn_others) -> void:
    for btn_other in btn_others: btn_other.set_pressed(btn_this == btn_other)
    btn_select = btn_this.get_meta('state')
    on_button_strobe_pressed()
    signaller.emit_signal('rto_threat_unsel_all')
    unsel_fs_all(true)
    set_ecm_btns_state(true)


## Поведение радиокнопок в группе. Управляет состоянием кнопок в радиогруппе.
func on_button_pressed(btn_this, btn_others) -> void:
    $chk_auto.set_pressed_no_signal(false)
    on_value_changed(false)
    for btn_other in btn_others: btn_other.set_pressed(btn_this == btn_other)
    var interfer_name: String = btn_this.get_meta('rfi_name', 'off')
    var fs_arr: Array = []
    for key in fs_selected.keys():
        fs_arr.append(prd.get_fs_param(key))
    signaller.emit_signal('interfer_init', interfer_name, fs_arr, interfer.POW_DEFAULT)


## Управляет состоянием кнопок в радиогруппе при выборе помехи.
func on_interfer_selected(ecm) -> void:
    var ecm_name: String
    if ecm != null:
        ecm_name = ecm.krp
    else:
        ecm_name = interfer.INTERFER_OFF
    var btns: Array = get_tree().get_nodes_in_group('группа-режим-помехи')
    for btn in btns:
        set_btns_disabled(false, btn)
        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 / 2.0, pos / 2.0)
    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 not $canvas.get_strob_visible(): return
    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:
    if not $canvas.get_strob_visible(): return
    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) and (view_mode == MapViewMode.RTO):
        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:
            if btn_select == BtnSel.FS:
                sel_fs_sector(event)
            drag_fsm = DragFSM.IDLE
            emit_signal('drag_end', event)

    elif event is InputEventKey:
        if event.physical_keycode == KEY_SHIFT:
            shift_pressed = event.pressed


## Обработчик нажатия по сектору формирователя сигналов.
func sel_fs_sector(event):
    if view_mode != MapViewMode.RTO: return
    if (event.button_index == MOUSE_BUTTON_LEFT) or (event.button_index == MOUSE_BUTTON_RIGHT):
        var center: Vector2 = $tilemap.position
        var center_offset: Vector2 = ProjectSettings.get_setting('application/interfer/center_offset', Vector2i(0, 25))
        var angle: float = event.position.angle_to_point(center + center_offset) * 180/PI - 45.0 - course
        if angle < 0:
            angle += 360
        var distance: float = event.position.distance_to(center + center_offset)
        var sector: int
        var band: int
        var has_band: bool = false
        for sec in prd.FS_SECTORS.values():
            if angle >= sec[0] and angle <= sec[1]:
                sector = prd.FS_SECTORS.find_key(sec)
        for diap in fs_band.values():
            if distance >= diap[0] and distance <= diap[1]:
                band = fs_band.find_key(diap)
                has_band = true
        if not has_band:
            return
        var fs_index = band * 4 + sector
        if event.button_index == MOUSE_BUTTON_LEFT:
            fs_selected[fs_index] = null
        else:
            fs_selected.erase(fs_index)
        update_fs_colors()
        signaller.emit_signal('rto_threat_unsel_all')
        var btn_state = len(fs_selected) == 0
        set_ecm_btns_state(btn_state)


func set_fs_color(ecms):
    fs_active.clear()
    fs_emit.clear()
    for ecm in ecms.values():
        if not prd.fs_caps_id.has(ecm.nmfs):
            push_warning('нет такого модуля ФС: %d, но имеется: %s' % [ecm.nmfs, prd.fs_caps_id.keys()])
            continue
        if ecm.krp != interfer.INTERFER_OFF:
            fs_active[prd.fs_caps_id[ecm.nmfs]] = null
        if ecm.active:
            fs_emit[prd.fs_caps_id[ecm.nmfs]] = null
    update_fs_colors()


func update_fs_colors():
    var fs_colors = $canvas.fs_default_colors.duplicate()
    for key in fs_active.keys():
        fs_colors[key] = color_ecm
    for key in fs_emit.keys():
        fs_colors[key] = color_emit
    for key in fs_closed:
        if key in fs_emit:
            fs_colors[key] = color_closed_emit
        else:
            fs_colors[key] = color_closed
    for key in fs_selected.keys():
        if key in fs_emit:
            fs_colors[key] = color_emit_sel
        else:
            fs_colors[key] = color_select
    $canvas.set_band_colors(fs_colors)
    $canvas.set_band_failures(fs_failed)
    if fs_emit.size():
        if $btn_activate.pressed:
            $btn_activate.self_modulate = col_btn_act
        else:
            $btn_activate.self_modulate = Color.WHITE
    else:
        $btn_activate.self_modulate = Color.WHITE


func unsel_fs_all(need_btns_off: bool):
    fs_selected.clear()
    update_fs_colors()
    if need_btns_off:
        set_ecm_btns_state(true)


func set_ecm_btns_state(value: bool):
    var btns: Array = get_tree().get_nodes_in_group('группа-режим-помехи')
    for btn in btns:
        btn.set_pressed(false)
        set_btns_disabled(value, btn)


func on_fs_selected(ecm):
    var fs_index_arr: Array = []
    prd.get_fs_index(ecm, fs_index_arr)
    fs_selected.clear()
    if view_mode != MapViewMode.RTO: return
    for item in fs_index_arr:
        fs_selected[item] = null
    update_fs_colors()


func set_btns_disabled(value: bool, btn):
    var external_ctl = ProjectSettings.get_setting('application/config/Внешнее управление', false)
    if external_ctl:
        btn.set_pressed(false)
        btn.set_disabled(true)
    else:
        btn.set_disabled(value)


func on_interfer_prinuditelno(prenuditelno_sectors):
    for key in prenuditelno_sectors:
        var sectors: = []
        for sector in prenuditelno_sectors[key]:
            sectors.append(prd.get_fs_param(sector))
        signaller.emit_signal('interfer_init', key, sectors, interfer.POW_DEFAULT)
    update_fs_colors()
    var btns: = get_tree().get_nodes_in_group('группа-режим-помехи')
    for btn in btns:
        btn.set_pressed(false)
        set_btns_disabled(true, btn)


## Вызывается при получении информации о состоянии модулей ФС от КАПС РПБ.
func on_fs_update_state(fs_dict: Dictionary):
    for key in fs_dict.keys():
        fs_failed[key] = AntBandState.ANT_BAND_READY if fs_dict[key].ready else AntBandState.ANT_BAND_FAILED


func on_btn_center_toggled(toggled_on: bool) -> void:
    $btn_center.tooltip_text = 'Центрирует карту на текущие координаты (%s)' % ('включено' if toggled_on else 'отключено')
    signaller.emit_signal('map_centered', toggled_on)


func on_btn_activate_toggled(toggled_on: bool) -> void:
    $btn_activate.tooltip_text = 'Включает подавление (%s)' % ('включено' if toggled_on else 'отключено')
    signaller.emit_signal('emit_changed', toggled_on)
    if not toggled_on:
        $btn_activate.self_modulate = Color.WHITE


func on_update_coordinates_label(coordinates_label: String) -> void:
    $coordinates_map.text = coordinates_label


func on_update_scale_label(scale_label: String) -> void:
    $scale_map.text = scale_label


func on_btn_close():
    await get_tree().create_timer(0.2).timeout
    $btn_close.pressed = false
    fs_closed.merge(fs_selected)
    signaller.emit_signal('update_fs_closed', fs_closed)


func on_btn_work():
    await get_tree().create_timer(0.2).timeout
    $btn_work.pressed = false
    fs_closed.clear()
    for fs_index in prd.FS_PRD.keys():
        if fs_index in fs_selected: continue
        fs_closed[fs_index] = null
    signaller.emit_signal('update_fs_closed', fs_closed)


func _on_btn_all_work_pressed() -> void:
    fs_closed.clear()
    signaller.emit_signal('update_fs_closed', fs_closed)


func on_th_aoa_update(ths):
    count_threats(ths)


func count_threats(ths):
    var c0: int = ths.size() if ths.size() < 100 else 99
    $count_all_pad/count_all.text = '%02d' % c0
    var c: int = 0
    if gos_flag:
        c = ths.values().filter(func(th: threats.Threat): return th.proto != '').size()
    else:
        c = ths.values().filter(func(th: threats.Threat): return not th.gos).size()
    $count_danger_pad/count_danger.text = '%02d' % c
