extends Node

# ЯУ-07 Блок
var unit = Yau07.YaU07.new('ЯУ-07Б')
var soc_unicast: Socket
var soc_brodcast: Socket
var ip_address_yau: String = Constants.ADDRESSES[0][1]
var ip_port_yau: int = Constants.ADDRESSES[0][2]
var timeout: float = 10.0
var last_update_time_yau07: float = 0.0
var last_update_time_fs: float = 0.0
var broadcast_packet: PackedByteArray
var state = Constants.STATE.WAIT
var send_array: Array = []

# ФС Блок
const ClientFs = preload("res://scripts/FS.gd")
var unit_fs_1: Node = ClientFs.ClientFs.new('FS1')
var unit_fs_2: Node = ClientFs.ClientFs.new('FS2')
var unit_fs_3: Node = ClientFs.ClientFs.new('FS3')


# Яу-07Б
signal yau_status_line(status, addr)  ## Вызывается когда меняется состояние связи с ячейкой
signal yau_receive(data_from_yau)
signal yau_feedback_receive(data_from_yau)
signal yau_read_isa(unit_isa_ports)
# ФС модуль
signal data_from_fs_1(data:PackedByteArray)
signal data_from_fs_2(data:PackedByteArray)
signal data_from_fs_3(data:PackedByteArray)
signal port_fs_opened(port_name: String)
signal port_fs_closed(port_name: String)
signal port_error(error_str: String)


## Класс для отправки данных в сокет
class Socket extends PacketPeerUDP:
    func send_to(addr: String, port: int, data: PackedByteArray):
        self.set_dest_address(addr, port)
        self.put_packet(data)


func poll_receive_yau07(sock: Socket) -> bool:  ## Приёмник
    if timeout - last_update_time_yau07 > 0:
        while sock.get_available_packet_count() > 0:
            broadcast_packet = sock.get_packet()
            var addr_receive = sock.get_packet_ip()
            var port_receive = sock.get_packet_port()
            if (ip_address_yau == addr_receive) and (ip_port_yau == port_receive):
                last_update_time_yau07 = 0.0
                unit.parse(broadcast_packet)
                var data_from_yau_07 = unit.status
                emit_signal('yau_receive', data_from_yau_07)
                if  sock == soc_unicast:
                    emit_signal('yau_feedback_receive', data_from_yau_07)
            emit_signal('yau_status_line', addr_receive)
    else:
        if sock.get_available_packet_count():
            last_update_time_yau07 = 0.0
        else:
            emit_signal('yau_status_line', '')
    return false


func _ready() -> void:
    # Привязка для принятия широковещательного канала
    soc_brodcast = Socket.new()
    var rc = soc_brodcast.bind(Constants.BROADCAST_PORT, '*')
    if rc != OK:
        print_debug('Ошибка: Неудачная привязка широковещательного адреса')

    soc_unicast = Socket.new()
    rc = soc_unicast.bind(Constants.UNICAST_PORT, Constants.UNICAST_ADDRESS)
    if rc != OK:
        print_debug('Ошибка: неудачная привязка адреса: ', Constants.UNICAST_ADDRESS)

    unit.connect('line_changed', Callable(self, '_on_connect_change'))
    add_child(unit_fs_1)
    add_child(unit_fs_2)
    ## Настройка при старте программы
    set_config()


func set_config():
    write_port_isa(Constants.BASE_PORTS.EMS_G+2, Constants.META.CI_2_B_UF)
    read_port_isa([Constants.BASE_PORTS.EMS_G+8])
    write_port_isa(Constants.BASE_PORTS.EMS_G+2, Constants.META.CI_3_B_UF)
    read_port_isa([Constants.BASE_PORTS.EMS_G+8])
    write_port_isa(Constants.BASE_PORTS.EMS_G+2, Constants.META.MODUL_UM_2)
    read_port_isa([Constants.BASE_PORTS.EMS_G+8])
    write_port_isa(Constants.BASE_PORTS.EMS_G+2, Constants.META.MODUL_UM_3)
    read_port_isa([Constants.BASE_PORTS.EMS_G+8])
    write_port_isa(Constants.BASE_PORTS.EMS_G+2, Constants.META.FGOZ_3)
    read_port_isa([Constants.BASE_PORTS.EMS_G+8, Constants.BASE_PORTS.UG+6, Constants.BASE_PORTS.UG+8])


