class_name configure extends Panel

@export var TableHeader: PackedScene
@export var TableToggle: PackedScene
@export var TableEdit: PackedScene
@export var TableColorPick: PackedScene

const ALIGNMENT = [HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER]
const HEADER_ROW_TEXT: = ['Параметр', 'Значение']

var HEADER_ROW: Array

## TODO: Придумать как избавиться от индексов
## Индексы строк таблицы.
const EXTERNAL_CU = 16    ## Внешнее целеуказание
const TRASSA = 17         ## Строка - Трасса
const SUPPRESS = 18       ## Строка - Подавление
const KEYBOARD = 19       ## Строка - Виртуальная клавиатура
const HIDE_EMS2 = 20      ## Строка - Скрыть вкладку ЭМС 2
const DEBAG_CONTROL = 21  ## Строка - Отладка контроля
const COMMIT = 22         ## Строка - Версия УАРЭП
const GOS_BTN = 52        ## Разрешить работу по своим целям
const COLOR_BTN_ACT = 54  ## Цвет кнопки "Подавление"
const COLOR_WHITE = 55    ## Цвет фона схемы
const COLOR_BLACK = 56    ## Цвет схемы
const COLOR_THEME = 57    ## Цвет темы

var SETTING_TABLE: Array

var name_to_line_index: = {}    ## Для преобразования названия параметра в номер строки
var table_color_instance: Node  ## Нода цвета кнопки подавления

func on_checkbutton_pressed(i_row: int):
    on_row_pressed(i_row)


