class_name Iterfer extends Node

## Представление помехи.

## Режимы помехи.
const ITERFER_MODE = {
    INTERFER_OFF: [INTERFER_OFF, {}, 0],
    'srni1': [INTERFER_IQFILE, SRNI1_PARAMS, 1],
    'srnm2': ['Линейная ЧМ', SRNM2_PARAMS, 2],
    'srngps': [INTERFER_IQFILE, SRNGPS_PARAMS, 3],
    'lchm1': ['Линейная ЧМ', LCHM1_PARAMS, 10],
    'lchm2': ['Линейная ЧМ', LCHM2_PARAMS, 16],
    'mchm1': [INTERFER_IQFILE, MCHM1_PARAMS, 11],
    'pdm2':  [INTERFER_IQFILE, PDM2_PARAMS, 12],
    'pdm4':  [INTERFER_IQFILE, PDM4_PARAMS, 13],
    'pdm4s': [INTERFER_IQFILE, PDM4S_PARAMS, 14],
    'pdchm': [INTERFER_IQFILE,  PDCHM_PARAMS, 15],
    'svi1':  [INTERFER_IQFILE,  SVI1_PARAMS, 20],
    'svm2':  [INTERFER_IQFILE,  SVM2_PARAMS, 21],
    'k1':    [INTERFER_IQFILE,  K1_PARAMS, 50],
    'ozp1':  [INTERFER_IQFILE,  OZP1_PARAMS, 51] }

const RECOMMEND_INTERFER = {
    'ПСП + ФМ-2': 'srni1',
    'Линейная ЧМ': 'lchm1'
}

const SRNI1_PARAMS = {'files': {3: ['SRNI1_LIT4.pcm', 1220],
                                4: ['SRNI1_LIT5.pcm', 1555]},
                    'call_proc': 'call_diap',
                    'par_names' : ['freq', 'filename']}
const SRNM2_PARAMS = {'par_names' : ['freq', 'width', 'period']}
const SRNGPS_PARAMS = {'par_names' : ['freq', 'filename'],
                    'files': 'SRNGPS.pcm',
                    'call_proc': 'call_all_diap'}
const LCHM1_PARAMS = {'par_names' : ['freq', 'width', 'period']}
const LCHM2_PARAMS = {'par_names' : ['freq', 'width', 'period']}
const MCHM1_PARAMS = {'par_names' : ['freq', 'filename'],
                    'files': 'MCHM1.pcm',
                    'call_proc': 'call_all_diap'}
const PDM2_PARAMS = {'par_names' : ['freq', 'filename'],
                    'files': 'PDM2_20.pcm',
                    'call_proc': 'call_all_diap'}
const PDM4_PARAMS = {'par_names' : ['freq', 'filename'],
                    'files': 'PDM4_20.pcm',
                    'call_proc': 'call_all_diap'}
const PDM4S_PARAMS = {'par_names' : ['freq', 'filename'],
                    'files': 'PDM4S_5.pcm',
                    'call_proc': 'call_all_diap'}
const K1_PARAMS = {'files' : 'K1.pcm',
                    'call_proc' : 'call_all_diap',
                    'par_names' : ['freq', 'filename']}
const OZP1_PARAMS = {'files': 'OZP1.pcm',
                    'call_proc': 'call_all_diap',
                    'par_names' : ['freq', 'filename']}
# Файл : Диапазон: ['имя файла', частота]
const SVI1_PARAMS = {'files': {1: ['SVI1_LIT2.pcm', 1017],
                               2: ['SVI1_LIT3.pcm', 1156]},
                    'call_proc': 'call_diap',
                    'par_names' : ['freq', 'filename']}
const SVM2_PARAMS = {'files': {1: ['SVM2_LIT2.pcm', 1017],
                               2: ['SVM2_LIT3.pcm', 1156]},
                    'call_proc': 'call_diap',
                    'par_names' : ['freq', 'filename']}

# Файл : Ключ (ширина): ['имя файла']
const PDCHM_PARAMS = {'files': {
                5 : 'pdchm_5.pcm',
                10: 'pdchm__0.pcm',
                20: 'pdchm_20.pcm',
                40: 'pdchm_40.pcm' },
                'call_proc': 'call_pdchm',
                'par_names' : ['freq', 'filename'],}