func _process(delta: float) -> void:
    last_update_time_yau07 += delta
    last_update_time_fs += delta

    poll_receive_yau07(soc_brodcast)
    poll_receive_yau07(soc_unicast)

    state_machine_yau07()

    match unit.process(delta):
        Error.OK: soc_unicast.send_to(ip_address_yau, ip_port_yau, unit.tx_data.slice(0, unit.tx_len))
        #Error.FAILED: print_debug('Ошибка отправки данных')


func state_machine_yau07():
    var fl_done = (unit.cmd_state == unit.CmdState.DONE or unit.cmd_state == unit.CmdState.FAIL)
    ## Режим ожидания
    match  state:
        Constants.STATE.WAIT:
            if fl_done and send_array.size():
                    state =  Constants.STATE.READ_ISA if send_array[0][0] == 'rd' else Constants.STATE.WRITE_ISA
        ## Режим чтения из ИСА
        Constants.STATE.READ_ISA:
            if fl_done:
                var ports_read = send_array.pop_front()
                unit.send_isa(unit.CmdCode.READ_ISA, ports_read[1])
                state = Constants.STATE.DONE
        ## Режим записи в ИСА
        Constants.STATE.WRITE_ISA:
            if fl_done:
                var ports_write: Array = send_array.pop_front()
                if ports_write[0] == 'wr':
                    var key = ports_write[1].keys()
                    unit.send_isa(unit.CmdCode.WRITE_ISA, [key[0], ports_write[1][key[0]]])
                state = Constants.STATE.WAIT
        Constants.STATE.DONE:
            if fl_done:
                emit_signal('yau_read_isa', unit.isa_ports)
                state = Constants.STATE.WAIT


# Записать команду в ИСА
func read_port_isa(read_ports: Array) -> void:
    send_array.append(['rd', read_ports])


# Прочитать данные из порта от ИСА
func write_port_isa(port_isa: int, data_isa: int) -> void:
    var write_data: Dictionary = {port_isa: data_isa}
    send_array.append(['wr', write_data])


## Изменения состояния соединения с ячейкой ЯУ-07Б
func _on_connect_change(unit_state_connect) -> void:
    print_debug("%s" % unit_state_connect)


func on_command_change_device(meta_device):
    print(meta_device)
    send_array = []
    ip_address_yau = meta_device[0]
    ip_port_yau = meta_device[1]
    if unit_fs_1._stream:
        unit_fs_1.disconnect_fs()
    unit_fs_1.connect_to_host(meta_device[3], Constants.PORT_FS)

    if unit_fs_2._stream:
        unit_fs_2.disconnect_fs()
    unit_fs_2.connect_to_host(meta_device[4], Constants.PORT_FS)

    await get_tree().create_timer(0.1).timeout
    setup_fs(unit_fs_1, meta_device[2])
    setup_fs(unit_fs_2, meta_device[2])
    #ip_fs_3 = meta_device[5]


func setup_fs(unit_fs: Node, mode_prd: int) -> void:
    var freq: int
    var att: float

    if mode_prd == Constants.MODE.PRD_H:
        freq = Constants.FS_FREQ.f2 if unit_fs == Network.unit_fs_1 else Constants.FS_FREQ.f3
        att = Constants.FS_ATT['ПРД-Н1'][0] if unit_fs == Network.unit_fs_1 else Constants.FS_ATT['ПРД-Н1'][1]

    elif mode_prd == Constants.MODE.PRD_B:
        freq = Constants.FS_FREQ.f4 if unit_fs == Network.unit_fs_1 else Constants.FS_FREQ.f5
        att = Constants.FS_ATT['ПРД-В1'][0] if unit_fs == Network.unit_fs_1 else Constants.FS_ATT['ПРД-В1'][1]

    elif mode_prd == Constants.MODE.PRD_K:
        freq = Constants.FS_FREQ.f6 if unit_fs == Network.unit_fs_1 else Constants.FS_FREQ.f7
        att = Constants.FS_ATT['ПРД-К1'][0] if unit_fs == Network.unit_fs_1 else Constants.FS_ATT['ПРД-К1'][1]
    #var freq = Constants.FS_FREQ.f1 if unit_fs = Network.unit_fs_1 else

    if unit_fs.online:
        unit_fs.set_gen_state(false)
        await get_tree().create_timer(0.3).timeout
        unit_fs.get_gen_state()
        unit_fs.set_gen_state(true)
        await get_tree().create_timer(0.3).timeout
        unit_fs.set_carrier(freq * 1_000_000)
        unit_fs.set_att_batch(att)

        unit_fs.get_carrier()
        unit_fs.get_att_batch()
        unit_fs.get_base_current_temp()
        unit_fs.get_base_can_macro()
        unit_fs.get_gen_state()
