Загрузка данных


# -*- coding: utf-8 -*-
# group_manager.py

import json
import logging
import os
import re
import tkinter as tk
from tkinter import messagebox, ttk

from modules.database_module import *

# Настройка логирования
logging.basicConfig(level=logging.INFO)

# Определение абсолютного пути к файлу конфигурации
CONFIG_DIR = os.path.dirname(os.path.abspath(__file__))
CONFIG_FILE = os.path.join(CONFIG_DIR, "config.json")


# Загрузка и сохранение конфигурации
def load_config():
    global config_data
    if os.path.exists(CONFIG_FILE):
        logging.info(f"Файл конфигурации найден: {CONFIG_FILE}. Начинаем загрузку.")
        with open(CONFIG_FILE, "r") as file:
            try:
                config_data = json.load(file)
                logging.info("Файл конфигурации успешно загружен.")
                logging.info(f"Текущие данные: {config_data}")
            except json.JSONDecodeError:
                logging.error(f"Файл {CONFIG_FILE} поврежден или неправильный формат!")
                config_data = {"amplifier": "", "groups": {}}
    else:
        logging.info(
            f"Файл конфигурации не найден: {CONFIG_FILE}. Создание нового файла."
        )
        config_data = {"amplifier": "", "groups": {}}
        save_config()


def save_config():
    try:
        with open(CONFIG_FILE, "w") as file:
            json.dump(config_data, file)
        logging.info("Файл конфигурации успешно сохранён.")
    except Exception as e:
        logging.error(f"Ошибка при сохранении конфигурации: {e}")


