extends Node

## Реализация "Протокол информационного сопряжения
## СПО АСУ изделия «МП‑550» с СПО «Управления КАПС РПБ»"


const ONLINE_TIMEOUT = 3000  ## Время ожидания пакета от КАПС РПБ, мс
const BUFFER_SIZE    = 2048  ## Размер приёмного буфера для датаграмм


class CapsRpb:
    signal line_changed(unit:  CapsRpb)               ## Сигнал состояние связи изменилось
    signal data_received(unit: CapsRpb)               ## Сигнал данные приняты
    signal command_fail(unit:  CapsRpb)               ## Сигнал при не выполнении команды
    signal parse_error(unit:   CapsRpb, msg: String)  ## Сигнал ошибки разбора сообщения

    static var json_conv: = JSON.new()
    var online: = false                ## Состояние связи с источником сообщений
    var name: String                   ## Имя экземпляра
    var json_dic: Dictionary           ## Аппарат для разбора сообщений
    var tick: = 0                      ## Тик время последнего обновления, мс
    var tx_data: = PackedByteArray()   ## Пакет для отправки
    var tx_stack: Array               ## Массив пакетов для отправки

    func _to_string() -> String: return String('капсрпб: "%s" %s ' % [self.name, ['отключен', 'на связи'][int(online)]])
    func _init(nm): self.name = nm

    func parse(data: PackedByteArray, now_tick: int):
        tick = now_tick
        if not online:
            online = true
            emit_signal('line_changed', self)
        var utf8_data = data.get_string_from_utf8()
        if Error.OK == json_conv.parse(utf8_data):
            json_dic.merge(json_conv.get_data(), true)
            emit_signal('data_received', self)
        else:
            var msg = json_conv.get_error_message()
            emit_signal('parse_error', self, msg)

    func process(now_tick: int):
        if online and ((now_tick - tick) > ONLINE_TIMEOUT):
            online = false
            emit_signal('line_changed', self)
        if len(tx_stack):
            tx_data = tx_stack[0]
            tx_stack.remove_at(0)
            return Error.OK
        else:
            return Error.ERR_UNAVAILABLE