func _init_scene_arrays():
    HEADER_ROW = [TableHeader, TableHeader]
    SETTING_TABLE = [
    ['Ограниченный режим',       TableEdit, TableToggle, 'Ограничть возможности по постановке помех'],  # 0
    ['Кнопка «ПД-М4»',           TableEdit, TableToggle, 'Разрешить отображение кнопки'],               # 1
    ['Кнопка «ПД-М2»',           TableEdit, TableToggle, 'Разрешить отображение кнопки'],               # 2
    ['Кнопка «ОЗП-1»',           TableEdit, TableToggle, 'Разрешить отображение кнопки'],               # 3
    ['Кнопка «МЧМ-1»',           TableEdit, TableToggle, 'Разрешить отображение кнопки'],               # 4
    ['Кнопка «ОРН-И1»',          TableEdit, TableToggle, 'Разрешить отображение кнопки'],               # 5
    ['Кнопка «ОРН-М2»',          TableEdit, TableToggle, 'Разрешить отображение кнопки'],               # 6
    ['Кнопка «ЛЧМ-1»',           TableEdit, TableToggle, 'Разрешить отображение кнопки'],               # 7
    ['Кнопка «ПД-М4С»',          TableEdit, TableToggle, 'Разрешить отображение кнопки'],               # 8
    ['Кнопка «ПД-ЧМ»',           TableEdit, TableToggle, 'Разрешить отображение кнопки'],               # 9
    ['Кнопка «СВ-И1»',           TableEdit, TableToggle, 'Разрешить отображение кнопки'],               # 10
    ['Кнопка «К1»',              TableEdit, TableToggle, 'Разрешить отображение кнопки'],               # 11
    ['Кнопка «СВ-М2»',           TableEdit, TableToggle, 'Разрешить отображение кнопки'],               # 12
    ['Кнопка «ОРН»',             TableEdit, TableToggle, 'Разрешить отображение кнопки'],               # 13
    ['Кнопка «JTIDS»',           TableEdit, TableToggle, 'Разрешить отображение кнопки'],               # 14
    ['Кнопка «КУПД»',            TableEdit, TableToggle, 'Разрешить отображение кнопки'],               # 15
    ['Внешнее управление',       TableEdit, TableToggle, 'Передать управление в 5П28'],                 # 16
    ['Внешнее указание Трасса',  TableEdit, TableToggle, 'Разрешить постановку помех от Трасса'],       # 17
    ['Кнопка «Подавление»',      TableEdit, TableToggle, 'Разрешить отображение кнопки'],               # 18
    ['Виртуальная клавиатура',   TableEdit, TableToggle, 'Включить отображение экранной клавиатуры'],   # 19
    ['Скрыть вкладку ЭМС 2',     TableEdit, TableToggle, 'Отображать вкладку \"ЭМС-2\"'],               # 20
    ['Отладка контроля',         TableEdit, TableToggle, 'Отображать отладку контроля'],                # 21
    ['Текущая версия ПО УАРЭП',  TableEdit, TableEdit,   'Время сборки, версия и номер фиксации'],      # 22
    ['уарэп-яу07-частный',       TableEdit, TableEdit,   'IP-адрес для получения частных сообщений от ЯУ-07'],           # 23
    ['уарэп-яу07-общий',         TableEdit, TableEdit,   'IP-адрес для получения широковещательных сообщений от ЯУ-07'], # 24
    ['уарэп-капсрпб',            TableEdit, TableEdit,   'IP-адрес для связи с КАПС-РПБ [<адрес этого узла>, <адрес удалённого узла>, <порт этого узла>, <порт удалённого узла>]'], # 25
    ['уарэп-эмс',                TableEdit, TableEdit,   'IP-адрес для связи с ЭМС'],                   # 26
    ['уарэп-яу07-2в',            TableEdit, TableEdit,   'IP-адрес для связи с прибором ПРД-В 2'],      # 27
    ['уарэп-яу07-2н',            TableEdit, TableEdit,   'IP-адрес для связи с прибором ПРД-Н 2'],      # 28
    ['уарэп-яу07-2к',            TableEdit, TableEdit,   'IP-адрес для связи с прибором ПРД-К 2'],      # 29
    ['уарэп-яу07-4в',            TableEdit, TableEdit,   'IP-адрес для связи с прибором ПРД-В 4'],      # 30
    ['уарэп-яу07-4н',            TableEdit, TableEdit,   'IP-адрес для связи с прибором ПРД-Н 4'],      # 31
    ['уарэп-яу07-4к',            TableEdit, TableEdit,   'IP-адрес для связи с прибором ПРД-К 4'],      # 32
    ['уарэп-яу07-1в',            TableEdit, TableEdit,   'IP-адрес для связи с прибором ПРД-В 1'],      # 33
    ['уарэп-яу07-1н',            TableEdit, TableEdit,   'IP-адрес для связи с прибором ПРД-Н 1'],      # 34
    ['уарэп-яу07-1к',            TableEdit, TableEdit,   'IP-адрес для связи с прибором ПРД-К 1'],      # 35
    ['уарэп-яу07-3в',            TableEdit, TableEdit,   'IP-адрес для связи с прибором ПРД-В 3'],      # 36
    ['уарэп-яу07-3н',            TableEdit, TableEdit,   'IP-адрес для связи с прибором ПРД-Н 3'],      # 37
    ['уарэп-яу07-3к',            TableEdit, TableEdit,   'IP-адрес для связи с прибором ПРД-К 3'],      # 38
    ['уарэп-5п28',               TableEdit, TableEdit,   'IP-адрес для связи с 5П28'],                  # 39
    ['навигация',                TableEdit, TableEdit,   'Порт назначения для получения данных от АКНГ'],   # 40
    ['уарэп-щ3',                 TableEdit, TableEdit,   'Путь к UART-устройству для связи с прибором Щ3'], # 41
    ['уарэп-спт25-1',            TableEdit, TableEdit,   'Путь к UART-устройству для связи с прибором СПТ-25 1'],  # 42
    ['уарэп-спт25-2',            TableEdit, TableEdit,   'Путь к UART-устройству для связи с прибором СПТ-25 2'],  # 43
    ['Шаблон адреса сервера карт', TableEdit, TableEdit, 'Шаблон URL-адреса сервера карт, должен содержать поля \"{x}\", \"{y}\", \"{z}\" для подстановки индекса плитки'], # 44
    ['Адрес АФСП левого борта', TableEdit, TableEdit,    'http-адрес для запроса состояния прибора АФСП'],         # 45
    ['Адрес АФСП правого борта', TableEdit, TableEdit,   'http-адрес для запроса состояния прибора АФСП'],         # 46
    ['Адрес БПО левого борта', TableEdit, TableEdit,     'http-адрес для запроса состояния прибора БПО'],          # 47
    ['Адрес БПО правого борта', TableEdit, TableEdit,    'http-адрес для запроса состояния прибора БПО'],          # 48
    ['Период опроса состояния БПО, секунды', TableEdit, TableEdit, 'Время в секундах' ],                           # 49
    ['Период опроса состояния АФСП, секунды', TableEdit, TableEdit, 'Время в секундах' ],                          # 50
    ['уарэп-трасса', TableEdit, TableEdit, 'IP-адрес для связи с Трассой [<адрес этого узла>, <адрес удалённого узла>, <порт этого узла>, <порт удалённого узла>]'], # 51
    ['Включить работу по своим целям',   TableEdit, TableToggle, 'Разрешает работу в секторе со своей целью'],     # 52
    ['Список своих протоколов', TableEdit, TableEdit, 'Список протоколов целей, по которым запрещено работать' ],  # 53
    ['Цвет кнопки \"Подавление\"', TableEdit, TableColorPick, 'Цвет кнопки. Введено по требованию ПЗ' ],           # 54
    ['Цвет фона схемы', TableEdit, TableColorPick, 'Схема прибора Э2. Изменение цвет фона'],                       # 55
    ['Цвет схемы', TableEdit, TableColorPick, 'Схема прибора Э2. Изменение цвет схемы '],                          # 56
    ['Цвет темы программы', TableEdit, TableToggle, 'ВЫКЛ - темная тема, ВКЛ - светлая тема'],                     # 57
    ['Коэффициент ширины полосы излучения', TableEdit, TableEdit, 'Изменение ширины полосы излучения помехи в зависимости от цели'], # 58
    ['Время повторной отправки помехи', TableEdit, TableEdit, 'Изменение времени повторной отправки помехи'] ] # 59