const SOURCE_INTERFER = ['th','fs','cu']
const EXCLUDE_INTERFER = ['srni1', 'srnm2', 'srngps', 'svi1', 'svm2']
const ID_INTERFERS_LEN = 63    ## Размер пула номеров целей.
const INTERFER_OFF = 'off'
const INTERFER_IQFILE = 'IQ-файл'
const POW_DEFAULT: float = 50.0
var msg6_num: int = 0          ## Счётчик сообщений "тип 6"
var msg8_num: int = 0          ## Счётчик сообщений "тип 8"
var id_array: Array            ## Массив id воздействий.
var thrs: Dictionary           ## Словарь воздействия для целей, ключ - id воздействия.
var fs: Dictionary             ## Словарь воздействий для секторов, ключ - id воздействия.
var cu: Dictionary             ## Словарь воздействий для 5П-28, ключ - id воздействия.
var thrs_dict: Dictionary      ## Ссылка на словарь целей
var auto_enabled: bool = false ## Режим автомата
var emit_enable: bool = true   ## Разрешить излучение

## Сеанс помехи.
class Interfer:
    var ispp: int = 0                   ## Индекс сеанса.
    var svk: = 0                        ## Состояние сеанса. Ответ КАПСРПБ. Возможные значения в [param ITERFER_STATE].
    var krp: String = ''                ## Тип помехи. Возможные значения в [param INTERFER_MODE].
    var powp: float = 100.0             ## Мощность излучения выраженная в процентах.
    var kni: = 0.0                      ## Курсовой угол направления излучения.
    var params: = {}                    ## Параметры помехи.
    var get_params: Array[String]       ## Запрос массива параметров (список запрошенных параметров).
    var retss: int                      ## Значение счётчика сообщения в котором был произведён запрос массива параметров.
    var tick_tx: int                    ## Тик время обновления цели, мс.
    var source_interfer: String = ''    ## Тип объекта по которой поставлена помеха.
    var modulation: bool                ## Модуляция для включения усилителей
    var um: float                       ## Угол места для помехи.
    var nmfs: int = 0                   ## Номер модуля ФС в нумерации СТЦ

    func _to_string() -> String:
        return 'номер: %d название: %s частота: %0.1f МГц пеленг: %0.1f гр.' % [ispp, ITERFER_MODE[krp][0], params['freq'], kni]

    func get_msg6_data(msg_num: int) -> PackedByteArray:
        var data_to_json : Dictionary = {}
        data_to_json['ts'] = 6
        data_to_json['ss'] = msg_num
        data_to_json['ispp'] = ispp
        data_to_json['krp'] = ITERFER_MODE[krp][0]
        data_to_json['nmfs'] = nmfs
        if krp != INTERFER_OFF:
            data_to_json['kni'] = kni
            data_to_json['powp'] = powp
            data_to_json['params'] = {}
            for key in ITERFER_MODE[krp][1]['par_names']:
                if params.has(key):
                    data_to_json['params'][key] = params[key]
            data_to_json['get'] = get_params
        var pac = JSON.stringify(data_to_json).to_utf8_buffer()
        return pac

    func set_from_dic(dic: Dictionary):
        var names: = tools.get_members_names(self)
        names.any(func(vn): if dic.has(vn): set(vn, dic[vn]); return false)

    func get_value(value_key):
        var param = self.get(value_key)
        if param == null:
            if params.has(value_key): param = params[value_key]
        return param

    func set_value(value, value_key):
        var param = self.get(value_key)
        if param == null:
            params[value_key] = value
        else:
            self.set(value_key, value)

signal interfer_preparing(ecm: Interfer)           ## Вызывается в момент запуска помехи.
signal interfer_run(ecm: Interfer)                 ## Вызывается в момент начала работы помехи.
signal interfer_error(ecm: Interfer, msg: String)  ## Вызывается при ошибке.
signal interfer_update(ecm: Interfer)              ## Вызывается при обновлении помехи.
signal interfer_resized(ecms: Dictionary)          ## Вызывается при изменении количества сеансов помех.
signal interfer_recommendate(ecm: Interfer)        ## Вызывается когда назначается рекомендуемая для цели помеха


## Отправляет словарь помех в юнит, для запаковки и отправки в 5П28.
func on_get_interfers(unit, ecms) -> void: unit.pack_interfers(cu, ecms)


## Автомат выключен
func on_manual_control() -> void: auto_enabled = false


## Автомат отключен
func on_full_auto() -> void: auto_enabled = true


