extends Panel

# Предзагрузка ячеек таблиц
const TableHeader = preload('res://table/header.tscn')
const CellYemsButton  = preload('res://scenes/эмс/кнопка-эмс.tscn')
const CellLineEdit  = preload('res://table/ячейка-2.tscn')
const CellState  = preload('res://scenes/эмс/состояния-эмс.tscn')
const CellOptBtn = preload('res://scenes/эмс/кнопка-5.tscn')
const CellLEEmpty = preload('res://scenes/эмс/line-edit-empty.tscn')
const CellFront = preload('res://scenes/cell/cell-front.tscn')
const CellFrontRear = preload('res://scenes/cell/cell-front-rear.tscn')

# Режимы работы выходов
const OUT_MODE: Array = ['Работа', 'Контроль', '1', '0']            #
const COLUMN_OPTS_BTN: Array = [5]
const TABLE_ENTRY_COLUMNS: Array = [2,3]
const OUT_SET_ROW: Array = [CellLineEdit, CellLEEmpty, CellLEEmpty, CellLEEmpty, CellLEEmpty, CellLEEmpty]
const IN_SET_ROW: Array = [CellLineEdit, CellLEEmpty, CellLEEmpty, CellLEEmpty, CellLEEmpty]


var g_boards: Dictionary		# Словарь плат ЭМС
var posx: int = 125				# Позиция элементов по x
var posy: int = 70				# Позиция элементов по y


func _ready() -> void:
    call_deferred('init_boards')


## Инициализация основных элементов экрана ЭМС
func init_boards():
    # Выставление позиций элементов ЭМС на экране
    $scrollin.set_position(Vector2(posx,posy))
    $scrollout.set_position(Vector2(posx+650,posy))
    $scrl_in_set.set_position(Vector2(posx,posy + 700))
    $scrl_out_set.set_position(Vector2(posx+650,posy + 700))
    $lbl_online.set_position(Vector2(posx,posy-60))
    $btn_flash_read.set_position(Vector2(posx,posy + 900))
    $btn_flash_write.set_position(Vector2(posx,posy+ 935))
    $btn_connect.set_position(Vector2(posx+590,posy-25))
    $btn_disconnect.set_position(Vector2(posx+587,posy + 675))

    g_boards['КЭМС'] = yemsboards.EmsBoard.new('КЭМС', 0x130, yemsconsts.INPUT_ROWS, yemsconsts.OUTPUT_ROWS)
    g_boards['П5-28'] = yemsboards.EmsBoard.new('П5-28', 0x140, yemsconsts.INPUT_ROWS1, yemsconsts.OUTPUT_ROWS1)
    init_tbl_in()
    $scrollin/tbl_in.pin_header($scrollin, self)
    init_tbl_out()
    $scrollout/tbl_out.pin_header($scrollout, self)
    $scrl_in_set/tbl_in_set.pin_header($scrl_in_set, self)
    $scrl_out_set/tbl_out_set.pin_header($scrl_out_set, self)
    init_tbl_files()
    $scrl_files/tbl_files.pin_header($scrl_files, self)
    $btn_connect.connect('pressed', Callable(self, 'on_btn_connect'))
    $btn_disconnect.connect('pressed', Callable(self, 'on_btn_disconnect'))
    $btn_flash_read.button_connect('pressed', Callable(self, 'on_btn_flash_read').bind($btn_flash_read))
    $btn_flash_write.button_connect('pressed', Callable(self, 'on_btn_flash_write').bind($btn_flash_write))


## Обработчик нажатия кнопки disconnect.
func on_btn_disconnect():
    var selected_rows_in: Array = []
    var selected_rows_out: Array = []
    $scrl_in_set/tbl_in_set.get_selected_rows(selected_rows_in)
    $scrl_out_set/tbl_out_set.get_selected_rows(selected_rows_out)
    if len(selected_rows_in):
        on_disconnect($scrl_in_set/tbl_in_set, selected_rows_in, 'вход')
    elif len(selected_rows_out):
        on_disconnect($scrl_out_set/tbl_out_set, selected_rows_out, 'выход')


## Разрывает связь входа и выхода, [param tbl] - таблица, [param selected_rows] - выбранные строки
## [param type_dev] - тип, 'вход' или 'выход'
func on_disconnect(tbl, selected_rows, type_dev: String):
        var dev = tbl.get_node_user_data(0, 0)
        var user_data: Array = tbl.get_node_user_data(0, selected_rows[0])
        var con_dev = user_data[0]
        var connector: String = con_dev.connector
        dev.connect_devs.erase(con_dev.connector)
        con_dev.connect_devs.erase(dev.connector)
        if type_dev == 'вход':
            set_in_dev(dev)
            set_out_dev(con_dev)
        elif type_dev == 'выход':
            set_in_dev(con_dev)
            set_out_dev(dev)