## Вызывается, когда узел впервые попадает в дерево сцены.
func _ready() -> void:
    setting_tab()
    if OS.get_cmdline_args().has('++ограниченный'):
        $Label2.text = 'Текущий режим доступа: ограниченный'
        for node in $GridContainer.get_children().filter(func(b): return b is Button):
            node.disabled = true
    ProjectSettings.emit_signal('settings_changed')


func on_external_cu_btn_pressed(btn) -> void:
    ProjectSettings.set_setting('application/config/%s' % 'Внешнее управление', btn.button_pressed)
    if btn.button_pressed:
        signaller.emit_signal('interfer_off_all')
    _autosave_now()


func on_trassa_btn_pressed(btn) -> void:
    ProjectSettings.set_setting('application/config/%s' % 'Внешнее указание Трасса', btn.button_pressed)
    _autosave_now()


func on_vk_pressed(btn) -> void:
    signaller.emit_signal('kb_pressed', btn.button_pressed)
    _autosave_now()


func on_gos_pressed(btn) -> void:
    ProjectSettings.set_setting('application/config/Включить работу по своим целям', btn.button_pressed)
    _autosave_now()


func on_ems2_pressed(btn) -> void:
    var state = btn.button_pressed
    signaller.emit_signal('ems2_hide_pressed', state)
    _autosave_now()


func on_debag_control_pressed(btn) -> void:
    var state = btn.button_pressed
    signaller.emit_signal('debag_control_pressed', state)
    _autosave_now()


