extends Node

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


## Режимы помехи
const ITERFER_MODE = {
    'off': ['Откл', ['freq', 'width']],
    'auto': ['АВТО', ['freq', 'width']],
    'srni1': ['СРН-И1', ['freq', 'width']],
    'srnm2': ['СРН-М2', ['freq', 'width']],
    'lchm1': ['ЛЧМ-1',  ['freq', 'width']],
    'mchm1': ['МЧМ-1',  ['freq', 'width']],
    'pdm2':  ['ПД-М2',  ['freq', 'width']],
    'pdm4':  ['ПД-М4',  ['freq', 'width']],
    'pdm4s': ['ПД-М4С', ['freq', 'width']],
    'pdchm': ['ПД-ЧМ',  ['freq', 'width']],
    'svi1':  ['СВ-И1',  ['freq', 'width']],
    'svm2':  ['СВ-М2',  ['freq', 'width']],
    'k1':    ['K1',     ['freq', 'width', 'dur', 'period']],
    'ozp1':  ['ОЗП-1',  ['freq', 'width']] }

const ID_INTERFERS_LEN = 63    ## Размер пула номеров целей
const INTERFER_OFF = 'off'
const STATE_TSMT = 5           ## Значение svk для цели, когда ответ ещё не получен
var msg_ss: int = 0            ## счётчик сообщений
var id_array: Array            ## Массив id воздействий
var thrs: Dictionary           ## Словарь воздействия для целей, ключ - id воздействия


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

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

    func get_msg6_data():
        var data_to_json : Dictionary = {}
        data_to_json['ts'] = 6
        data_to_json['ss'] = ss
        data_to_json['ispp'] = ispp
        data_to_json['krp'] = krp
        if krp != INTERFER_OFF:
            data_to_json['kni'] = kni
            data_to_json['powp'] = powp            # Необходимо добавить управление мощностью
            data_to_json['get'] = []
            data_to_json['params'] = params
        var json = JSON.stringify(data_to_json)
        var pac = 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)          ## Вызывается при изменении количества сеансов помех.


func _ready():
    var ecms: Dictionary = {}      ## Словарь помех
    for i in range(ID_INTERFERS_LEN):               # Заполняет массив ID целей
        id_array.append(i + 1)
    var unit_key = repsettings.get_unit_key('уарэп-капсрпб-отп')
    var unit = repnetwork.units[unit_key]
    var timer_check_state: = Timer.new()
    add_child(timer_check_state)
    var resend_timeout = ProjectSettings.get_setting('application/interfer/resend_timeout', 1000.0)
    timer_check_state.connect('timeout', Callable(self, 'on_timer_check_state').bind(unit, ecms, resend_timeout))
    timer_check_state.start(resend_timeout / 1000.0)
    unit.connect('data_received', Callable(self, 'on_data_capsrpb_received').bind(ecms))
    signaller.connect('interfer_create', Callable(self, 'on_interfer_create').bind(unit, ecms))
    signaller.connect('interfer_new', Callable(self, 'send_ecm').bind(unit))
    signaller.connect('interfer_off_all', Callable(self, 'on_interfer_off_all').bind(unit, ecms))

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


## Производит приём состояния помех. [param unit] -> [param ecms]
func on_data_capsrpb_received(unit: capsrpb.CapsRpb, ecms: Dictionary):
    if not unit.json_dic.has('ts'):                  return
    if not (unit.json_dic['ts'] is float):           return
    if unit.json_dic['ts'] != 5:                     return
    if not unit.json_dic.has('msvk'):                return
    if not (unit.json_dic['msvk'] is Array): return
    var msvk = unit.json_dic['msvk']
    var sz: = ecms.size()
    for dic_msvk in msvk:
        if not (dic_msvk is Dictionary): continue
        if dic_msvk.has('ispp'):
            var ispp = int(dic_msvk['ispp'])
            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)
    if sz != ecms.size():
        call_deferred('emit_signal', 'interfer_resized', ecms)


## Вызыватся, когда пользователь выбрал помеху и выбраны цели
func on_interfer_create(btn, sel_threats, unit, ecms):
    for item in sel_threats:
        var ispp: int = 0
        var interfer_name: String = btn.get_meta('rfi_name')
        var param: Dictionary = {}
        var kni: float = item.aoa
        param['freq'] = item.freq
        param['width'] = item.width
        if interfer_name == 'k1':
            param['dur'] = 1.0      # Необходимо добавить параметры управления
            param['period'] = 1.0   # Необходимо добавить параметры управления
        var key = thrs.find_key(item.id)
        if key != null:
            ispp = key
        else:
            if interfer_name == 'off':
                return
            ispp = pop_id()
        if ispp == 0: return
        msg_ss += 1
        var ecm: Interfer
        if ecms.has(ispp):
            ecm = ecms[ispp]
        else:
            ecm = Interfer.new()
            ecm.ispp = ispp
            ecms[ispp] = ecm
        ecm.svk = STATE_TSMT         # Подготовка к передаче сообщения
        ecm.ss = msg_ss
        ecm.kni = kni
        ecm.krp = interfer_name
        ecm.params = param
        ecm.powp = 100.0            # Необходимо добавить управление мощностью
        thrs[ispp] = item.id
        signaller.emit_signal('interfer_new', ecm)
        if interfer_name == 'off':
            signaller.emit_signal('interfer_off', ecm, ecms, thrs)
            push_id(ecm.ispp)
            thrs.erase(ispp)
        ecm.tick_tx = Time.get_ticks_msec()


func send_ecm(ecm, unit):
    var json_data = ecm.get_msg6_data()
    unit.tx_stack.append(json_data)


func on_interfer_off_all(unit, ecms):
    for ecm in ecms.values():
        ecm.krp = INTERFER_OFF
        push_id(ecm.ispp)
        send_ecm(ecm, unit)
        signaller.emit_signal('interfer_off',ecm, ecms, thrs)


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


func push_id(id : int):
    id_array.append(id)
    id_array.sort()