## Обработчик нажатия кнопки "Прочитать"
func on_btn_flash_read(btn):
    await get_tree().create_timer(0.1).timeout
    btn.pressed = false


## Обработчик нажатия кнопки "Записать"
func on_btn_flash_write(btn):
    await get_tree().create_timer(0.1).timeout
    btn.pressed = false


## Инициализация таблицы с файлами настроек ЭМС
func init_tbl_files():
    $scrl_files/tbl_files.set_header([TableHeader, TableHeader, TableHeader])
    $scrl_files/tbl_files.set_header_text(['Имя файла', 'Дата изменения', 'Размер'])
    $scrl_files/tbl_files.set_columns_min_size([200, 120, 70])


## Инициализация таблиц входов
func init_tbl_in():
    # Инициализация основной таблицы входов, в ней отображается информация о параметрах и состоянии
    var header_type: Array = [TableHeader, TableHeader, CellFront, CellFrontRear, TableHeader]
    var header_text: Array = ['Входы', 'Соединитель', 'мкс', 'мкс', 'Состояние']
    var row_type: Array = [CellLineEdit, CellLineEdit, CellLineEdit, CellLineEdit, CellState]
    var yams_alligment_in: Array = [ HORIZONTAL_ALIGNMENT_LEFT,  HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER]
    var column_size: Array = [250, 100, 70, 70, 50]
    $scrollin/tbl_in.set_header(header_type)
    $scrollin/tbl_in.set_header_text(header_text)
    for board in g_boards:
        for item in g_boards[board].in_tbl:
            $scrollin/tbl_in.add_row(row_type)
            var row_index : int = $scrollin/tbl_in.get_rows_count() - 1
            var params : Array = item[1]
            var in_dev: yemsdevs.InDev = yemsdevs.InDev.new(item[0], params, row_index)
            in_dev.board = board
            for i in range(len(row_type)):
                if i < len(params):
                    var node = $scrollin/tbl_in.get_node2(i, row_index)
                    node.text = params[i]
                    node.editable = false
                $scrollin/tbl_in.set_node_user_data(i, row_index, [in_dev, board])
    $scrollin/tbl_in.set_columns_alignments(yams_alligment_in)
    $scrollin/tbl_in.set_columns_min_size(column_size)
    $scrollin/tbl_in.connect('row_pressed', Callable(self, 'on_row_pressed_in'))
    $scrollin/tbl_in.connect('selected_changed', Callable(self, 'on_selected_changed_in'))

    # Инициализация таблицы изменения параметров входа и списка выходов связанных с ним
    header_text[0] = 'Вход'
    $scrl_in_set/tbl_in_set.set_header(header_type)
    $scrl_in_set/tbl_in_set.set_header_text(header_text)
    $scrl_in_set/tbl_in_set.set_columns_alignments(yams_alligment_in)
    $scrl_in_set/tbl_in_set.set_columns_min_size(column_size)
    $scrl_in_set/tbl_in_set.connect('row_pressed', Callable(self, 'on_row_pressed_si'))
    $scrl_in_set/tbl_in_set.connect('selected_changed', Callable(self, 'on_selected_changed_si'))


## Обработчик редактирования Entry в таблице параметров входов/выходов
func on_edit_entry(text : String, entry):
    print_debug(text, entry)


## Обработчик выбора строки в таблице входов
func on_selected_changed_in(i_row: int):
    var selecter_rows: Array = []
    $scrollin/tbl_in.get_selected_rows(selecter_rows)
    var user_data = $scrollin/tbl_in.get_node_user_data(0, i_row)
    var dev = user_data[0]
    set_in_dev(dev)


## Обработчик нажатия на таблицу входов
func on_row_pressed_in(i_row: int):
    on_row_pressed(i_row, $scrollin/tbl_in)
    on_selected_changed_in(i_row)


##  Выбор входного устройства, для отображения в таблице соединений входа и изменения параметров
func set_in_dev(dev):
    var row_type: Array = [CellLineEdit, CellLineEdit, CellLineEdit, CellLineEdit, CellState]
    set_dev($scrl_in_set/tbl_in_set, dev, row_type, IN_SET_ROW, 'Список соединённых выходов :', [250, 100, 70, 70, 70])