func on_row_pressed(i_row: int):
    $scroll_set/table.clear_rows_selected()
    $scroll_set/table.set_row_selected(i_row, true)


func parse_cmd_line_args(settings_data: Dictionary):
    var args = OS.get_cmdline_args()
    for i in range(0, args.size(), 2):
        var key: String = args[i]
        key = key.lstrip('\'\" ').rstrip('\'\" ').strip_edges().strip_escapes()
        if not settings_data.has(key):
            continue
        if not ((i + 1) < args.size()):
            push_error('для аргумента \"%s\" не указано значение.' % key)
            break
        var val0 = args[i + 1]
        var val1 = settings_data[key]
        val0 = val0.lstrip('\'\" ').rstrip('\'\" ').strip_edges().strip_escapes()
        if typeof(val1) == TYPE_BOOL:
            if val0 not in ['yes', 'true', 'да', 'no', 'false', 'нет']:
                push_error('для аргумента \"%s\" указано неверное значение \"%s\".' % [key, val0])
                break
            settings_data[key] = true if val0 in ['yes', 'true', 'да'] else false
        elif typeof(val1) == TYPE_ARRAY:
            var val0s = val0.split(',')
            if val0s.size() != val1.size():
                push_error('для аргумента \"%s\" указано неверное значение \"%s\" (исходное: \"%s\").' % [key, val0, val1])
                break
            for j in val0s.size():
                var val: String = val0s[j]
                val = val.lstrip('\'\" ').rstrip('\'\" ').strip_edges().strip_escapes()
                if tools.type_is_num(val):
                    val0s[j] = int(val)
                elif val in ['true', 'false']:
                    val0s[j] = true if val == 'true' else false
                else:
                    val0s[j] = val
        elif typeof(val1) == TYPE_STRING:
            settings_data[key] = val0


func setting_tab():
    _init_scene_arrays()
    $heard_table.set_header(HEADER_ROW)
    $heard_table.set_header_text(HEADER_ROW_TEXT)
    $heard_table.set_columns_min_size([600, 950])
    $heard_table.set_columns_alignments(ALIGNMENT)
    var settings_data = {}
    parse_cmd_line_args(settings_data)
    for key in settings_data:
        ProjectSettings.set_setting('application/config/%s' % key, settings_data[key])
    for i in SETTING_TABLE.size():
        var tbl_row = SETTING_TABLE[i]
        var param_name = tbl_row[0]
        var node_label = tbl_row[1]
        var node_value = tbl_row[2]
        var tootip_text = tbl_row[3]
        name_to_line_index[param_name] = i
        $scroll_set/table.add_row([node_label, node_value])
        var label_instance = $scroll_set/table.get_node2(0, i)
        label_instance.text = param_name
        label_instance.tooltip_text = tootip_text
        $scroll_set/table.set_node_editable(0, i, false)
        var node_values = $scroll_set/table.get_node2(1, i).get_children()
        var edit_node = $scroll_set/table.get_node2(1, i)
        if node_values.size():
            var child = node_values[0]
            if child is CheckButton:
                child.connect('pressed', Callable(self, 'on_checkbutton_pressed').bind(i))
                var val = ProjectSettings.get_setting('application/config/%s' % param_name, true)
                child.set_pressed(val)
                child.pressed.connect(_autosave_now)
        else:
            if settings_data.has(param_name):
                var val = settings_data[param_name]
                if typeof(val) == TYPE_STRING:
                    $scroll_set/table.get_node2(1, i).text = settings_data[param_name]
        if edit_node:
            if edit_node is LineEdit:
                $scroll_set/table.set_node_control(1, i, true)
                edit_node.focus_exited.connect(_autosave_now)
    $scroll_set/table.set_node_editable(1, COMMIT, false)
    $scroll_set/table.set_columns_min_size([600, 950])
    $scroll_set/table.set_columns_alignments(ALIGNMENT)
    $scroll_set/table.connect('row_pressed', Callable(self, 'on_row_pressed'))
    var commit_instance = $scroll_set/table.get_node2(1, COMMIT)
    commit_instance.text = '%s' % commit.VCS_HEAD
    for i in SETTING_TABLE.size():
        var param_name = SETTING_TABLE[i][0]
        var profile = $scroll_set/table.get_node2(1, i)
        if settings.UnitProfiles.has(param_name):
            var unit_data = settings.UnitProfiles[param_name][1]
            profile.text = ''
            for val in unit_data:
                profile.text += str(val) + ','
            profile.text = profile.text.trim_suffix(',')
            continue
        var psk = 'application/config/%s' % param_name
        if ProjectSettings.has_setting(psk):
            var unit_data = ProjectSettings.get_setting(psk)
            if is_instance_of(unit_data, TYPE_STRING):
                profile.text = unit_data
    button_settings()