func _ready() -> void:
    for i in ID_INTERFERS_LEN:               # Заполняет массив ID целей
        id_array.append(i + 1)
    var unit_caps = network.get_unit_instance('уарэп-капсрпб')
    var unit_5p28 = network.get_unit_instance('уарэп-5п28')
    var timer_check_state: = Timer.new()
    add_child(timer_check_state)
    var resend_timeout = ProjectSettings.get_setting('application/interfer/resend_timeout', 1000.0)
    var ecms: Dictionary = {}  ## Словарь помех.
    var seczaps: Dictionary = {}  ## Словарь секторов запрета
    timer_check_state.connect('timeout', Callable(self, 'on_timer_check_state').bind(unit_caps, ecms, resend_timeout))
    timer_check_state.start(resend_timeout / 1000.0)
    unit_caps.connect('data_received', Callable(self, 'on_data_capsrpb_received').bind(ecms, seczaps))
    unit_5p28.connect('get_interfers', Callable(self, 'on_get_interfers').bind(unit_5p28, ecms))
    signaller.connect('interfer_create', Callable(self, 'on_interfer_create').bind(unit_caps, ecms))
    signaller.connect('interfer_rcv', Callable(self, 'on_interfer_rcv').bind(unit_5p28, ecms))
    signaller.connect('interfer_new', Callable(self, 'send_ecm').bind(unit_caps))
    signaller.connect('interfer_off_all', Callable(self, 'on_interfer_off_all').bind(unit_caps, ecms))
    signaller.connect('th_aoa_update', Callable(self, 'on_th_aoa_update').bind(ecms, unit_caps))
    signaller.connect('interfer_off', Callable(self, 'on_interfer_off'))
    signaller.connect('manual_control', Callable(self, 'on_manual_control'))
    signaller.connect('full_auto', Callable(self, 'on_full_auto'))
    signaller.connect('interfer_prinuditelno', Callable(self, 'on_interfer_prinuditelno'))
    signaller.connect('emit_changed', Callable(self, 'on_emit_changed').bind(ecms))
    threats.connect('threat_lost', Callable(self, 'on_threats_lost').bind(ecms, unit_caps))
    threats.connect('threats_resized', Callable(self, 'on_threats_resized'))
    threats.connect('threat_update', Callable(self, 'on_threats_update').bind(ecms, unit_caps))
    var unit_nav = network.get_unit_instance('навигация')
    unit_nav.connect('data_received', on_nav_data_received.bind(unit_caps))


func on_nav_data_received(coords: Dictionary, unit_caps):
    var ship_time = Time.get_datetime_dict_from_system()
    var data_to_json = {
        'ts': 8,
        'ss': msg8_num,
        'roll': coords.get('bk', 0),
        'trim': coords.get('kk', 0),
        'long': coords.get('longitude', 0),
        'lat': coords.get('latitude', 0),
        'course': coords.get('k', 0),
        'speed': coords.get('speed', 0),
        'year': ship_time['year'],
        'month': ship_time['month'],
        'day': ship_time['day'],
        'hour': ship_time['hour'],
        'minute': ship_time['minute'],
        'second': ship_time['second'],}
    var json_data = JSON.stringify(data_to_json).to_utf8_buffer()
    unit_caps.tx_stack.append(json_data)
    msg8_num += 1
    msg8_num %= 0xffffffff


## Проверяет состояние отправки пакета и если не доставлен, повторяет отправку.
func on_timer_check_state(unit_instance, ecms, resend_timeout) -> void:
    var tick = Time.get_ticks_msec()
    for ecm in ecms.values():
        if (tick - ecm.tick_tx) >= resend_timeout:
            send_ecm(ecm, unit_instance)
            ecm.tick_tx = tick


func on_th_aoa_update(threats: Dictionary, ecms: Dictionary, unit_instance) -> void:
    for thr in threats.values():
        var th_id = thr.id
        for ecm_i in thrs.keys():
            if thrs[ecm_i] == th_id:
                var ecm = ecms[ecm_i]
                ecm.params['freq'] = thr.freq
                ecm.kni = thr.aoa
                send_ecm(ecm, unit_instance)
    signaller.emit_signal('fs_update_color', ecms)
    prd.update_fs_state(ecms)

    if not auto_enabled:
        return

    if auto_enabled:
        for thr in threats.values():
            thr.auto_selected = true
            signaller.emit_signal('interfer_init', 'lchm1', [], interfer.POW_DEFAULT)
            thr.auto_selected = false