## Обработчик выбора строки в таблице соединений входа и изменения параметров
func on_selected_changed_si(i_row: int):
    if i_row < 2:
        return
    var out_user_data = $scrl_in_set/tbl_in_set.get_node_user_data(0, i_row)
    var dev = out_user_data[0]
    var connector = dev.connector
    for i in range($scrollout/tbl_out.get_rows_count()):
        var node = $scrollout/tbl_out.get_node2(1, i)
        if connector == node.text:
            on_row_pressed_out(i)


## Обработчик нажатия на таблицу соединений входа и изменения параметров
func on_row_pressed_si(i_row: int):
    if i_row < 2:
        return
    on_row_pressed(i_row, $scrl_in_set/tbl_in_set)
    on_selected_changed_si(i_row)


## Инициализация таблиц выходов
func init_tbl_out():
    # Инициализация основной таблицы выходов, в ней отображается информация о параметрах и состоянии
    var header_text = ['Выходы', 'Соединитель', 'мкс', 'мкс', 'Состояние', 'Режим']
    var yams_alligment_out: Array = [ HORIZONTAL_ALIGNMENT_LEFT,  HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER]
    $scrollout/tbl_out.set_header([TableHeader, TableHeader, CellFront, CellFrontRear, TableHeader, TableHeader])
    $scrollout/tbl_out.set_header_text(header_text)
    for board in g_boards:
        for item in g_boards[board].out_tbl:
            $scrollout/tbl_out.add_row([CellLineEdit, CellLineEdit, CellLineEdit, CellLineEdit, CellState, CellLineEdit])
            var row_index : int = $scrollout/tbl_out.get_rows_count() - 1
            var params : Array = item[1]
            var out_dev = yemsdevs.OutDev.new(item[0], params, row_index)
            out_dev.board = board
            for i in range(len(header_text)):
                var cell = $scrollout/tbl_out.get_node2(i, row_index)
                if i < len(params):
                    cell.text = params[i]
                    cell.editable = false
                $scrollout/tbl_out.set_node_user_data(i, row_index, [out_dev, board])
                if i in COLUMN_OPTS_BTN:
                    cell.text = out_dev.mode
    $scrollout/tbl_out.set_columns_min_size([250, 100, 70, 70, 70, 100])
    $scrollout/tbl_out.set_columns_alignments(yams_alligment_out)
    $scrollout/tbl_out.connect('row_pressed', Callable(self, 'on_row_pressed_out'))
    $scrollout/tbl_out.connect('selected_changed', Callable(self, 'on_selected_changed_out'))

    # Инициализация таблицы изменения параметров выхода и списка входов связанных с ним
    header_text[0] = 'Выход'
    $scrl_out_set/tbl_out_set.set_header([TableHeader, TableHeader, CellFront, CellFrontRear, TableHeader, TableHeader])
    $scrl_out_set/tbl_out_set.set_header_text(header_text)
    $scrl_out_set/tbl_out_set.set_columns_min_size([250, 100, 70, 70, 70, 100])
    $scrl_out_set/tbl_out_set.connect('row_pressed', Callable(self, 'on_row_pressed_so'))
    $scrl_out_set/tbl_out_set.connect('selected_changed', Callable(self, 'on_selected_changed_so'))


## Обработчик выбора строки в таблице соединений выхода и изменения параметров
func on_selected_changed_so(i_row: int):
    if i_row < 2:
        return
    var in_user_data = $scrl_out_set/tbl_out_set.get_node_user_data(0, i_row)
    var dev = in_user_data[0]
    var connector = dev.connector
    for i in range($scrollin/tbl_in.get_rows_count()):
        var node = $scrollin/tbl_in.get_node2(1, i)
        if connector == node.text:
            on_row_pressed_in(i)


## Обработчик нажатия на таблицу соединений выхода и изменения параметров
func on_row_pressed_so(i_row: int):
    if i_row < 2:
        return
    on_row_pressed(i_row, $scrl_out_set/tbl_out_set)
    on_selected_changed_so(i_row)


## Обработчик выбора строки в таблице выходов
func on_selected_changed_out(i_row: int):
    var selecter_rows: Array = []
    $scrollout/tbl_out.get_selected_rows(selecter_rows)
    var user_data = $scrollout/tbl_out.get_node_user_data(0, i_row)
    var dev = user_data[0]
    set_out_dev(dev)


## Обработчик выбора строки в таблице выходов
func on_row_pressed_out(i_row: int):
    on_row_pressed(i_row, $scrollout/tbl_out)
    on_selected_changed_out(i_row)