func button_settings():
    var extern_cu_node = $scroll_set/table.get_node2(1, EXTERNAL_CU).get_children()[0]
    extern_cu_node.connect('pressed', on_external_cu_btn_pressed.bind(extern_cu_node))
    on_external_cu_btn_pressed(extern_cu_node)
    var trassa_node = $scroll_set/table.get_node2(1, TRASSA).get_children()
    trassa_node = trassa_node[0]
    trassa_node.connect('pressed', on_trassa_btn_pressed.bind(trassa_node))
    var vk_node = $scroll_set/table.get_node2(1, KEYBOARD).get_children()[0]
    vk_node.connect('pressed', on_vk_pressed.bind(vk_node))
    var ems2_hide_node = $scroll_set/table.get_node2(1, HIDE_EMS2).get_children()[0]
    ems2_hide_node.connect('pressed', on_ems2_pressed.bind(ems2_hide_node))
    ems2_hide_node.set_pressed(true)
    on_ems2_pressed(ems2_hide_node)
    var gos_node = $scroll_set/table.get_node2(1, GOS_BTN).get_children()[0]
    gos_node.connect('pressed', on_gos_pressed.bind(gos_node))
    var debag_control = $scroll_set/table.get_node2(1, DEBAG_CONTROL).get_children()[0]
    debag_control.connect('pressed', on_debag_control_pressed.bind(debag_control))
    debag_control.set_pressed(false)
    on_debag_control_pressed(debag_control)
    var color_btn_act = $scroll_set/table.get_node2(1, COLOR_BTN_ACT)
    color_btn_act.connect('popup_closed', on_color_closed.bind(color_btn_act))
    var json_col = ProjectSettings.get_setting('application/config/%s' % 'Цвет кнопки \"Подавление\"', '[1.0, 1.0, 1.0, 1.0]')
    var arr_col = JSON.parse_string(json_col)
    color_btn_act.color = Color(arr_col[0], arr_col[1], arr_col[2], arr_col[3]) if arr_col else Color.WHITE
    color_btn_act.text = JSON.stringify(arr_col)
    var color_white = $scroll_set/table.get_node2(1, COLOR_WHITE)
    color_white.connect('popup_closed', on_color_closed_w.bind(color_white))
    var json_col_w = ProjectSettings.get_setting('application/config/%s' % 'Цвет фона схемы', '[0.0, 0.0, 0.0, 0.0]')
    var arr_col_w = JSON.parse_string(json_col_w)
    color_white.color = Color(arr_col_w[0], arr_col_w[1], arr_col_w[2], arr_col_w[3]) if arr_col_w else Color.DIM_GRAY
    color_white.text = JSON.stringify(arr_col_w)
    var color_black = $scroll_set/table.get_node2(1, COLOR_BLACK)
    color_black.connect('popup_closed', on_color_closed_b.bind(color_black))
    var json_col_b = ProjectSettings.get_setting('application/config/%s' % 'Цвет схемы', '[1.0, 1.0, 1.0, 1.0]')
    var arr_col_b = JSON.parse_string(json_col_b)
    color_black.color = Color(arr_col_b[0], arr_col_b[1], arr_col_b[2], arr_col_b[3]) if arr_col_b else Color.WHITE_SMOKE
    color_black.text = JSON.stringify(arr_col_b)
    var theme_node = $scroll_set/table.get_node2(1, COLOR_THEME).get_children()[0]
    theme_node.connect('pressed', on_theme_toggle_pressed.bind(theme_node))
    on_theme_toggle_pressed(theme_node)