## Производит приём состояния помех. [param unit] -> [param ecms].
func on_data_capsrpb_received(unit_instance: capsrpb.CapsRpb, ecms: Dictionary, seczaps: Dictionary) -> void:
    if not unit_instance.json_dic.has('ts'): return
    if not tools.type_is_num(unit_instance.json_dic['ts']): return
    if unit_instance.json_dic['ts'] != 5:    return
    map_msvk_to_ecms(unit_instance, ecms)
    map_mpchf_to_seczaps(unit_instance, seczaps)


## Извлекает массив состояний выполнения команды
func map_msvk_to_ecms(unit_instance: unit.Unit, ecms: Dictionary):
    var json_dic = unit_instance.json_dic
    if not json_dic.has('msvk'): return
    var msvk = unit_instance.json_dic.get('msvk', [])
    for dic_msvk in msvk:
        if dic_msvk is not Dictionary: continue
        if not dic_msvk.has('ispp'): continue
        var ispp = int(dic_msvk['ispp'])
        var errmsg = dic_msvk.get('errmsg', '')
        if errmsg:
            log.error('сеанс %d: \"%s\"' % [ispp, errmsg])
        if ecms.has(ispp):
            var ecm = ecms[ispp]
            ecm.set_from_dic(dic_msvk)
            call_deferred('emit_signal', 'interfer_update', ecm)
        else:
            var ecm = Interfer.new()
            ecm.set_from_dic(dic_msvk)
            ecm.krp = INTERFER_OFF
            send_ecm(ecm, unit_instance)


## Извлекает массив пространственно-частотных фильтров
func map_mpchf_to_seczaps(unit_instance: unit.Unit, seczaps: Dictionary):
    var json_dic: = unit_instance.json_dic as Dictionary
    var mpchf = json_dic.get('mpchf', [])
    if mpchf is not Array: return
    for item in mpchf:
        if item is not Dictionary: continue
        var id = item.get('index', -1)
        if id < 0: continue
        var freq = item.get('freq', 0)
        if freq == 0: continue


## Вызыватся, когда пользователь выбрал помеху и выбраны цели.
func on_interfer_create(interfer_name, sel_threats, fs_arr, power, u, ecms) -> void:
    for item in sel_threats:
        var param: Dictionary = {}
        var kni: float = item.aoa
        var id = item.id
        param['freq'] = item.freq
        param['width'] = item.width
        if (item.rkrp != '') and item.fflags.rkrp:
            var krp = get_krp(item)
            if krp != '':
                interfer_name = krp
                set_rparams(item, param)
        if (param['width'] < settings.WIDTH_MIN):
            param['width'] = settings.WIDTH_MIN
        elif (param['width'] > settings.WIDTH_MAX):
            param['width'] = settings.WIDTH_MAX
        interfer_create(u, interfer_name, ecms, param, kni, id, thrs, SOURCE_INTERFER[0], power)

    for item in fs_arr:
        var param: Dictionary = {}
        var kni: float = item[0]
        var id = item[3]
        var th = null
        if not interfer_name in EXCLUDE_INTERFER:
            th = find_threat(item[1], kni)
        if th != null:
            param['freq'] = th.freq
            param['width'] = th.width
            if (th.rkrp != '') and th.fflags.rkrp:
                var krp = get_krp(th)
                if krp != '':
                    interfer_name = krp
                    set_rparams(th, param)
        else:
            param['freq'] = item[1]
            param['width'] = item[2]
        if (param['width'] < settings.WIDTH_MIN):
            param['width'] = settings.WIDTH_MIN
        elif (param['width'] > settings.WIDTH_MAX):
            param['width'] = settings.WIDTH_MAX
        if th == null:
            interfer_create(u, interfer_name, ecms, param, kni, id, fs, SOURCE_INTERFER[1], power)
        else:
            id = th.id
            interfer_create(u, interfer_name, ecms, param, kni, id, thrs, SOURCE_INTERFER[0], power)

func on_interfer_rcv(interfer_params: Array, unit0, ecms) -> void:
        var err: bool = false
        var mode = interfer_params[0]
        var id = interfer_params[1]
        var aoa = interfer_params[2]
        var um = interfer_params[3]
        if (aoa < 0.0) and (aoa > 360.0):
            err = true
        var param: Dictionary = {}
        if (um < -settings.UM_MIN) and (um > settings.UM_MAX):
            err = true
        param['um'] = um
        param['freq'] = interfer_params[4]
        if (param['freq'] < settings.FREQ_MIN) and (param['freq'] > settings.FREQ_MAX):
            err = true
        param['width'] = interfer_params[5]
        if (param['width'] < settings.WIDTH_MIN) and (param['width'] > settings.WIDTH_MAX):
            err = true
        var interfer_name: = ''
        for key in ITERFER_MODE:
            if ITERFER_MODE[key][2] == mode:
                interfer_name = key
                break
        if interfer_name == '':
            err = true
        if not err:
            interfer_create(unit0, interfer_name, ecms, param, aoa, id, cu, SOURCE_INTERFER[2], POW_DEFAULT)
        unit0.on_interfer_accept(err)