##  Выбор выходного устройства, для отображения в таблице соединений выхода и изменения параметров
func set_out_dev(dev):
    var row_type: Array = [CellLineEdit, CellLineEdit, CellLineEdit, CellLineEdit, CellState, CellOptBtn]
    set_dev($scrl_out_set/tbl_out_set, dev, row_type, OUT_SET_ROW, 'Список соединённых входов :', [250, 100, 70, 70, 70, 100])
    var mode = $scrl_out_set/tbl_out_set.get_node2(5, 0)
    for opt in OUT_MODE:
        mode.add_item(opt)
    var mode_index: int = OUT_MODE.find(dev.mode)
    if mode_index != -1:
        mode.select(mode_index)


## Выбор входного или выходного устройства [param tbl] - таблица, [param dev] - устройство,
## [param row_type] - массив с типами колонок, [param row_type_conn] - массив с пустыми LineEdit
## [param lbl_text] - текст отображаемый во 2 строке: пример: ('Список соединённых входов :')
func set_dev(tbl, dev, row_type, row_type_conn, lbl_text, row_size):
    tbl.clear_rows()
    tbl.add_row(row_type)
    tbl.set_columns_min_size(row_size)
    var le_name: LineEdit = tbl.get_node2(0, 0)
    le_name.editable = false
    le_name.text = dev.dev_name
    var connector: LineEdit = tbl.get_node2(1, 0)
    connector.editable = false
    connector.text = dev.connector
    var delay: LineEdit = tbl.get_node2(2, 0)
    delay.text = '%4.2f'%dev.delay
    var offset: LineEdit = tbl.get_node2(3, 0)
    offset.text = '%4.2f'%dev.offset
    var state = tbl.get_node2(4, 0)
    state.set_frame(dev.state)
    tbl.add_row(row_type_conn)
    var lbl: LineEdit = tbl.get_node2(0, 1)
    lbl.text = lbl_text
    for i in len(row_type_conn):
        var le: LineEdit = tbl.get_node2(i, 1)
        tbl.set_node_user_data(i, 0, dev)
        le.editable = false

    for i in dev.connect_devs:
        var dev_con = dev.connect_devs[i][0]
        tbl.add_row(row_type_conn)
        var node_index: Array = [0, tbl.get_rows_count() -1]
        var le_name_out: LineEdit = tbl.get_node2(node_index[0], node_index[1])
        disable_edit(tbl, len(row_type_conn), node_index[1])
        le_name_out.text = dev_con.dev_name
        tbl.set_node_user_data(node_index[0], node_index[1], dev.connect_devs[i])
    tbl.connect_columns(self, 'text_submitted', 'on_edit_entry', TABLE_ENTRY_COLUMNS, [])


## Обработчик нажатия кнопки connect
func on_btn_connect():
    var in_row_index: Array = []
    var out_row_index: Array = []
    $scrollin/tbl_in.get_selected_rows(in_row_index)
    $scrollout/tbl_out.get_selected_rows(out_row_index)
    if len(in_row_index) and len(out_row_index):
        var in_user_data = $scrollin/tbl_in.get_node_user_data(0, in_row_index[0])
        var out_user_data = $scrollout/tbl_out.get_node_user_data(0, out_row_index[0])
        var in_dev = in_user_data[0]
        var out_dev = out_user_data[0]
        add_connection_dev($scrl_out_set/tbl_out_set, in_dev, out_dev, OUT_SET_ROW, in_user_data)
        add_connection_dev($scrl_in_set/tbl_in_set, out_dev, in_dev, IN_SET_ROW, out_user_data)


## образовывает связь между выбранным входом и выходом [param tbl] - таблица, [param dev1] - устройство1,
## [param dev2] - устройство 2, [param set_row] - массив с пустыми LineEdit
## [param user_data] - пользовательские данные устройства1
func add_connection_dev(tbl, dev1, dev2, set_row, user_data):
    if not dev1.connector in dev2.connect_devs:
        tbl.add_row(set_row)
        var node_index: Array = [0, tbl.get_rows_count() -1]
        var le_name: LineEdit = tbl.get_node2(node_index[0], node_index[1])
        le_name.text = dev1.connector
        disable_edit(tbl, len(set_row), node_index[1])
        tbl.set_node_user_data(node_index[0], node_index[1], user_data)
        dev2.connect_devs[dev1.connector] = user_data


## Отключает возможность редактирования LineEdit в таблице [param tbl] - таблица,
## [param num_col] - номер колонки, [param i_row] - номер столбца
func disable_edit(tbl, num_col: int, i_row: int):
    for col in range(num_col):
        var node: LineEdit = tbl.get_node2(col, i_row)
        node.editable = false


## Обработчик выбора строки с таблице
func on_row_pressed(i_row: int, tbl):
    tbl.clear_rows_selected()
    var is_row_selected = tbl.is_row_selected(i_row)
    tbl.set_row_selected(i_row, not is_row_selected)