func on_theme_toggle_pressed(btn: CheckButton) -> void:
    var is_light = btn.button_pressed
    ProjectSettings.set_setting('application/config/Цвет темы программы', is_light)
    _autosave_now()


func _update_theme_colors():
    var color_white = $scroll_set/table.get_node2(1, COLOR_WHITE)
    var color_black = $scroll_set/table.get_node2(1, COLOR_BLACK)
    on_color_closed_w(color_white)
    on_color_closed_b(color_black)


func on_color_closed_w(color_white: ColorPickerButton):
    var col_w = [color_white.color.r, color_white.color.g, color_white.color.b, color_white.color.a]
    color_white.text = JSON.stringify(col_w)
    ProjectSettings.set_setting('application/config/%s' % 'Цвет фона схемы', color_white.text)
    _autosave_now()


func on_color_closed_b(color_black: ColorPickerButton):
    var col_b = [color_black.color.r, color_black.color.g, color_black.color.b, color_black.color.a]
    color_black.text = JSON.stringify(col_b)
    ProjectSettings.set_setting('application/config/%s' % 'Цвет схемы', color_black.text)
    _autosave_now()


func on_color_closed(color_btn_act: ColorPickerButton):
    var col = [color_btn_act.color.r, color_btn_act.color.g, color_btn_act.color.b, color_btn_act.color.a]
    color_btn_act.text = JSON.stringify(col)
    ProjectSettings.set_setting('application/config/%s' % 'Цвет кнопки \"Подавление\"', color_btn_act.text)
    _autosave_now()


func _autosave_now() -> void:
    var json_data = {}
    for i in SETTING_TABLE.size():
        var parameter = SETTING_TABLE[i][0]
        if parameter in settings.UnitProfiles:
            var ref_profile = settings.UnitProfiles[parameter][1]
            var profiles = $scroll_set/table.get_node2(1, i)
            var value = profiles.get_text()
            if parameter not in json_data:
                var row: = []
                for token in value.split(','):
                    var j: = row.size()
                    if token.is_valid_int():
                        token = int(token)
                    elif token == 'false':
                        token = false
                    elif token == 'true':
                        token = true
                    if typeof(ref_profile[j]) == typeof(token):
                        row.append(token)
                    else:
                        # TODO: Это надо вывести на экран пользователю
                        push_error([parameter, j, type_string(typeof(ref_profile[j])), type_string(typeof(token))])
                        row.append(ref_profile[j])
                json_data[parameter] = row
        else:
            var children = $scroll_set/table.get_node2(1, i).get_children()
            if len(children):
                var child = children[0]
                json_data[parameter] = child.is_pressed()
            else:
                var row = $scroll_set/table.get_row(i)
                json_data[parameter] = row[1].text
    for key in json_data:
        ProjectSettings.set_setting('application/config/%s' % key, json_data[key])
    var settings_file: = settings.get_settings_file_path()
    var file: = FileAccess.open(settings_file, FileAccess.WRITE)
    var abs_path: = ProjectSettings.globalize_path(settings_file)
    if not file:
        log.error('Не удалось открыть файл для записи \"%s\"' % abs_path)
        return
    var json_string: = JSON.stringify(json_data, '  ', true)
    if file.store_string(json_string):
        log.info('Настройки сохранены в файл \"%s\"' % abs_path)
    file.close()