func interfer_create(u, interfer_name, ecms, param, kni, id, dict, source_interfer, power) -> void:
    var sz = ecms.size()
    var ispp: int = 0
    param['dur'] = 1.0      # Необходимо добавить параметры управления
    param['period'] = 1.0   # Необходимо добавить параметры управления
    var key = dict.find_key(id)
    if source_interfer != SOURCE_INTERFER[2]:
        if key != null:
            ispp = key
        else:
            if interfer_name == 'off':
                return
            ispp = pop_id()
        if ispp == 0:
            return
    else:
        ispp = id
    dict[ispp] = id
    var ecm: Interfer
    if ecms.has(ispp):
        ecm = ecms[ispp]
    else:
        ecm = Interfer.new()
        ecm.ispp = ispp
        ecms[ispp] = ecm
    ecm.kni = kni
    ecm.krp = interfer_name
    ecm.params = param
    ecm.powp = power
    ecm.source_interfer = source_interfer
    ecm.modulation = emit_enable
    ecm.um = param.get('um', 15.0)                               # Значение по умолчанию
    var ecm_params = ITERFER_MODE[interfer_name][1]
    if ecm_params.has('call_proc'):
        var call_set_params = Callable(self, ecm_params['call_proc']).bind(ecm, ecm_params)
        call_set_params.call()
    var set_nmfs_ok = set_nmfs(ecm)
    if set_nmfs_ok != Error.OK:
        log.error('Ошибка выбора модуля ФС для помехи: %s' %[ecm.ispp])
    signaller.emit_signal('interfer_new', ecm)
    if interfer_name == 'off':
        signaller.emit_signal('interfer_off', ecm, ecms, thrs)
        thrs.erase(ispp)
    ecm.tick_tx = Time.get_ticks_msec()
    send_ecm(ecm, u)
    if sz != ecms.size():
        call_deferred('emit_signal', 'interfer_resized', ecms)


func send_ecm(ecm, unit0) -> void:
    if ecm.krp != INTERFER_OFF:
        if not emit_enable:
            return
    msg6_num += 1
    var json_data = ecm.get_msg6_data(msg6_num)
    unit0.tx_stack.append(json_data)


func on_interfer_off_all(unit0, ecms: Dictionary) -> void:
        for ecm in ecms.values():
            ecm.krp = INTERFER_OFF
            send_ecm(ecm, unit0)
            signaller.emit_signal('interfer_off', ecm, ecms, thrs)


func on_threats_lost(th, ecms, unit0) -> void:
    for key in interfer.thrs:
        if interfer.thrs[key] == th.id:
            var ecm_id = key
            var ecm = ecms[ecm_id]
            ecm.krp = INTERFER_OFF
            send_ecm(ecm, unit0)
            signaller.emit_signal('interfer_off', ecm, ecms, thrs)


func pop_id() -> int:
    var id = 0
    if len(id_array):
        id =  id_array[0]
        id_array.remove_at(0)
    return id


func push_id(id: int) -> void:
    id_array.append(id)
    id_array.sort()


func on_emit_changed(state, _ecms) -> void:
    emit_enable = state


func call_all_diap(ecm, ecm_params: Dictionary):
    ecm.params['filename'] = ecm_params['files']


func call_diap(ecm, ecm_params: Dictionary):
    var fs_index_arr: Array
    prd.get_fs_index(ecm, fs_index_arr)
    if len(fs_index_arr):
        var band = fs_index_arr[0] / 4
        if ecm_params['files'].has(band):
            ecm.params['filename'] = ecm_params['files'][band][0]
            ecm.params['freq'] = ecm_params['files'][band][1]


func call_pdchm(ecm, ecm_params: Dictionary):
    var temp_key: float = settings.WIDTH_MIN
    for key in ecm_params['files'].keys():
        if key > temp_key: temp_key = key
    for key in ecm_params['files'].keys():
        if key < ecm.params['width']: continue
        if key < temp_key:
            temp_key = key
    ecm.params['filename'] = ecm_params['files'][int(temp_key)]