# Класс менеджера групп
class GroupManager(tk.Toplevel):

    def __init__(self, parent):
        super().__init__(parent)
        self.title("Менеджер групп")
        self.geometry("450x350")
        # Сохраняем ссылку на главное окно
        self.parent = parent

        # Начало моего кода
        # Централизация окна относительно родительского окна
        self.update_idletasks()  # Обязательно вызывайте update_idletasks для точности расчетов
        parent_x = parent.winfo_x()
        parent_y = parent.winfo_y()
        parent_w = parent.winfo_width()
        parent_h = parent.winfo_height()

        # Рассчитываем позицию нового окна
        w = self.winfo_width()
        h = self.winfo_height()
        x = parent_x + (parent_w - w) // 2
        y = parent_y + (parent_h - h) // 2

        # Устанавливаем позицию окна
        self.geometry(f"+{x}+{y}")

        # Загружаем конфигурационные данные
        load_config()

        # Верхняя панель навигации
        nav_panel = tk.Frame(self)
        nav_panel.pack(fill="x", pady=10)

        # Название группы
        tk.Label(nav_panel, text="Название группы:").grid(
            row=0, column=0, sticky="w", padx=5
        )
        self.name_entry = tk.Entry(nav_panel, width=30)
        self.name_entry.grid(row=0, column=1, sticky="w", padx=5)

        # Код группы (уникальный идентификатор)
        tk.Label(nav_panel, text="Код группы (ID):").grid(
            row=1, column=0, sticky="w", padx=5
        )
        self.code_entry = tk.Entry(nav_panel, width=30)
        self.code_entry.grid(row=1, column=1, sticky="w", padx=5)

        # КОВ группы
        tk.Label(nav_panel, text="КОВ группы:").grid(
            row=2, column=0, sticky="w", padx=5
        )
        self.kov_entry = tk.Entry(nav_panel, width=15)
        self.kov_entry.grid(row=2, column=1, sticky="w", padx=5)

        # Постоянное поле для отображения коэффициента усиления
        tk.Label(nav_panel, text="Постоянный коэффициент усиления:").grid(
            row=3, column=0, sticky="w", padx=5
        )
        self.amplifier_display = tk.Entry(
            nav_panel, state="normal", readonlybackground="white", fg="black", width=15
        )
        self.amplifier_display.grid(row=3, column=1, sticky="w", padx=5)
        current_value = config_data.get("amplifier", "")
        self.amplifier_display.delete(
            0, tk.END
        )  # очистка поля перед установкой нового значения
        self.amplifier_display.insert(0, current_value)
        self.amplifier_display.config(
            state="readonly"
        )  # переключаем поле в режим "только для чтения"

        # Поле для временного ввода нового значения коэффициента
        tk.Label(nav_panel, text="Новый коэффициент усиления:").grid(
            row=4, column=0, sticky="w", padx=5
        )
        self.new_amplifier_entry = tk.Entry(nav_panel, width=15)
        self.new_amplifier_entry.grid(row=4, column=1, sticky="w", padx=5)

        # Кнопка для установки нового коэффициента
        apply_amp_button = tk.Button(
            nav_panel, text="Установить усиление", command=self.apply_new_amplifier
        )
        apply_amp_button.grid(row=5, column=0, columnspan=2, pady=10)

        # Кнопка для добавления группы
        add_group_button = tk.Button(
            nav_panel, text="Добавить группу", command=self.add_group
        )
        add_group_button.grid(row=6, column=0, columnspan=2, pady=10)

        # Дерево для отображения существующих групп
        self.groups_tree = ttk.Treeview(self, columns=("code", "name"), show="headings")
        self.groups_tree.column("code", width=150)
        self.groups_tree.column("name", width=150)
        self.groups_tree.heading("code", text="Код группы")
        self.groups_tree.heading("name", text="Название")
        self.groups_tree.pack(expand=True, fill="both")

        # Привязываем события к дереву
        self.groups_tree.bind("<Double-Button-1>", self.edit_group)
        self.groups_tree.bind("<Button-3>", self.show_context_menu)

        # Обновляем дерево с информацией о группах
        self.update_groups_tree()

    # Отдельно определяем методы класса
    def notify_main_window(self):
        # Уведомляем главное окно о том, что группа сменилась
        self.parent.notify_group_change()

    def select_group(self):
        # Вызываем уведомление главного окна о смене группы
        self.notify_main_window()

    def update_groups_tree(self):
        # Очищаем текущий список групп
        self.groups_tree.delete(*self.groups_tree.get_children())

        # Получаем список всех групп из базы данных
        groups = list_groups()

        # Заполняем таблицу заново
        for group in groups:
            self.groups_tree.insert("", "end", values=(group.code, group.name))

    def apply_new_amplifier(self):
        new_value = self.new_amplifier_entry.get().strip()
        if new_value:
            try:
                float(new_value)  # Проверяем, является ли значение числом
            except ValueError:
                messagebox.showwarning(
                    "Ошибка", "Коэффициент усиления должен быть числом."
                )
                return

            # Обновляем постоянное поле
            self.amplifier_display.config(state="normal")
            self.amplifier_display.delete(0, tk.END)
            self.amplifier_display.insert(0, new_value)
            self.amplifier_display.config(state="readonly")

            # Присваиваем значение глобальному состоянию
            config_data["amplifier"] = new_value
            save_config()

            # Очищаем временное поле ввода
            self.new_amplifier_entry.delete(0, tk.END)
        else:
            messagebox.showwarning(
                "Ошибка", "Нужно ввести значение коэффициента усиления."
            )

    def add_group(self):
        name = self.name_entry.get().strip()
        code = self.code_entry.get().strip()
        kov = self.kov_entry.get().strip()

        # Проверка формата КОВ
        if not re.match(r"^\d+(.\d+)?$", kov):
            return messagebox.showwarning(
                "Ошибка", "КОВ группы должен быть численным значением."
            )

        # Проверка уникальности кода группы
        existing_codes = [grp.code for grp in list_groups()]
        if code in existing_codes:
            return messagebox.showwarning("Ошибка", "Такой код группы уже занят.")

        if not all([name, code]):
            return messagebox.showwarning("Ошибка", "Заполните название и код группы.")

        # Добавляем группу в базу данных
        add_group(name=name, code=code, kov=float(kov))

        # Обновляем таблицу
        self.update_groups_tree()

        # Очищаем поля ввода
        self.name_entry.delete(0, tk.END)
        self.code_entry.delete(0, tk.END)
        self.kov_entry.delete(0, tk.END)

    def edit_group(self, event):
        selected_item = self.groups_tree.selection()
        if selected_item:
            item_values = self.groups_tree.item(selected_item)["values"]
            current_code = item_values[0]  # получаем код группы
            found_group = next(
                (grp for grp in list_groups() if grp.code == current_code), None
            )

            if found_group:
                # Начинаем создание окна редактирования группы
                dialog = tk.Toplevel(self)
                dialog.title("Редактировать группу")
                dialog.geometry("300x200")

                # ЦЕНТРИРУЕМ ОКНО ОТНОСИТЕЛЬНО РОДИТЕЛЯ
                self.update_idletasks()  # Важно для правильной оценки размеров
                parent_x = self.winfo_x()
                parent_y = self.winfo_y()
                parent_w = self.winfo_width()
                parent_h = self.winfo_height()

                # Расчёт позиций окна
                w = dialog.winfo_width()
                h = dialog.winfo_height()
                x = parent_x + (parent_w - w) // 2
                y = parent_y + (parent_h - h) // 2

                # Установка позиции окна
                dialog.geometry(f"+{x}+{y}")

                # Дальше остальная логика создания элементов окна...
                # Название группы
                tk.Label(dialog, text="Название группы:").pack(anchor="w")
                name_field = tk.Entry(dialog)
                name_field.insert(0, found_group.name)
                name_field.pack(fill="x", pady=5)

                # Код группы (уникальный идентификатор)
                tk.Label(dialog, text="Код группы (ID):").pack(anchor="w")
                code_field = tk.Entry(dialog)
                code_field.insert(0, found_group.code)
                code_field.pack(fill="x", pady=5)

                # КОВ группы
                tk.Label(dialog, text="КОВ группы:").pack(anchor="w")
                kov_field = tk.Entry(dialog)
                kov_field.insert(0, str(found_group.kov))
                kov_field.pack(fill="x", pady=5)

                # Кнопка для сохранения изменений
                save_btn = tk.Button(
                    dialog,
                    text="Сохранить",
                    command=lambda: self.save_group_changes(
                        current_code,
                        name_field.get(),
                        code_field.get(),
                        kov_field.get(),
                    ),
                )
                save_btn.pack(anchor="w", pady=5)
            else:
                messagebox.showwarning("Ошибка", "Не удалось найти указанную группу.")
        else:
            messagebox.showwarning("Ошибка", "Выберите группу для редактирования.")


    def save_group_changes(self, group_code, new_name, new_code, new_kov):
        # Проверяем оригинальную группу
        original_group = next(
            (grp for grp in list_groups() if grp.code == group_code), None
        )
        if original_group is None:
            return messagebox.showwarning("Ошибка", "Группа не найдена.")

        # Проверка уникальности KOV
        other_groups = [grp for grp in list_groups() if grp.code != group_code]
        existing_kovs = set(grp.kov for grp in other_groups)

        # Проверка нового значения KOV
        if new_kov.strip():
            try:
                new_kov_float = float(new_kov)
            except ValueError:
                return messagebox.showwarning(
                    "Ошибка", "Некорректное значение КОВ. Оно должно быть числом."
                )

            if new_kov_float in existing_kovs:
                return messagebox.showwarning(
                    "Ошибка", "Такое значение КОВ уже занято другой группой."
                )
        else:
            new_kov_float = None

        # Если код группы изменился, обновляем показатели
        old_code = original_group.code
        if new_code != old_code:
            # Получаем список показателей текущей группы
            indicators = get_all_indicators_by_group(old_code)
            updated_indicators = []

            # Формируем новый код для каждого показателя
            for ind in indicators:
                # ЗАМЕНА _ НА -
                parts = ind.code.split("-")
                if len(parts) > 1:
                    new_indicator_code = f"{new_code}-{parts[-1]}"
                else:
                    # Защита от ситуаций, когда в коде нет "-"
                    new_indicator_code = f"{new_code}-{ind.code}"
                updated_indicators.append((ind.id, new_indicator_code))

            # Обновляем коды показателей
            for ind_id, new_code in updated_indicators:
                print(f"Обновляю индикатор {ind_id}: новый код {new_code}")
                edit_indicator(ind_id, new_code=new_code)

        # Прямо обновляем группу в базе данных
        session = Session()
        group = session.query(Group).filter_by(code=group_code).first()
        if group:
            group.name = new_name
            group.code = new_code
            group.kov = new_kov_float
            session.commit()
            self.update_groups_tree()
            messagebox.showinfo("Готово", "Группа успешно обновлена.")
        else:
            messagebox.showwarning("Ошибка", "Группа не найдена.")

    def show_context_menu(self, event):
        context_menu = tk.Menu(self, tearoff=0)
        context_menu.add_command(label="Удалить группу", command=self.delete_group)
        context_menu.post(event.x_root, event.y_root)

    def delete_group(self):
        selected_item = self.groups_tree.selection()
        if not selected_item:
            messagebox.showwarning("Ошибка", "Нет выбранной группы для удаления.")
            return

        item_values = self.groups_tree.item(selected_item)["values"]
        group_code = item_values[0]
        found_group = next(
            (grp for grp in list_groups() if grp.code == group_code), None
        )

        if found_group:
            confirmation = messagebox.askyesno(
                "Подтверждение",
                f"Вы уверены, что хотите удалить группу '{found_group.name}'?",
            )
            if confirmation:
                with Session() as session:
                    group = session.query(Group).filter_by(code=group_code).first()
                    if group:
                        session.delete(group)
                        session.commit()
                        self.update_groups_tree()
                        messagebox.showinfo("Готово", "Группа успешно удалена.")
                    else:
                        messagebox.showwarning(
                            "Ошибка", "Группу не удалось найти в базе данных."
                        )
        else:
            messagebox.showwarning("Ошибка", "Не удалось найти указанную группу.")


# Основная точка входа
if __name__ == "__main__":
    root = tk.Tk()
    load_config()  # Загружаем конфигурацию
    manager = GroupManager(root)
    root.mainloop()