func set_nmfs(ecm):
    var fs_index_arr: Array
    prd.get_fs_index(ecm, fs_index_arr)
    if len(fs_index_arr):
        ecm.nmfs = prd.FS_PRD[fs_index_arr[0]][1]
        return Error.OK
    else:
        return Error.FAILED


func on_threats_resized(th_dic):
    thrs_dict = th_dic


func on_threats_update(threat, ecms, unit_caps):
    var th_id = threat.id
    var ecm = null
    for ecm_i in thrs.keys():
        if thrs[ecm_i] == th_id:
            ecm = ecms[ecm_i]
            ecm.params['freq'] = threat.freq
            ecm.params['width'] = threat.width
            if (threat.rkrp != '') and threat.fflags.rkrp:
                var krp = get_krp(threat)
                if krp != '':
                    ecm.krp = krp
                    set_rparams(threat, ecm.params)
                    emit_signal('interfer_recommendate', ecm)
            ecm.kni = threat.aoa
            set_nmfs(ecm)
    if threat.tmod != 'fm':
        if ecm != null:
            send_ecm(ecm, unit_caps)
        return
    var th_fm_dict: Dictionary
    var fs_index_arr: Array
    prd.find_fs_index(threat.aoa, threat.freq, fs_index_arr)
    if fs_index_arr.size() == 0:
        if ecm != null:
            send_ecm(ecm, unit_caps)
        return
    var fs_index = fs_index_arr[0]
    var nmfs = prd.FS_PRD[fs_index][1]
    if ecm == null:
        for ecm_i in ecms.values():
            if nmfs != ecm_i.nmfs: continue
            if ecm_i.svk != 1: continue
            ecm = ecm_i
    if ecm == null: return

    for th_index in thrs_dict:
        if thrs_dict[th_index].tmod != 'fm': continue
        fs_index_arr = []
        prd.find_fs_index(thrs_dict[th_index].aoa, thrs_dict[th_index].freq, fs_index_arr)
        if fs_index_arr.size() == 0: continue
        if fs_index_arr[0] != fs_index: continue
        th_fm_dict[th_index] = thrs_dict[th_index]
    if len(th_fm_dict) > 1:
        pass
    send_ecm(ecm, unit_caps)


func get_freq_range(freq_range_dict: Dictionary, th_dict: Dictionary):
    for key_i in th_dict:
        var min_range: int = 6000
        var key_min = null
        for key_j in th_dict:
            if key_i == key_j: continue
            var width = (th_dict[key_i].width / 2) + (th_dict[key_j].width / 2)
            var freq_range = abs(th_dict[key_i].freq - th_dict[key_j].freq) + width
            if freq_range < min_range:
                key_min = key_j
                min_range = freq_range
        var max_width = 0
        for key in PDCHM_PARAMS['files'].keys():
            if max_width < key: max_width = key
        if min_range > max_width:
            th_dict.erase(key_i)
            continue
        else:
            if key_min == null: continue
            freq_range_dict[key_i] = [th_dict[key_i], th_dict[key_min], min_range]


func find_threat(freq: int, aoa: float):
    var fs_index_arr = []
    prd.find_fs_index(aoa, freq, fs_index_arr)
    if not fs_index_arr.size(): return null
    var fs_index = fs_index_arr[0]
    for th in thrs_dict.values():
        fs_index_arr = []
        prd.find_fs_index(th.aoa, th.freq, fs_index_arr)
        if not fs_index_arr.size(): continue
        if fs_index_arr[0] == fs_index:
            return th
    return null


func set_rparams(threat: threats.Threat, params: Dictionary):
    if threat.rparams.has('freq'):
        params['freq'] = threat.rparams['freq']
    else:
        params['freq'] = threat.freq
    if threat.rparams.has('period'):
        params['period'] = threat.rparams['period']
    if threat.rparams.has('width'):
        params['width'] = threat.rparams['width']
    else:
        params['width'] = threat.width
    if threat.rparams.has('filename'):
        params['filename'] = threat.rparams['filename']


func get_krp(threat: threats.Threat):
    var krp = ''
    if RECOMMEND_INTERFER.has(threat.rkrp):
        krp = RECOMMEND_INTERFER[threat.rkrp]
        return krp
    elif threat.rkrp == INTERFER_IQFILE:
        if not threat.rparams.has('filename'): return krp
        for key in ITERFER_MODE.keys():
            var ecm_params = ITERFER_MODE[key][1]
            if not ecm_params.has('files'): continue
            if ecm_params['files'] == threat.rparams['filename']:
                krp = key
                return krp
    return krp
