#!/usr/bin/env python3
"""
GeoMedical Helper - Main.py
마우스 휠 클릭으로 활성화되는 퀵 액세스 메뉴

=== MAIN.PY VERSION INFORMATION ===
MAIN_VERSION = "1.3.0"
MAIN_BUILD_DATE = "2025-08-05"
MAIN_UPDATE_LOG = [
    "1.2.0 (2025-08-04): 버전 관리 시스템 개선, 코드 내 버전 관리로 변경",
    "1.1.0 (2025-08-03): 네트워크 어댑터 관리 기능 개선",
    "1.0.0 (2025-08-01): 초기 마우스휠 기반 UI 시스템 구축"
]
"""

# =============================================================================
# MAIN.PY 버전 정보 - 여기서 직접 관리
# =============================================================================
MAIN_VERSION = "1.2.0"
MAIN_BUILD_DATE = "2025-08-04"
MAIN_DESCRIPTION = "GeoMedical Helper GUI with Mouse Wheel Activation"

import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
import tkinter.scrolledtext as scrolledtext
import webbrowser
import socket
import platform
import psutil
import math
import logging
import datetime
import subprocess
import re
import os
import threading
import sqlite3

# 네트워크 어댑터 관리 함수
def enable_network_adapters():
    """비활성화된 네트워크 어댑터 활성화"""
    import logging
    import subprocess
    import time
    
    logger = logging.getLogger(__name__)
    logger.info("=== Starting network adapter activation process ===")
    
    try:
        # 먼저 현재 어댑터 상태 확인
        status_script = '''
        $adapters = Get-NetAdapter | Select-Object Name, Status
        foreach ($adapter in $adapters) {
            Write-Host "ADAPTER: $($adapter.Name) - STATUS: $($adapter.Status)"
        }
        '''
        
        status_result = subprocess.run([
            'powershell', '-Command', status_script
        ], capture_output=True, text=True, timeout=30, encoding='cp949')
        
        logger.info("Current network adapter status:")
        if status_result.stdout:
            for line in status_result.stdout.split('\n'):
                if line.strip() and line.startswith('ADAPTER:'):
                    logger.info(f"  {line.strip()}")
        else:
            logger.warning("No output from adapter status check")
        
        # PowerShell을 사용해서 비활성화된 어댑터 조회 및 활성화
        powershell_script = '''
        $adapters = Get-NetAdapter | Where-Object { $_.Status -eq "Disabled" }
        $enabledCount = 0
        
        Write-Host "FOUND_DISABLED: $($adapters.Count) adapters"
        
        foreach ($adapter in $adapters) {
            try {
                Write-Host "ENABLING: $($adapter.Name)"
                Enable-NetAdapter -Name $adapter.Name -Confirm:$false
                Write-Host "ENABLED: $($adapter.Name)"
                $enabledCount++
            } catch {
                Write-Host "FAILED: $($adapter.Name) - $($_.Exception.Message)"
            }
        }
        
        Write-Host "TOTAL_ENABLED: $enabledCount"
        '''
        
        # PowerShell 실행
        result = subprocess.run([
            'powershell', '-Command', powershell_script
        ], capture_output=True, text=True, timeout=30, encoding='cp949')
        
        logger.info(f"PowerShell adapter enable result: {result.stdout}")
        
        if result.stderr:
            logger.warning(f"PowerShell adapter enable warning: {result.stderr}")
        
        # 결과 파싱
        enabled_adapters = []
        total_enabled = 0
        
        if result.stdout:
            for line in result.stdout.split('\n'):
                line = line.strip()
                if line.startswith('ENABLED:'):
                    adapter_name = line.replace('ENABLED:', '').strip()
                    enabled_adapters.append(adapter_name)
                elif line.startswith('TOTAL_ENABLED:'):
                    try:
                        total_enabled = int(line.replace('TOTAL_ENABLED:', '').strip())
                    except:
                        pass
        else:
            logger.warning("No PowerShell output to parse")
        
        if total_enabled > 0:
            logger.info(f"Successfully enabled {total_enabled} network adapters: {enabled_adapters}")
            # 어댑터 활성화 후 잠시 대기
            import time
            time.sleep(5)
            return True
        else:
            logger.info("No disabled network adapters found or all adapters were already enabled")
            # 모든 어댑터가 이미 활성화되어 있는 경우도 성공으로 처리
            return True
            
    except subprocess.TimeoutExpired:
        logger.error("Network adapter enable operation timed out")
        return False
    except Exception as e:
        logger.error(f"Network adapter enable error: {e}")
        return False

# 캐시 폴더 관리
def get_cache_dir():
    """캐시 폴더 경로 반환"""
    try:
        # __file__이 정의된 경우 (일반 실행)
        if '__file__' in globals():
            script_dir = os.path.dirname(os.path.abspath(__file__))
        else:
            # 동적 로딩된 경우 현재 작업 디렉토리 사용
            script_dir = os.getcwd()
        
        cache_dir = os.path.join(script_dir, 'cache')
        
        # 캐시 폴더가 없으면 생성
        if not os.path.exists(cache_dir):
            try:
                os.makedirs(cache_dir)
                print(f"Cache directory created: {cache_dir}")
            except OSError as e:
                print(f"Failed to create cache directory: {e}")
                # 캐시 폴더 생성 실패 시 스크립트 폴더 사용
                return script_dir
        
        return cache_dir
        
    except Exception as e:
        print(f"Error in get_cache_dir: {e}")
        # 모든 오류 발생 시 현재 작업 디렉토리의 cache 폴더 사용
        fallback_cache = os.path.join(os.getcwd(), 'cache')
        if not os.path.exists(fallback_cache):
            try:
                os.makedirs(fallback_cache)
            except:
                pass
        return fallback_cache

def get_cache_file_path(filename):
    """캐시 파일의 전체 경로 반환"""
    return os.path.join(get_cache_dir(), filename)

# 데이터 저장/로드 함수
def save_data(key, value):
    """
    캐시 폴더의 app_data.json에 데이터를 저장합니다.
    """
    import json
    
    data_file = get_cache_file_path('app_data.json')
    data = {}
    
    if os.path.exists(data_file):
        try:
            with open(data_file, 'r', encoding='utf-8') as f:
                data = json.load(f)
        except (json.JSONDecodeError, FileNotFoundError):
            data = {}
    
    data[key] = value
    
    try:
        with open(data_file, 'w', encoding='utf-8') as f:
            json.dump(data, f, indent=2, ensure_ascii=False)
    except OSError as e:
        print(f"Failed to save data: {e}")

def load_data(key, default=None):
    """
    캐시 폴더의 app_data.json에서 데이터를 불러옵니다.
    """
    import json
    
    data_file = get_cache_file_path('app_data.json')
    
    if os.path.exists(data_file):
        try:
            with open(data_file, 'r', encoding='utf-8') as f:
                data = json.load(f)
                return data.get(key, default)
        except (json.JSONDecodeError, FileNotFoundError):
            return default
    
    return default

# 디버깅 로그 설정 - 콘솔 출력만 사용 (파일 로깅 제거)
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)

class StatusWindow:
    def __init__(self):
        self.status_window = None
        self.status_label = None
        self.is_visible = False
        self.is_dragging = False
        self.drag_start_x = 0
        self.drag_start_y = 0
        self.settings_window = None  # 설정 창 참조
        self.edit_mode = False  # 편집 모드 플래그
        self.click_through_enabled = False  # 클릭 통과 상태
        self.last_mouse_pos = (0, 0)  # 마지막 마우스 위치
        self.user_has_moved = False  # 사용자가 수동으로 이동했는지 여부
        self.radial_menu = None  # 라디얼 메뉴 참조
        
    def create_status_window(self):
        """상태 표시 창 생성 - Windows 11 완전 호환 버전"""
        if self.status_window:
            return
            
        logger.info("Creating Windows 11 compatible status window...")
        
        # 저장된 위치 로드 또는 기본 위치 설정
        position = load_data('status_position', None)
        window_width = 350
        window_height = 80
        
        if position:
            x, y = position
        else:
            # 기본 위치 계산
            root = tk._default_root or tk.Tk()
            screen_width = root.winfo_screenwidth()
            screen_height = root.winfo_screenheight()
            taskbar_height = 50
            x = screen_width - window_width - 5
            y = screen_height - window_height - taskbar_height
        
        if self.edit_mode:
            # 편집 모드: 일반적인 창으로 생성 (드래그 가능)
            self.create_edit_mode_window(x, y, window_width, window_height)
        else:
            # 일반 모드: 선택된 방식에 따라 클릭 통과 창 생성
            method = load_data('click_through_method', 'pyqt_perfect')
            if method == 'pyqt_perfect':
                self.create_pyqt_perfect_window(x, y, window_width, window_height)
            elif method == 'auto_hide':
                self.create_auto_hide_window(x, y, window_width, window_height)
            else:
                # 기본값은 auto_hide (PyQt5가 없을 때 대안)
                self.create_auto_hide_window(x, y, window_width, window_height)
        
        self.is_visible = True
        self.update_status()
        logger.info(f"Status window created at ({x}, {y}), edit_mode={self.edit_mode}")
    
    def create_pyqt_perfect_window(self, x, y, width, height):
        """완벽한 PyQt5 클릭 통과 창 - 제공된 코드 기반"""
        try:
            from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout
            from PyQt5.QtCore import Qt, QTimer
            from PyQt5.QtGui import QFont
            import sys
            
            # QApplication 인스턴스 확인/생성
            if not QApplication.instance():
                self.qt_app = QApplication(sys.argv)
            else:
                self.qt_app = QApplication.instance()
            
            # QWidget 생성
            self.qt_widget = QWidget()
            
            # 핵심: 제공된 코드와 동일한 설정
            self.qt_widget.setWindowFlags(
                Qt.FramelessWindowHint |
                Qt.WindowStaysOnTopHint |
                Qt.Tool |
                Qt.WindowTransparentForInput  # 이것이 핵심!
            )
            
            # 반투명 배경 설정
            self.qt_widget.setAttribute(Qt.WA_TranslucentBackground)
            
            # 초기 크기와 위치 설정
            self.qt_widget.resize(width, height)
            self.qt_widget.move(x, y)
            
            # 창 크기를 내용에 맞게 자동 조정 설정
            self.initial_x = x
            self.initial_width = width
            
            # 레이아웃 생성
            layout = QVBoxLayout(self.qt_widget)
            layout.setContentsMargins(8, 8, 8, 8)
            
            # 상태 표시 라벨 생성 (제공된 코드의 버튼과 동일한 방식)
            self.qt_label = QLabel("인터넷 상태 확인 중...", self.qt_widget)
            self.qt_label.setStyleSheet("""
                QLabel {
                    background-color: rgba(44, 62, 80, 220);
                    color: white;
                    padding: 8px;
                    border: 1px solid rgba(255, 255, 255, 100);
                    border-radius: 5px;
                    font-size: 9pt;
                }
            """)
            self.qt_label.setFont(QFont("Arial", 9))
            self.qt_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
            self.qt_label.setWordWrap(False)
            
            # 레이아웃에 라벨 추가
            layout.addWidget(self.qt_label)
            
            # 타이머로 상태 업데이트
            self.qt_timer = QTimer()
            self.qt_timer.timeout.connect(self.update_pyqt_perfect_status)
            self.qt_timer.start(5000)  # 5초마다 업데이트
            
            # 창 표시
            self.qt_widget.show()
            
            # 초기 상태 업데이트 및 크기 조정
            self.update_pyqt_perfect_status()
            
            # 클릭 이벤트 처리를 위한 전역 마우스 리스너 설정 (click_status 모드용)
            self.setup_pyqt_click_listener(x, y, width, height)
            
            # tkinter 창은 None으로 설정 (PyQt 사용 중임을 표시)
            self.status_window = None
            self.status_label = self.qt_label  # 호환성을 위해
            
            logger.info("Perfect PyQt5 click-through window created successfully")
            logger.info("Window should be visible but completely click-through")
            
        except ImportError:
            logger.error("PyQt5 not available, falling back to auto-hide")
            self.create_auto_hide_window(x, y, width, height)
        except Exception as e:
            logger.error(f"Perfect PyQt window creation failed: {e}")
            import traceback
            traceback.print_exc()
            self.create_auto_hide_window(x, y, width, height)
    
    def update_pyqt_perfect_status(self):
        """완벽한 PyQt 창의 상태 업데이트"""
        try:
            if hasattr(self, 'qt_label') and self.qt_label:
                is_connected = self.check_internet_connection()
                
                if is_connected:
                    network_info = self.get_network_info()
                    status_text = f"🟢 온라인 - {network_info}"
                else:
                    status_text = "🔴 오프라인"
                
                self.qt_label.setText(status_text)
                
                # 텍스트에 맞게 창 크기 자동 조정
                self.adjust_window_size()
                
        except Exception as e:
            logger.error(f"Perfect PyQt status update error: {e}")
    
    def adjust_window_size(self):
        """텍스트 크기에 맞게 창 크기 조정"""
        try:
            if hasattr(self, 'qt_label') and hasattr(self, 'qt_widget'):
                from PyQt5.QtCore import Qt
                
                # 텍스트 크기 측정
                font_metrics = self.qt_label.fontMetrics()
                try:
                    # PyQt5.15+ 사용
                    text_width = font_metrics.horizontalAdvance(self.qt_label.text())
                except AttributeError:
                    # 구버전 PyQt5 사용
                    text_width = font_metrics.width(self.qt_label.text())
                text_height = font_metrics.height()
                
                # 패딩 추가 (좌우 16px, 상하 16px)
                widget_width = text_width + 16
                widget_height = max(text_height + 16, 80)  # 최소 높이 80
                
                # 창 크기 조정
                self.qt_widget.resize(widget_width, widget_height)
                
                # 오른쪽 정렬을 위해 x 좌표 재계산 (편집모드, 드래그 중, 사용자가 이미 이동한 경우에는 비활성화)
                if hasattr(self, 'initial_x') and not self.edit_mode and not getattr(self, 'is_dragging', False) and not getattr(self, 'user_has_moved', False):
                    screen_width = self.qt_widget.screen().geometry().width()
                    new_x = screen_width - widget_width - 5
                    self.qt_widget.move(new_x, self.qt_widget.y())
                
        except Exception as e:
            logger.error(f"Window size adjustment error: {e}")
    
    def setup_pyqt_click_listener(self, x, y, width, height):
        """PyQt 클릭 통과 창에 대한 클릭 이벤트 리스너 설정"""
        try:
            # 현재 실행키 설정이 click_status인지 확인
            hotkey_type = load_data('hotkey_type', 'mouse_wheel')
            if hotkey_type != 'click_status':
                logger.info(f"PyQt click listener not needed for hotkey type: {hotkey_type}")
                return
            
            # 기존 PyQt 클릭 리스너가 있으면 먼저 정리
            if hasattr(self, 'pyqt_mouse_listener'):
                try:
                    self.pyqt_mouse_listener.stop()
                    delattr(self, 'pyqt_mouse_listener')
                    logger.info("Existing PyQt mouse listener cleaned up")
                except:
                    pass
            
            # pynput을 사용한 전역 마우스 클릭 리스너 설정
            try:
                from pynput import mouse as pynput_mouse
                
                def on_click(mouse_x, mouse_y, button, pressed):
                    # 왼쪽 버튼 클릭이고 눌렀을 때만 처리
                    if button == pynput_mouse.Button.left and pressed:
                        # 클릭 위치가 상태창 영역 내인지 확인
                        if hasattr(self, 'qt_widget') and self.qt_widget:
                            # PyQt 창의 현재 위치와 크기 가져오기
                            widget_x = self.qt_widget.x()
                            widget_y = self.qt_widget.y()
                            widget_width = self.qt_widget.width()
                            widget_height = self.qt_widget.height()
                            
                            # 클릭이 창 영역 내에 있는지 확인
                            if (widget_x <= mouse_x <= widget_x + widget_width and 
                                widget_y <= mouse_y <= widget_y + widget_height):
                                # 라디얼 메뉴 직접 생성 (더 정확한 위치 제어)
                                try:
                                    # 중복 클릭 방지 (PyQt 리스너용) - 시간 단축
                                    import time
                                    current_time = time.time()
                                    if hasattr(self, '_last_pyqt_click_time') and current_time - self._last_pyqt_click_time < 0.2:
                                        logger.info("Ignoring duplicate PyQt click within 200ms")
                                        return
                                    self._last_pyqt_click_time = current_time
                                    
                                    # 상태창 중앙 위치 계산
                                    center_x = widget_x + widget_width // 2
                                    center_y = widget_y + widget_height // 2
                                    
                                    # 설정 창이 열려있는지 확인
                                    if hasattr(self, 'radial_menu') and self.radial_menu and hasattr(self.radial_menu, 'settings_window'):
                                        settings_window = self.radial_menu.settings_window
                                        if hasattr(settings_window, 'settings_root') and settings_window.settings_root and settings_window.settings_root.winfo_exists():
                                            logger.info("Settings window is open - ignoring status click")
                                            return
                                    
                                    # 설정 버튼 클릭 직후 1초간 무시
                                    if hasattr(self, '_settings_button_clicked_time'):
                                        import time
                                        if time.time() - self._settings_button_clicked_time < 1.0:
                                            logger.info("Settings button recently clicked - ignoring status click")
                                            return
                                    
                                    # 편집 모드 활성화 시 클릭 무시
                                    if hasattr(self, 'edit_mode') and self.edit_mode:
                                        logger.info("Edit mode is active - ignoring status click")
                                        return
                                    
                                    # 라디얼 메뉴가 이미 열려있으면 클릭 무시 (중복 방지)
                                    if hasattr(self, 'radial_menu') and self.radial_menu and hasattr(self.radial_menu, 'overlay') and self.radial_menu.overlay:
                                        logger.info("Radial menu already open - ignoring status click")
                                        return
                                    
                                    # 라디얼 메뉴 활성 플래그 확인 (추가 보안)
                                    if hasattr(self, '_radial_menu_active') and self._radial_menu_active:
                                        logger.info("Radial menu active flag is set - ignoring status click")
                                        return
                                    
                                    # 실시간 실행키 설정 재확인 (설정 변경 반영)
                                    current_hotkey = load_data('hotkey_type', 'mouse_wheel')
                                    if current_hotkey != 'click_status':
                                        logger.info(f"Hotkey changed from click_status to {current_hotkey} - ignoring PyQt status click")
                                        return
                                    
                                    # 라디얼 메뉴 생성
                                    if hasattr(self, 'radial_menu') and self.radial_menu:
                                        logger.info(f"PyQt status window clicked - opening radial menu at center ({center_x}, {center_y})")
                                        # 메뉴가 이미 열려있는지 확인
                                        if hasattr(self.radial_menu, 'overlay') and self.radial_menu.overlay:
                                            logger.info("Menu already open - will close and reopen at new position")
                                        try:
                                            self.radial_menu.create_menu(center_x, center_y)
                                            logger.info("PyQt radial menu create_menu called successfully")
                                            # 메뉴가 실제로 생성되었는지 확인
                                            if hasattr(self.radial_menu, 'overlay') and self.radial_menu.overlay:
                                                logger.info("Menu successfully created and displayed")
                                            else:
                                                logger.warning("Menu create_menu called but overlay not found")
                                        except Exception as menu_error:
                                            logger.error(f"Error in create_menu: {menu_error}")
                                            import traceback
                                            traceback.print_exc()
                                    else:
                                        logger.error(f"Radial menu not available - hasattr: {hasattr(self, 'radial_menu')}, radial_menu: {getattr(self, 'radial_menu', None)}")
                                except Exception as e:
                                    logger.error(f"Error handling PyQt status click: {e}")
                
                # 리스너 생성 및 시작
                self.pyqt_mouse_listener = pynput_mouse.Listener(on_click=on_click)
                self.pyqt_mouse_listener.start()
                
                logger.info("PyQt click listener setup completed")
                
            except ImportError:
                logger.warning("pynput not available for PyQt click detection")
                
        except Exception as e:
            logger.error(f"PyQt click listener setup error: {e}")
    
    def create_autohotkey_style_window(self, x, y, width, height):
        """오토핫키 스타일 창 생성 - +LastFound +AlwaysOnTop -Caption +ToolWindow 구현"""
        try:
            import ctypes
            from ctypes import wintypes
            
            # tkinter 창 생성
            self.status_window = tk.Toplevel()
            self.status_window.overrideredirect(True)  # -Caption (타이틀바 제거)
            self.status_window.attributes('-topmost', True)  # +AlwaysOnTop
            self.status_window.attributes('-alpha', 0.85)
            self.status_window.configure(bg='#2c3e50')
            
            self.status_window.geometry(f"{width}x{height}+{x}+{y}")
            
            # 상태 표시 라벨
            self.status_label = tk.Label(
                self.status_window,
                text="인터넷 상태 확인 중...",
                bg='#2c3e50',
                fg='white',
                font=('Arial', 9),
                justify='left',
                anchor='w'
            )
            self.status_label.pack(fill=tk.BOTH, expand=True, padx=8, pady=8)
            
            # 창이 완전히 생성된 후 Windows API 적용
            self.status_window.after(200, lambda: self.apply_autohotkey_style())
            self.status_window.after(1000, lambda: self.verify_and_reapply_style())
            
            logger.info("AutoHotkey style window created")
            
        except Exception as e:
            logger.error(f"AutoHotkey style window creation failed: {e}")
            # 실패시 자동 숨김 창으로 대체
            self.create_auto_hide_window(x, y, width, height)
    
    def apply_autohotkey_style(self):
        """오토핫키 스타일 적용 - 단순하고 확실한 방식"""
        if platform.system() != "Windows":
            return
            
        try:
            import ctypes
            
            # 윈도우 핸들 가져오기
            hwnd = self.status_window.winfo_id()
            
            # Windows API 상수
            GWL_EXSTYLE = -20
            WS_EX_LAYERED = 0x00080000
            WS_EX_TRANSPARENT = 0x00000020
            WS_EX_NOACTIVATE = 0x08000000
            WS_EX_TOOLWINDOW = 0x00000080
            
            # 현재 Extended Style 가져오기
            current_style = ctypes.windll.user32.GetWindowLongW(hwnd, GWL_EXSTYLE)
            
            # 새로운 스타일 = 기존 + 필요한 플래그들
            new_style = (current_style | 
                        WS_EX_LAYERED | 
                        WS_EX_TRANSPARENT | 
                        WS_EX_NOACTIVATE | 
                        WS_EX_TOOLWINDOW)
            
            # Extended Style 적용
            result = ctypes.windll.user32.SetWindowLongW(hwnd, GWL_EXSTYLE, new_style)
            
            if result:
                # 투명도 설정
                LWA_ALPHA = 0x00000002
                ctypes.windll.user32.SetLayeredWindowAttributes(
                    hwnd, 0, int(255 * 0.9), LWA_ALPHA  # 90% 불투명도로 증가
                )
                
                # 최상위 유지
                HWND_TOPMOST = -1
                SWP_NOMOVE = 0x0002
                SWP_NOSIZE = 0x0001
                SWP_NOACTIVATE = 0x0010
                
                ctypes.windll.user32.SetWindowPos(
                    hwnd, HWND_TOPMOST, 0, 0, 0, 0,
                    SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE
                )
                
                logger.info("Simple AutoHotkey style applied successfully")
                logger.info("Click-through should now work properly")
            else:
                logger.error("Failed to apply window styles")
                
        except Exception as e:
            logger.error(f"AutoHotkey style application failed: {e}")
            import traceback
            traceback.print_exc()
    
    def verify_and_reapply_style(self):
        """스타일 검증 및 재적용"""
        if not self.status_window or not self.status_window.winfo_exists():
            return
            
        try:
            import ctypes
            hwnd = self.status_window.winfo_id()
            
            # 현재 스타일 확인
            GWL_EXSTYLE = -20
            current_style = ctypes.windll.user32.GetWindowLongW(hwnd, GWL_EXSTYLE)
            
            WS_EX_TRANSPARENT = 0x00000020
            WS_EX_TOOLWINDOW = 0x00000080
            
            # 필요한 스타일이 적용되어 있는지 확인
            has_transparent = bool(current_style & WS_EX_TRANSPARENT)
            has_toolwindow = bool(current_style & WS_EX_TOOLWINDOW)
            
            if not (has_transparent and has_toolwindow):
                logger.warning("Style verification failed, reapplying...")
                self.apply_autohotkey_style()
            else:
                logger.info("Style verification passed - click-through is active")
                
        except Exception as e:
            logger.error(f"Style verification error: {e}")
    
    
    def create_edit_mode_window(self, x, y, width, height):
        """편집 모드용 창 생성 (드래그 가능)"""
        self.status_window = tk.Toplevel()
        self.status_window.overrideredirect(True)
        self.status_window.attributes('-topmost', True)
        self.status_window.attributes('-alpha', 0.9)
        
        # 편집 모드 시각적 표시
        self.status_window.configure(bg='#e74c3c')  # 빨간색 배경
        
        self.status_window.geometry(f"{width}x{height}+{x}+{y}")
        
        # 상태 표시 라벨
        self.status_label = tk.Label(
            self.status_window,
            text="편집 모드 - 드래그하여 이동",
            bg='#e74c3c',
            fg='white',
            font=('Arial', 9, 'bold'),
            justify='center',
            cursor='hand2'
        )
        self.status_label.pack(fill=tk.BOTH, expand=True, padx=2, pady=2)
        
        # 드래그 이벤트 바인딩
        self.enable_drag_events()
        
        logger.info("Edit mode window created with drag functionality")
    
    def create_click_through_window(self, x, y, width, height):
        """클릭 통과용 창 생성 - 방법 1: 투명색 지정 방식"""
        self.status_window = tk.Toplevel()
        self.status_window.overrideredirect(True)
        self.status_window.attributes('-topmost', True)
        self.status_window.attributes('-alpha', 0.85)
        
        self.status_window.geometry(f"{width}x{height}+{x}+{y}")
        
        if platform.system() == "Windows":
            try:
                # 방법 1: 특정 색상을 투명하게 만들어 클릭 통과 구현
                transparent_color = '#000001'  # 거의 검은색이지만 완전한 검은색은 아님
                self.status_window.configure(bg=transparent_color)
                self.status_window.attributes('-transparentcolor', transparent_color)
                
                # 상태 표시용 프레임 (보이는 부분)
                visible_frame = tk.Frame(
                    self.status_window,
                    bg='#2c3e50',
                    relief='raised',
                    bd=1
                )
                visible_frame.place(x=0, y=0, width=width, height=height)
                
                # 상태 표시 라벨
                self.status_label = tk.Label(
                    visible_frame,
                    text="인터넷 상태 확인 중...",
                    bg='#2c3e50',
                    fg='white',
                    font=('Arial', 9),
                    justify='left',
                    anchor='w'
                )
                self.status_label.pack(fill=tk.BOTH, expand=True, padx=8, pady=8)
                
                # 클릭 통과 설정을 나중에 적용
                self.status_window.after(200, self.apply_windows_click_through)
                
                logger.info("Windows click-through window created with transparent color method")
                
            except Exception as e:
                logger.error(f"Transparent color method failed: {e}")
                # 대안: Win32 API 방식
                self.create_win32_click_through_window(x, y, width, height)
        else:
            # Linux/Mac용 일반 창
            self.status_window.configure(bg='#2c3e50')
            self.status_label = tk.Label(
                self.status_window,
                text="인터넷 상태 확인 중...",
                bg='#2c3e50',
                fg='white',
                font=('Arial', 9),
                justify='left',
                anchor='w'
            )
            self.status_label.pack(fill=tk.BOTH, expand=True, padx=8, pady=8)
    
    def create_win32_click_through_window(self, x, y, width, height):
        """Win32 API를 사용한 클릭 통과 창 생성"""
        try:
            # 일반 창으로 다시 생성
            if self.status_window:
                self.status_window.destroy()
                
            self.status_window = tk.Toplevel()
            self.status_window.overrideredirect(True)
            self.status_window.attributes('-topmost', True)
            self.status_window.attributes('-alpha', 0.85)
            self.status_window.configure(bg='#2c3e50')
            
            self.status_window.geometry(f"{width}x{height}+{x}+{y}")
            
            # 상태 표시 라벨
            self.status_label = tk.Label(
                self.status_window,
                text="인터넷 상태 확인 중...",
                bg='#2c3e50',
                fg='white',
                font=('Arial', 9),
                justify='left',
                anchor='w'
            )
            self.status_label.pack(fill=tk.BOTH, expand=True, padx=8, pady=8)
            
            # Win32 API로 클릭 통과 설정
            self.status_window.after(200, self.apply_win32_click_through)
            
            logger.info("Win32 API click-through window created")
            
        except Exception as e:
            logger.error(f"Win32 click-through window creation failed: {e}")
    
    def apply_win32_click_through(self):
        """Win32 API를 사용한 강화된 클릭 통과"""
        if platform.system() != "Windows":
            return
            
        try:
            import ctypes
            hwnd = self.status_window.winfo_id()
            
            # 다중 방식 시도
            # 방식 1: 기본 투명 설정
            GWL_EXSTYLE = -20
            WS_EX_LAYERED = 0x00080000
            WS_EX_TRANSPARENT = 0x00000020
            WS_EX_NOACTIVATE = 0x08000000
            
            style = ctypes.windll.user32.GetWindowLongW(hwnd, GWL_EXSTYLE)
            new_style = style | WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_NOACTIVATE
            
            result = ctypes.windll.user32.SetWindowLongW(hwnd, GWL_EXSTYLE, new_style)
            
            if result:
                # 방식 2: 창을 최하위로 이동
                HWND_BOTTOM = 1
                SWP_NOSIZE = 0x0001
                SWP_NOMOVE = 0x0002
                SWP_NOACTIVATE = 0x0010
                
                ctypes.windll.user32.SetWindowPos(
                    hwnd, HWND_BOTTOM, 0, 0, 0, 0,
                    SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE
                )
                
                self.click_through_enabled = True
                logger.info("Win32 enhanced click-through applied successfully")
            else:
                logger.error("Failed to apply Win32 click-through")
                
        except Exception as e:
            logger.error(f"Win32 click-through error: {e}")
            # 최후 수단: PyQt 방식 제안
            logger.info("Consider using PyQt for better click-through support")
    
    def create_pyqt_click_through_window(self, x, y, width, height):
        """PyQt 기반 클릭 통과 창 생성"""
        try:
            from PyQt5.QtWidgets import QApplication, QWidget, QLabel
            from PyQt5.QtCore import Qt, QTimer
            from PyQt5.QtGui import QFont
            import sys
            
            # QApplication 인스턴스 확인/생성
            if not QApplication.instance():
                self.qt_app = QApplication(sys.argv)
            else:
                self.qt_app = QApplication.instance()
            
            # PyQt 위젯 생성
            self.qt_widget = QWidget()
            self.qt_widget.setWindowFlags(
                Qt.WindowStaysOnTopHint | 
                Qt.FramelessWindowHint | 
                Qt.Tool |
                Qt.WindowTransparentForInput  # 핵심: 마우스 입력 투과
            )
            
            # 창 크기와 위치 설정
            self.qt_widget.setGeometry(x, y, width, height)
            self.qt_widget.setStyleSheet("""
                QWidget {
                    background-color: rgba(44, 62, 80, 220);
                    border: 1px solid rgba(255, 255, 255, 100);
                    border-radius: 5px;
                }
            """)
            
            # 라벨 생성
            self.qt_label = QLabel("인터넷 상태 확인 중...", self.qt_widget)
            self.qt_label.setStyleSheet("""
                QLabel {
                    color: white;
                    background-color: transparent;
                    padding: 8px;
                }
            """)
            self.qt_label.setFont(QFont("Arial", 9))
            self.qt_label.setGeometry(0, 0, width, height)
            self.qt_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
            
            # 타이머로 상태 업데이트
            self.qt_timer = QTimer()
            self.qt_timer.timeout.connect(self.update_pyqt_status)
            self.qt_timer.start(5000)  # 5초마다 업데이트
            
            # 창 표시
            self.qt_widget.show()
            
            # tkinter 창은 None으로 설정 (PyQt 사용 중임을 표시)
            self.status_window = None
            self.status_label = self.qt_label  # 호환성을 위해
            
            logger.info("PyQt click-through window created successfully")
            
        except ImportError:
            logger.error("PyQt5 not available, falling back to tkinter")
            self.create_win32_click_through_window(x, y, width, height)
        except Exception as e:
            logger.error(f"PyQt window creation failed: {e}")
            self.create_win32_click_through_window(x, y, width, height)
    
    def update_pyqt_status(self):
        """PyQt 창의 상태 업데이트"""
        try:
            if hasattr(self, 'qt_label') and self.qt_label:
                is_connected = self.check_internet_connection()
                
                if is_connected:
                    network_info = self.get_network_info()
                    status_text = f"🟢 온라인 - {network_info}"
                else:
                    status_text = "🔴 오프라인"
                
                self.qt_label.setText(status_text)
                
        except Exception as e:
            logger.error(f"PyQt status update error: {e}")
    
    def create_pysimplegui_window(self, x, y, width, height):
        """PySimpleGUI 방식 클릭 통과 창 생성"""
        try:
            import PySimpleGUI as sg
            import threading
            
            # PySimpleGUI 테마 설정
            sg.theme('DarkBlue3')
            
            # 투명 레이아웃 생성
            layout = [
                [sg.Text('인터넷 상태 확인 중...', 
                        key='-STATUS-',
                        background_color='#2c3e50',
                        text_color='white',
                        font=('Arial', 9),
                        size=(25, 3),
                        justification='left')]
            ]
            
            # 창 생성 - 클릭 통과 설정
            self.sg_window = sg.Window(
                'Status',
                layout,
                location=(x, y),
                size=(width, height),
                no_titlebar=True,
                keep_on_top=True,
                alpha_channel=0.85,
                grab_anywhere=False,
                background_color='#2c3e50',
                margins=(8, 8),
                element_padding=(0, 0),
                finalize=True,
                transparent_color='#000001'  # 특정 색상을 투명하게 만듦
            )
            
            # Windows에서 클릭 통과 설정
            if platform.system() == "Windows":
                try:
                    import ctypes
                    hwnd = self.sg_window.TKroot.winfo_id()
                    
                    # Win32 API로 클릭 통과 설정
                    GWL_EXSTYLE = -20
                    WS_EX_LAYERED = 0x00080000
                    WS_EX_TRANSPARENT = 0x00000020
                    
                    style = ctypes.windll.user32.GetWindowLongW(hwnd, GWL_EXSTYLE)
                    new_style = style | WS_EX_LAYERED | WS_EX_TRANSPARENT
                    
                    ctypes.windll.user32.SetWindowLongW(hwnd, GWL_EXSTYLE, new_style)
                    logger.info("PySimpleGUI click-through applied")
                    
                except Exception as e:
                    logger.error(f"PySimpleGUI click-through failed: {e}")
            
            # 비동기 업데이트 스레드 시작
            self.sg_running = True
            self.sg_thread = threading.Thread(target=self.run_pysimplegui_loop, daemon=True)
            self.sg_thread.start()
            
            # tkinter 창은 None으로 설정
            self.status_window = None
            self.status_label = None
            
            logger.info("PySimpleGUI window created successfully")
            
        except ImportError:
            logger.error("PySimpleGUI not available, falling back")
            self.create_win32_click_through_window(x, y, width, height)
        except Exception as e:
            logger.error(f"PySimpleGUI window creation failed: {e}")
            self.create_win32_click_through_window(x, y, width, height)
    
    def run_pysimplegui_loop(self):
        """PySimpleGUI 이벤트 루프"""
        try:
            while self.sg_running and hasattr(self, 'sg_window'):
                event, values = self.sg_window.read(timeout=5000)  # 5초 타임아웃
                
                if event in (None, sg.WIN_CLOSED):
                    break
                
                # 상태 업데이트
                if self.sg_running:
                    self.update_pysimplegui_status()
                    
        except Exception as e:
            logger.error(f"PySimpleGUI loop error: {e}")
        finally:
            if hasattr(self, 'sg_window'):
                try:
                    self.sg_window.close()
                except:
                    pass
    
    def update_pysimplegui_status(self):
        """PySimpleGUI 상태 업데이트"""
        try:
            if hasattr(self, 'sg_window') and self.sg_window:
                is_connected = self.check_internet_connection()
                
                if is_connected:
                    network_info = self.get_network_info()
                    status_text = f"🟢 온라인 - {network_info}"
                else:
                    status_text = "🔴 오프라인"
                
                self.sg_window['-STATUS-'].update(status_text)
                
        except Exception as e:
            logger.error(f"PySimpleGUI status update error: {e}")
    
    def create_qt_transparent_window(self, x, y, width, height):
        """Qt WA_TransparentForMouseEvents 방식"""
        try:
            from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout
            from PyQt5.QtCore import Qt, QTimer
            from PyQt5.QtGui import QFont
            import sys
            
            # QApplication 인스턴스 확인/생성
            if not QApplication.instance():
                self.qt_app = QApplication(sys.argv)
            else:
                self.qt_app = QApplication.instance()
            
            # Qt 위젯 생성
            self.qt_widget = QWidget()
            
            # 핵심: WA_TransparentForMouseEvents 설정
            self.qt_widget.setAttribute(Qt.WA_TransparentForMouseEvents, True)
            
            # 추가 윈도우 플래그
            self.qt_widget.setWindowFlags(
                Qt.WindowStaysOnTopHint | 
                Qt.FramelessWindowHint | 
                Qt.Tool
            )
            
            # 창 설정
            self.qt_widget.setGeometry(x, y, width, height)
            self.qt_widget.setStyleSheet("""
                QWidget {
                    background-color: rgba(44, 62, 80, 200);
                    border: 1px solid rgba(255, 255, 255, 80);
                    border-radius: 8px;
                }
            """)
            
            # 레이아웃 생성
            layout = QVBoxLayout()
            layout.setContentsMargins(8, 8, 8, 8)
            
            # 라벨 생성
            self.qt_label = QLabel("인터넷 상태 확인 중...")
            self.qt_label.setStyleSheet("""
                QLabel {
                    color: white;
                    background-color: transparent;
                    font-size: 9pt;
                }
            """)
            self.qt_label.setFont(QFont("Arial", 9))
            self.qt_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
            self.qt_label.setWordWrap(False)
            
            layout.addWidget(self.qt_label)
            self.qt_widget.setLayout(layout)
            
            # 타이머로 상태 업데이트
            self.qt_timer = QTimer()
            self.qt_timer.timeout.connect(self.update_pyqt_status)
            self.qt_timer.start(5000)
            
            # 창 표시
            self.qt_widget.show()
            
            # tkinter 창은 None으로 설정
            self.status_window = None
            self.status_label = self.qt_label
            
            logger.info("Qt WA_TransparentForMouseEvents window created successfully")
            
        except ImportError:
            logger.error("PyQt5 not available for Qt transparent method")
            self.create_win32_click_through_window(x, y, width, height)
        except Exception as e:
            logger.error(f"Qt transparent window creation failed: {e}")
            self.create_win32_click_through_window(x, y, width, height)
    
    def create_auto_hide_window(self, x, y, width, height):
        """자동 숨김 방식 - 마우스가 근처에 오면 숨기기"""
        try:
            self.status_window = tk.Toplevel()
            self.status_window.overrideredirect(True)
            self.status_window.attributes('-topmost', True)
            self.status_window.attributes('-alpha', 0.9)
            self.status_window.configure(bg='#2c3e50')
            
            self.status_window.geometry(f"{width}x{height}+{x}+{y}")
            
            # 상태 표시 라벨
            self.status_label = tk.Label(
                self.status_window,
                text="인터넷 상태 확인 중...",
                bg='#2c3e50',
                fg='white',
                font=('Arial', 9),
                justify='left',
                anchor='w'
            )
            self.status_label.pack(fill=tk.BOTH, expand=True, padx=8, pady=8)
            
            # 클릭 이벤트 바인딩 (non-edit mode)
            self.status_label.bind('<Button-1>', self.on_status_click)
            self.status_window.bind('<Button-1>', self.on_status_click)
            
            # 마우스 추적 시작
            self.mouse_check_active = True
            self.check_mouse_position()
            
            logger.info("Auto-hide window created")
            
        except Exception as e:
            logger.error(f"Auto-hide window creation failed: {e}")
    
    def check_mouse_position(self):
        """마우스 위치 확인하여 자동 숨김/표시"""
        if not self.mouse_check_active or not self.status_window:
            return
            
        try:
            import mouse
            mouse_x, mouse_y = mouse.get_position()
            
            # 창 위치와 크기 가져오기
            win_x = self.status_window.winfo_x()
            win_y = self.status_window.winfo_y()
            win_width = self.status_window.winfo_width()
            win_height = self.status_window.winfo_height()
            
            # 마우스가 창 근처(50픽셀 이내)에 있는지 확인
            margin = 50
            near_window = (
                mouse_x >= win_x - margin and mouse_x <= win_x + win_width + margin and
                mouse_y >= win_y - margin and mouse_y <= win_y + win_height + margin
            )
            
            if near_window:
                # 마우스가 가까이 있으면 창 숨기기
                if self.status_window.winfo_viewable():
                    self.status_window.withdraw()
                    logger.debug("Window hidden due to nearby mouse")
            else:
                # 마우스가 멀리 있으면 창 표시
                if not self.status_window.winfo_viewable():
                    self.status_window.deiconify()
                    logger.debug("Window shown, mouse moved away")
            
            # 100ms 후 다시 확인
            self.status_window.after(100, self.check_mouse_position)
            
        except Exception as e:
            logger.error(f"Mouse position check error: {e}")
            # 오류 발생시 1초 후 다시 시도
            if self.status_window:
                self.status_window.after(1000, self.check_mouse_position)
    
    def create_minimal_dot_window(self, x, y):
        """최소 침입 방식 - 작은 점으로 표시, 호버시 확대"""
        try:
            # 작은 점 창 생성
            self.status_window = tk.Toplevel()
            self.status_window.overrideredirect(True)
            self.status_window.attributes('-topmost', True)
            self.status_window.attributes('-alpha', 0.7)
            self.status_window.configure(bg='#2c3e50')
            
            # 작은 크기로 시작 (20x20)
            self.dot_size = 20
            self.expanded_size = (200, 80)
            self.is_expanded = False
            
            self.status_window.geometry(f"{self.dot_size}x{self.dot_size}+{x}+{y}")
            
            # 점 표시 (원형)
            self.dot_canvas = tk.Canvas(
                self.status_window,
                width=self.dot_size,
                height=self.dot_size,
                bg='#2c3e50',
                highlightthickness=0
            )
            self.dot_canvas.pack()
            
            # 원형 점 그리기
            self.dot_canvas.create_oval(2, 2, 18, 18, fill='#27ae60', outline='white', width=1)
            
            # 마우스 이벤트 바인딩
            self.status_window.bind('<Enter>', self.expand_dot)
            self.status_window.bind('<Leave>', self.shrink_dot)
            self.dot_canvas.bind('<Enter>', self.expand_dot)
            self.dot_canvas.bind('<Leave>', self.shrink_dot)
            
            logger.info("Minimal dot window created")
            
        except Exception as e:
            logger.error(f"Minimal dot window creation failed: {e}")
    
    def expand_dot(self, event):
        """점을 확대하여 상태 정보 표시"""
        if self.is_expanded:
            return
            
        try:
            self.is_expanded = True
            
            # 창 크기 확대
            width, height = self.expanded_size
            x = self.status_window.winfo_x()
            y = self.status_window.winfo_y() - (height - self.dot_size) // 2
            
            self.status_window.geometry(f"{width}x{height}+{x}+{y}")
            
            # 캔버스 제거하고 라벨 생성
            self.dot_canvas.destroy()
            
            self.status_label = tk.Label(
                self.status_window,
                text="인터넷 상태 확인 중...",
                bg='#2c3e50',
                fg='white',
                font=('Arial', 9),
                justify='left',
                anchor='w'
            )
            self.status_label.pack(fill=tk.BOTH, expand=True, padx=8, pady=8)
            
            # 상태 업데이트
            self.update_minimal_status()
            
        except Exception as e:
            logger.error(f"Dot expansion error: {e}")
    
    def shrink_dot(self, event):
        """점을 다시 작게 만들기"""
        if not self.is_expanded:
            return
            
        try:
            self.is_expanded = False
            
            # 창 크기 축소
            x = self.status_window.winfo_x()
            y = self.status_window.winfo_y() + (self.expanded_size[1] - self.dot_size) // 2
            
            self.status_window.geometry(f"{self.dot_size}x{self.dot_size}+{x}+{y}")
            
            # 라벨 제거하고 캔버스 다시 생성
            if hasattr(self, 'status_label') and self.status_label:
                self.status_label.destroy()
            
            self.dot_canvas = tk.Canvas(
                self.status_window,
                width=self.dot_size,
                height=self.dot_size,
                bg='#2c3e50',
                highlightthickness=0
            )
            self.dot_canvas.pack()
            
            # 상태에 따라 색상 변경
            color = '#27ae60'  # 기본 녹색
            try:
                if self.check_internet_connection():
                    color = '#27ae60'  # 녹색 (온라인)
                else:
                    color = '#e74c3c'  # 빨간색 (오프라인)
            except:
                color = '#f39c12'  # 주황색 (확인 불가)
            
            self.dot_canvas.create_oval(2, 2, 18, 18, fill=color, outline='white', width=1)
            self.dot_canvas.bind('<Enter>', self.expand_dot)
            
        except Exception as e:
            logger.error(f"Dot shrinking error: {e}")
    
    def update_minimal_status(self):
        """최소 점 모드의 상태 업데이트"""
        if self.is_expanded and hasattr(self, 'status_label') and self.status_label:
            try:
                is_connected = self.check_internet_connection()
                
                if is_connected:
                    network_info = self.get_network_info()
                    status_text = f"🟢 온라인 - {network_info}"
                else:
                    status_text = "🔴 오프라인"
                
                self.status_label.config(text=status_text)
                
            except Exception as e:
                logger.error(f"Minimal status update error: {e}")
    
    def create_sliding_panel_window(self):
        """슬라이딩 패널 방식 - 화면 가장자리에서 슬라이드"""
        try:
            # 화면 가장자리에 숨겨진 패널 생성
            screen_width = tk._default_root.winfo_screenwidth()
            screen_height = tk._default_root.winfo_screenheight()
            
            panel_width = 250
            panel_height = 100
            
            self.status_window = tk.Toplevel()
            self.status_window.overrideredirect(True)
            self.status_window.attributes('-topmost', True)
            self.status_window.attributes('-alpha', 0.95)
            self.status_window.configure(bg='#34495e')
            
            # 초기에는 화면 오른쪽 밖에 숨김
            self.hidden_x = screen_width
            self.visible_x = screen_width - panel_width
            self.panel_y = screen_height - panel_height - 100
            
            self.status_window.geometry(f"{panel_width}x{panel_height}+{self.hidden_x}+{self.panel_y}")
            
            # 패널 내용
            self.status_label = tk.Label(
                self.status_window,
                text="← 마우스를 가져다 대세요",
                bg='#34495e',
                fg='white',
                font=('Arial', 10),
                justify='center'
            )
            self.status_label.pack(expand=True, fill=tk.BOTH, padx=10, pady=10)
            
            # 트리거 영역 생성 (화면 가장자리)
            self.create_trigger_area()
            
            self.is_panel_visible = False
            
            logger.info("Sliding panel window created")
            
        except Exception as e:
            logger.error(f"Sliding panel creation failed: {e}")
    
    def create_trigger_area(self):
        """마우스 트리거 영역 생성"""
        try:
            screen_width = tk._default_root.winfo_screenwidth()
            screen_height = tk._default_root.winfo_screenheight()
            
            # 화면 오른쪽 가장자리에 얇은 트리거 영역
            self.trigger_window = tk.Toplevel()
            self.trigger_window.overrideredirect(True)
            self.trigger_window.attributes('-topmost', True)
            self.trigger_window.attributes('-alpha', 0.01)  # 거의 투명
            self.trigger_window.configure(bg='black')
            
            trigger_width = 5
            trigger_height = 200
            trigger_x = screen_width - trigger_width
            trigger_y = screen_height - trigger_height - 100
            
            self.trigger_window.geometry(f"{trigger_width}x{trigger_height}+{trigger_x}+{trigger_y}")
            
            # 마우스 이벤트 바인딩
            self.trigger_window.bind('<Enter>', self.show_panel)
            self.status_window.bind('<Leave>', self.hide_panel)
            
        except Exception as e:
            logger.error(f"Trigger area creation failed: {e}")
    
    def show_panel(self, event):
        """패널 표시"""
        if self.is_panel_visible:
            return
            
        try:
            self.is_panel_visible = True
            self.slide_panel_in()
            
            # 상태 정보 업데이트
            is_connected = self.check_internet_connection()
            if is_connected:
                network_info = self.get_network_info()
                status_text = f"🟢 온라인\n{network_info}"
            else:
                status_text = "🔴 오프라인"
            
            self.status_label.config(text=status_text)
            
        except Exception as e:
            logger.error(f"Panel show error: {e}")
    
    def hide_panel(self, event):
        """패널 숨기기"""
        if not self.is_panel_visible:
            return
            
        # 마우스가 실제로 패널을 벗어났는지 확인
        try:
            mouse_x = event.x_root
            mouse_y = event.y_root
            
            # 패널 영역 확인
            panel_x = self.status_window.winfo_x()
            panel_y = self.status_window.winfo_y()
            panel_width = self.status_window.winfo_width()
            panel_height = self.status_window.winfo_height()
            
            if (mouse_x < panel_x or mouse_x > panel_x + panel_width or
                mouse_y < panel_y or mouse_y > panel_y + panel_height):
                
                self.is_panel_visible = False
                self.slide_panel_out()
                
        except Exception as e:
            logger.error(f"Panel hide error: {e}")
    
    def slide_panel_in(self):
        """패널 슬라이드 인 애니메이션"""
        try:
            current_x = self.status_window.winfo_x()
            if current_x > self.visible_x:
                new_x = max(self.visible_x, current_x - 20)
                self.status_window.geometry(f"+{new_x}+{self.panel_y}")
                self.status_window.after(20, self.slide_panel_in)
                
        except Exception as e:
            logger.error(f"Slide in error: {e}")
    
    def slide_panel_out(self):
        """패널 슬라이드 아웃 애니메이션"""
        try:
            current_x = self.status_window.winfo_x()
            if current_x < self.hidden_x:
                new_x = min(self.hidden_x, current_x + 20)
                self.status_window.geometry(f"+{new_x}+{self.panel_y}")
                if new_x < self.hidden_x:
                    self.status_window.after(20, self.slide_panel_out)
                    
        except Exception as e:
            logger.error(f"Slide out error: {e}")
    
    def create_corner_popup_window(self):
        """코너 팝업 방식 - 클릭하면 잠시 표시"""
        try:
            # 코너에 작은 버튼 생성
            screen_width = tk._default_root.winfo_screenwidth()
            screen_height = tk._default_root.winfo_screenheight()
            
            self.corner_button = tk.Toplevel()
            self.corner_button.overrideredirect(True)
            self.corner_button.attributes('-topmost', True)
            self.corner_button.attributes('-alpha', 0.8)
            self.corner_button.configure(bg='#3498db')
            
            button_size = 30
            button_x = screen_width - button_size - 10
            button_y = screen_height - button_size - 100
            
            self.corner_button.geometry(f"{button_size}x{button_size}+{button_x}+{button_y}")
            
            # 버튼 라벨
            button_label = tk.Label(
                self.corner_button,
                text="📶",
                bg='#3498db',
                fg='white',
                font=('Arial', 12),
                cursor='hand2'
            )
            button_label.pack(expand=True)
            
            # 클릭 이벤트
            button_label.bind('<Button-1>', self.show_corner_popup)
            self.corner_button.bind('<Button-1>', self.show_corner_popup)
            
            # 팝업 창은 처음에는 생성하지 않음
            self.popup_window = None
            self.status_window = self.corner_button  # 호환성을 위해
            
            logger.info("Corner popup window created")
            
        except Exception as e:
            logger.error(f"Corner popup creation failed: {e}")
    
    def show_corner_popup(self, event):
        """코너 팝업 표시"""
        try:
            if self.popup_window:
                self.popup_window.destroy()
            
            # 버튼 위치 기준으로 팝업 생성
            button_x = self.corner_button.winfo_x()
            button_y = self.corner_button.winfo_y()
            
            popup_width = 200
            popup_height = 80
            popup_x = button_x - popup_width + 30
            popup_y = button_y - popup_height - 10
            
            self.popup_window = tk.Toplevel()
            self.popup_window.overrideredirect(True)
            self.popup_window.attributes('-topmost', True)
            self.popup_window.attributes('-alpha', 0.95)
            self.popup_window.configure(bg='#2c3e50')
            
            self.popup_window.geometry(f"{popup_width}x{popup_height}+{popup_x}+{popup_y}")
            
            # 상태 정보 표시
            is_connected = self.check_internet_connection()
            if is_connected:
                network_info = self.get_network_info()
                status_text = f"🟢 온라인\n{network_info}"
            else:
                status_text = "🔴 오프라인"
            
            popup_label = tk.Label(
                self.popup_window,
                text=status_text,
                bg='#2c3e50',
                fg='white',
                font=('Arial', 9),
                justify='left',
                anchor='w'
            )
            popup_label.pack(fill=tk.BOTH, expand=True, padx=8, pady=8)
            
            # 3초 후 자동으로 숨김
            self.popup_window.after(3000, self.hide_corner_popup)
            
        except Exception as e:
            logger.error(f"Corner popup show error: {e}")
    
    def hide_corner_popup(self):
        """코너 팝업 숨기기"""
        try:
            if self.popup_window:
                self.popup_window.destroy()
                self.popup_window = None
        except Exception as e:
            logger.error(f"Corner popup hide error: {e}")
    
    def apply_windows_click_through(self):
        """Windows 전용 클릭 통과 적용"""
        if platform.system() != "Windows":
            return
            
        try:
            import ctypes
            hwnd = self.status_window.winfo_id()
            
            # Windows API를 사용한 클릭 통과 설정
            GWL_EXSTYLE = -20
            WS_EX_LAYERED = 0x00080000
            WS_EX_TRANSPARENT = 0x00000020
            
            style = ctypes.windll.user32.GetWindowLongW(hwnd, GWL_EXSTYLE)
            new_style = style | WS_EX_LAYERED | WS_EX_TRANSPARENT
            
            result = ctypes.windll.user32.SetWindowLongW(hwnd, GWL_EXSTYLE, new_style)
            
            if result:
                self.click_through_enabled = True
                logger.info("Windows click-through successfully applied")
            else:
                logger.error("Failed to apply Windows click-through")
                
        except Exception as e:
            logger.error(f"Windows click-through error: {e}")
    
    def set_click_through(self, enable=True):
        """클릭 통과 설정 - Windows 11 호환성 개선"""
        if not self.status_window:
            return
            
        if platform.system() == "Windows":
            try:
                import ctypes
                from ctypes import wintypes
                
                # Windows API 상수
                GWL_EXSTYLE = -20
                WS_EX_LAYERED = 0x00080000
                WS_EX_TRANSPARENT = 0x00000020
                WS_EX_NOACTIVATE = 0x08000000
                WS_EX_TOOLWINDOW = 0x00000080
                
                # 윈도우 핸들 가져오기
                hwnd = self.status_window.winfo_id()
                
                if enable:
                    # 방법 1: 완전한 클릭 통과 모드
                    try:
                        # 기존 스타일 가져오기
                        style = ctypes.windll.user32.GetWindowLongW(hwnd, GWL_EXSTYLE)
                        
                        # 투명 및 비활성화 스타일 적용
                        new_style = style | WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW
                        
                        result = ctypes.windll.user32.SetWindowLongW(hwnd, GWL_EXSTYLE, new_style)
                        
                        # 윈도우를 최하위로 이동하여 다른 창들이 위에 오도록 함
                        HWND_BOTTOM = 1
                        SWP_NOSIZE = 0x0001
                        SWP_NOMOVE = 0x0002
                        SWP_NOACTIVATE = 0x0010
                        
                        ctypes.windll.user32.SetWindowPos(
                            hwnd, HWND_BOTTOM, 0, 0, 0, 0,
                            SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE
                        )
                        
                        # 레이어 속성 설정
                        LWA_ALPHA = 0x00000002
                        ctypes.windll.user32.SetLayeredWindowAttributes(
                            hwnd, 0, int(255 * 0.8), LWA_ALPHA
                        )
                        
                        logger.info("Enhanced click-through enabled - 상태 UI 뒤의 버튼 클릭 가능")
                        
                    except Exception as e:
                        logger.error(f"Enhanced click-through failed, trying alternative: {e}")
                        # 대안: 창을 완전히 숨기고 다시 표시
                        self.hide_and_show_alternative()
                        return
                else:
                    # 클릭 통과 비활성화 - 편집 모드
                    style = ctypes.windll.user32.GetWindowLongW(hwnd, GWL_EXSTYLE)
                    new_style = (style | WS_EX_LAYERED) & ~WS_EX_TRANSPARENT & ~WS_EX_NOACTIVATE
                    
                    ctypes.windll.user32.SetWindowLongW(hwnd, GWL_EXSTYLE, new_style)
                    
                    # 윈도우를 최상위로 이동
                    HWND_TOPMOST = -1
                    SWP_NOSIZE = 0x0001
                    SWP_NOMOVE = 0x0002
                    
                    ctypes.windll.user32.SetWindowPos(
                        hwnd, HWND_TOPMOST, 0, 0, 0, 0,
                        SWP_NOSIZE | SWP_NOMOVE
                    )
                    
                    logger.info("Click-through disabled - 상태 UI 편집 모드")
                
            except Exception as e:
                logger.error(f"Failed to set click-through: {e}")
                import traceback
                traceback.print_exc()
                # 최후의 수단: 윈도우 재생성
                self.recreate_window_as_transparent()
        else:
            logger.info(f"Click-through not supported on {platform.system()}")
    
    def hide_and_show_alternative(self):
        """대안 방법: 창을 숨기고 투명하게 재생성"""
        try:
            if self.status_window:
                # 현재 위치 저장
                x = self.status_window.winfo_x()
                y = self.status_window.winfo_y()
                
                # 창 숨기기
                self.status_window.withdraw()
                
                # 100ms 후 다시 표시
                self.status_window.after(100, lambda: self.show_transparent_window(x, y))
                
        except Exception as e:
            logger.error(f"Hide and show alternative failed: {e}")
    
    def show_transparent_window(self, x, y):
        """투명 창으로 다시 표시"""
        try:
            self.status_window.deiconify()
            self.status_window.geometry(f"+{x}+{y}")
            
            # 다시 투명 설정 시도
            self.status_window.after(50, lambda: self.set_click_through(True))
            
        except Exception as e:
            logger.error(f"Show transparent window failed: {e}")
    
    def recreate_window_as_transparent(self):
        """최후의 수단: 완전히 새로운 투명 창 생성"""
        try:
            logger.info("Recreating window as fully transparent overlay")
            
            # 현재 위치와 설정 저장
            if self.status_window:
                x = self.status_window.winfo_x()
                y = self.status_window.winfo_y()
                text = self.status_label.cget('text') if self.status_label else "상태 확인 중..."
                
                # 기존 창 제거
                self.status_window.destroy()
                
                # 새로운 투명 오버레이 창 생성
                self.status_window = tk.Toplevel()
                self.status_window.overrideredirect(True)
                self.status_window.attributes('-topmost', False)  # 최상위 제거
                self.status_window.attributes('-alpha', 0.7)
                
                # 창 크기와 위치 설정
                self.status_window.geometry(f"200x80+{x}+{y}")
                self.status_window.configure(bg='#2c3e50')
                
                # 라벨 재생성
                self.status_label = tk.Label(
                    self.status_window,
                    text=text,
                    bg='#2c3e50',
                    fg='white',
                    font=('Arial', 9),
                    justify='left',
                    anchor='w'
                )
                self.status_label.pack(fill=tk.BOTH, expand=True, padx=8, pady=8)
                
                # 창을 백그라운드로 이동하여 클릭이 뒤로 전달되도록 함
                self.status_window.lower()
                
                logger.info("Window recreated as background overlay")
                
        except Exception as e:
            logger.error(f"Recreate window failed: {e}")
    
    def apply_initial_click_through(self):
        """초기 클릭 통과 설정 적용"""
        try:
            if self.status_window and self.status_window.winfo_exists():
                self.set_click_through(not self.edit_mode)
                logger.info("Initial click-through setting applied")
            else:
                logger.warning("Status window not available for click-through setting")
        except Exception as e:
            logger.error(f"Failed to apply initial click-through: {e}")
    
    def apply_enhanced_click_through(self):
        """강화된 클릭 통과 설정 적용 (Windows 11 전용)"""
        if platform.system() != "Windows" or self.edit_mode:
            return
            
        try:
            if self.status_window and self.status_window.winfo_exists():
                import ctypes
                
                hwnd = self.status_window.winfo_id()
                
                # 방법 1: 윈도우를 완전히 배경으로 이동
                HWND_BOTTOM = 1
                SWP_NOSIZE = 0x0001
                SWP_NOMOVE = 0x0002
                SWP_NOACTIVATE = 0x0010
                SWP_NOREDRAW = 0x0008
                
                ctypes.windll.user32.SetWindowPos(
                    hwnd, HWND_BOTTOM, 0, 0, 0, 0,
                    SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOREDRAW
                )
                
                # 방법 2: 윈도우를 비활성화
                WS_DISABLED = 0x08000000
                GWL_STYLE = -16
                
                style = ctypes.windll.user32.GetWindowLongW(hwnd, GWL_STYLE)
                ctypes.windll.user32.SetWindowLongW(hwnd, GWL_STYLE, style | WS_DISABLED)
                
                # 방법 3: 마우스 이벤트를 무시하도록 설정
                self.status_window.configure(cursor='')
                if self.status_label:
                    self.status_label.configure(cursor='')
                
                logger.info("Enhanced click-through applied for Windows 11")
                
        except Exception as e:
            logger.error(f"Enhanced click-through failed: {e}")
            # 최후 수단: 창을 숨기고 다시 표시
            try:
                self.status_window.withdraw()
                self.status_window.after(100, self.status_window.deiconify)
                logger.info("Used withdraw/deiconify as fallback")
            except:
                pass
    
    def on_status_click(self, event):
        """상태창 클릭 이벤트 처리"""
        try:
            # 편집 모드일 때는 드래그만 처리
            if self.edit_mode:
                return
            
            # 중복 호출 방지 - 짧은 시간 내 연속 클릭 무시
            import time
            current_time = time.time()
            if hasattr(self, '_last_click_time') and current_time - self._last_click_time < 0.3:
                logger.info("Ignoring duplicate click within 300ms")
                return
            self._last_click_time = current_time
            
            # 설정 창이 열려있는지 확인
            if hasattr(self, 'radial_menu') and self.radial_menu and hasattr(self.radial_menu, 'settings_window'):
                settings_window = self.radial_menu.settings_window
                if hasattr(settings_window, 'settings_root') and settings_window.settings_root and settings_window.settings_root.winfo_exists():
                    logger.info("Settings window is open - ignoring status click")
                    return
            
            # 설정 버튼 클릭 직후 1초간 무시
            if hasattr(self, '_settings_button_clicked_time'):
                import time
                if time.time() - self._settings_button_clicked_time < 1.0:
                    logger.info("Settings button recently clicked - ignoring status click")
                    return
            
            # 편집 모드 활성화 시 클릭 무시 (이미 위에서 확인하지만 추가 보안)
            if self.edit_mode:
                logger.info("Edit mode is active - ignoring status click")
                return
            
            # 라디얼 메뉴가 이미 열려있으면 클릭 무시 (중복 방지)
            if hasattr(self, 'radial_menu') and self.radial_menu and hasattr(self.radial_menu, 'overlay') and self.radial_menu.overlay:
                logger.info("Radial menu already open - ignoring status click")
                return
            
            # 라디얼 메뉴 활성 플래그 확인 (추가 보안)
            if hasattr(self, '_radial_menu_active') and self._radial_menu_active:
                logger.info("Radial menu active flag is set - ignoring status click")
                return
            
            # 클릭으로 실행하는 설정이 활성화된 경우만 처리
            hotkey_type = load_data('hotkey_type', 'mouse_wheel')
            if hotkey_type == 'click_status':
                logger.info("Status window clicked - opening radial menu")
                
                # 마우스 위치 가져오기
                try:
                    # pynput 먼저 시도
                    try:
                        from pynput import mouse as pynput_mouse
                        controller = pynput_mouse.Controller()
                        x, y = controller.position
                    except ImportError:
                        # pynput이 없으면 mouse 라이브러리 사용
                        import mouse
                        x, y = mouse.get_position()
                    
                    # 라디얼 메뉴 생성
                    if hasattr(self, 'radial_menu') and self.radial_menu:
                        self.radial_menu.create_menu(x, y)
                    else:
                        logger.warning("Radial menu not available")
                        
                except Exception as e:
                    logger.error(f"Error opening radial menu from status click: {e}")
                    
        except Exception as e:
            logger.error(f"Status click event error: {e}")

    def enable_drag_events(self):
        """드래그 이벤트 활성화"""
        if self.status_label:
            self.status_label.bind('<Button-1>', self.start_drag)
            self.status_label.bind('<B1-Motion>', self.do_drag)
            self.status_label.bind('<ButtonRelease-1>', self.stop_drag)
            self.status_label.bind('<Enter>', self.on_enter)
            self.status_label.bind('<Leave>', self.on_leave)
        
        if self.status_window:
            self.status_window.bind('<Enter>', self.on_enter)
            self.status_window.bind('<Leave>', self.on_leave)
    
    def disable_drag_events(self):
        """드래그 이벤트 비활성화"""
        if self.status_label:
            self.status_label.unbind('<Button-1>')
            self.status_label.unbind('<B1-Motion>')
            self.status_label.unbind('<ButtonRelease-1>')
            self.status_label.unbind('<Enter>')
            self.status_label.unbind('<Leave>')
        
        if self.status_window:
            self.status_window.unbind('<Enter>')
            self.status_window.unbind('<Leave>')
    
    def set_edit_mode(self, enabled):
        """편집 모드 설정 - 창 재생성 방식"""
        if self.edit_mode == enabled:
            return  # 이미 같은 모드면 무시
            
        self.edit_mode = enabled
        
        # 기존 창이 있으면 위치 저장 후 제거
        if self.status_window:
            try:
                # 창이 여전히 존재하는지 안전하게 확인
                if self.status_window.winfo_exists():
                    x = self.status_window.winfo_x()
                    y = self.status_window.winfo_y()
                    save_data('status_position', (x, y))
                    
                    self.status_window.destroy()
                    
            except Exception as e:
                logger.error(f"Error destroying old window: {e}")
            finally:
                # 오류가 발생하더라도 참조 정리
                self.status_window = None
                self.status_label = None
        
        # 새로운 모드로 창 재생성
        if self.is_visible:
            try:
                self.create_status_window()
            except Exception as e:
                logger.error(f"Error creating status window: {e}")
                # 오류 발생 시 편집 모드 강제 해제
                self.edit_mode = False
            
        logger.info(f"Edit mode {'enabled' if enabled else 'disabled'} - window recreated")
    
    def on_enter(self, event):
        """마우스가 상태 창에 들어올 때"""
        if self.edit_mode and self.status_window:
            self.status_window.configure(cursor='hand2')
        if self.edit_mode and self.status_label:
            self.status_label.configure(cursor='hand2')
    
    def on_leave(self, event):
        """마우스가 상태 창을 벗어날 때"""
        if self.edit_mode and not self.is_dragging:
            if self.status_window:
                self.status_window.configure(cursor='')
            if self.status_label:
                self.status_label.configure(cursor='hand2')
    
    def start_drag(self, event):
        """드래그 시작 또는 클릭 처리"""
        if not self.status_window:
            logger.warning("Cannot process event: window not available")
            return
        
        # 편집 모드가 아니면 클릭 이벤트로 처리
        if not self.edit_mode:
            self.on_status_click(event)
            return
        
        try:
            self.is_dragging = True
            
            # 마우스 위치를 창의 좌상단 기준으로 저장
            self.offset_x = event.x
            self.offset_y = event.y
            
            # 현재 창 위치 저장
            self.drag_start_x = self.status_window.winfo_x()
            self.drag_start_y = self.status_window.winfo_y()
            
            logger.info(f"Drag started - offset: ({self.offset_x}, {self.offset_y}), window: ({self.drag_start_x}, {self.drag_start_y})")
            
            # 드래그 중 커서 변경
            self.status_window.configure(cursor='fleur')
            self.status_label.configure(cursor='fleur')
            
            # 창을 최상위로 올려서 드래그가 잘 보이도록 함
            self.status_window.lift()
            
        except Exception as e:
            logger.error(f"Start drag error: {e}")
            self.is_dragging = False
    
    def do_drag(self, event):
        """드래그 진행 - 개선된 버전"""
        if not self.is_dragging or not self.status_window:
            return
            
        try:
            # 상태 창이 존재하고 유효한지 확인
            if not self.status_window.winfo_exists():
                logger.error("Status window does not exist during drag")
                self.is_dragging = False
                return
            
            # 새 위치 계산 (마우스 루트 좌표 - 오프셋)
            new_x = event.x_root - self.offset_x
            new_y = event.y_root - self.offset_y
            
            # 화면 경계 체크
            screen_width = self.status_window.winfo_screenwidth()
            screen_height = self.status_window.winfo_screenheight()
            
            # 창 크기 고려
            window_width = 350
            window_height = 80
            
            # 경계 제한
            new_x = max(0, min(new_x, screen_width - window_width))
            new_y = max(0, min(new_y, screen_height - window_height))
            
            # 창 이동
            self.status_window.geometry(f"+{new_x}+{new_y}")
            
            logger.debug(f"Dragging to ({new_x}, {new_y})")
            
        except Exception as e:
            logger.error(f"Drag error: {e}")
            import traceback
            traceback.print_exc()
            self.is_dragging = False
    
    def stop_drag(self, event):
        """드래그 종료 - 개선된 버전"""
        if not self.is_dragging:
            return
            
        self.is_dragging = False
        
        try:
            # 현재 위치 저장
            x = self.status_window.winfo_x()
            y = self.status_window.winfo_y()
            save_data('status_position', (x, y))
            logger.info(f"Drag completed - final position: ({x}, {y})")
            
            # 사용자가 수동으로 이동했음을 표시 (더 이상 자동 오른쪽 정렬 안함)
            self.user_has_moved = True
            
            # 설정 창의 위치 라벨 업데이트
            if self.settings_window and hasattr(self.settings_window, 'update_position_label'):
                self.settings_window.update_position_label()
                
        except Exception as e:
            logger.error(f"Stop drag error: {e}")
        
        # 커서를 편집 모드 커서로 복원
        try:
            if self.status_window:
                self.status_window.configure(cursor='hand2')
            if self.status_label:
                self.status_label.configure(cursor='hand2')
        except Exception as e:
            logger.error(f"Cursor restore error: {e}")
        
    def update_status(self):
        """상태 정보 업데이트"""
        if not self.is_visible or not self.status_window:
            return
            
        try:
            if self.edit_mode:
                # 편집 모드에서는 고정 텍스트 표시
                status_text = "편집 모드\n드래그하여 이동"
                if self.status_label and self.status_label.winfo_exists():
                    self.status_label.config(text=status_text)
            else:
                # 일반 모드에서는 네트워크 상태를 백그라운드에서 확인
                def check_network_status():
                    try:
                        # 네트워크 작업을 백그라운드에서 실행
                        is_connected = self.check_internet_connection()
                        
                        if is_connected:
                            network_info = self.get_network_info()
                            status_text = f"🟢 온라인 - {network_info}"
                        else:
                            status_text = "🔴 오프라인"
                        
                        # UI 업데이트는 메인 스레드에서 실행
                        def update_ui():
                            try:
                                if (self.is_visible and self.status_window and self.status_label and 
                                    self.status_label.winfo_exists()):
                                    self.status_label.config(text=status_text)
                            except Exception as e:
                                logger.error(f"UI update error: {e}")
                        
                        self.status_window.after(0, update_ui)
                        
                    except Exception as e:
                        logger.error(f"Background network check error: {e}")
                        # 오류 발생 시 UI 업데이트
                        def update_error_ui():
                            try:
                                if (self.is_visible and self.status_window and self.status_label and 
                                    self.status_label.winfo_exists()):
                                    self.status_label.config(text="❓ 상태 확인 실패")
                            except Exception as e:
                                logger.error(f"Error UI update error: {e}")
                        
                        self.status_window.after(0, update_error_ui)
                
                # 백그라운드 스레드에서 네트워크 작업 실행
                threading.Thread(target=check_network_status, daemon=True).start()
                
        except Exception as e:
            logger.error(f"Status update error: {e}")
            if self.edit_mode:
                self.status_label.config(text="편집 모드\n❗ 오류 발생")
            else:
                self.status_label.config(text="❓ 상태 확인 실패")
        
        # 5초마다 업데이트 (편집 모드에서는 업데이트 빈도 줄임)
        if self.is_visible:
            update_interval = 10000 if self.edit_mode else 5000
            self.status_window.after(update_interval, self.update_status)
    
    def check_internet_connection(self):
        """인터넷 연결 확인 - 향상된 버전"""
        # 먼저 DNS 서버에 socket 연결 시도
        try:
            socket.create_connection(("8.8.8.8", 53), timeout=3)
            return True
        except OSError:
            pass
        
        # socket 실패 시 ping으로 다시 확인
        try:
            result = subprocess.run(
                ["ping", "-n", "1", "8.8.8.8"],
                capture_output=True,
                text=True,
                timeout=5
            )
            return result.returncode == 0
        except Exception as e:
            logger.error(f"Internet connection check error: {e}")
            return False
    
    def get_network_info(self):
        """네트워크 정보 가져오기"""
        try:
            # IP 주소 가져오기
            ip = self.get_local_ip()
            
            # 무선 네트워크 이름 가져오기
            ssid = self.get_wifi_ssid()
            
            if ssid:
                return f"WiFi ({ssid})"
            else:
                return f"유선 연결"
                
        except Exception as e:
            logger.error(f"Network info error: {e}")
            return "네트워크 정보 없음"
    
    def get_local_ip(self):
        """로컬 IP 주소 가져오기"""
        try:
            # Google DNS에 연결하여 로컬 IP 확인
            with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
                s.connect(("8.8.8.8", 80))
                return s.getsockname()[0]
        except:
            return "IP 없음"
    
    def get_wifi_ssid(self):
        """현재 연결된 WiFi SSID 가져오기"""
        try:
            if platform.system() == "Windows":
                # Windows에서 현재 연결된 WiFi 정보 가져오기
                result = subprocess.run(
                    ["netsh", "wlan", "show", "interfaces"],
                    capture_output=True,
                    text=True,
                    encoding='cp949'
                )
                
                if result.returncode == 0:
                    # SSID 추출
                    for line in result.stdout.split('\n'):
                        if 'SSID' in line and 'BSSID' not in line:
                            ssid = line.split(':', 1)[1].strip()
                            if ssid:
                                return ssid
                                
            elif platform.system() == "Darwin":  # macOS
                result = subprocess.run(
                    ["/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport", "-I"],
                    capture_output=True,
                    text=True
                )
                
                if result.returncode == 0:
                    ssid_match = re.search(r'SSID: (.+)', result.stdout)
                    if ssid_match:
                        return ssid_match.group(1).strip()
                        
            elif platform.system() == "Linux":
                # Linux에서 iwgetid 명령어 사용
                result = subprocess.run(
                    ["iwgetid", "-r"],
                    capture_output=True,
                    text=True
                )
                
                if result.returncode == 0:
                    return result.stdout.strip()
                    
        except Exception as e:
            logger.error(f"WiFi SSID error: {e}")
            
        return None
    
    def destroy(self):
        """상태 창 완전히 제거 (스레드 재시작 시 사용)"""
        logger.info("=== Starting StatusWindow.destroy() ===")
        logger.info("Destroying status window completely...")
        
        # 자동 숨김 모드 중지
        if hasattr(self, 'mouse_check_active'):
            self.mouse_check_active = False
        
        # 트리거 창 제거
        if hasattr(self, 'trigger_window') and self.trigger_window:
            try:
                self.trigger_window.destroy()
            except:
                pass
            self.trigger_window = None
        
        # PyQt 위젯 제거 - 강화된 정리
        if hasattr(self, 'qt_widget') and self.qt_widget:
            try:
                # Qt 타이머 정리
                if hasattr(self, 'qt_timer') and self.qt_timer:
                    self.qt_timer.stop()
                    self.qt_timer = None
                
                # Qt 위젯 숨기기 및 닫기
                self.qt_widget.hide()
                self.qt_widget.close()
                
                # Qt 이벤트 루프에서 위젯 완전 제거
                self.qt_widget.deleteLater()
                
                # PyQt 마우스 리스너 정리
                if hasattr(self, 'pyqt_mouse_listener'):
                    try:
                        self.pyqt_mouse_listener.stop()
                        logger.info("PyQt mouse listener stopped during destroy")
                    except:
                        pass
                    self.pyqt_mouse_listener = None
                
                # Qt 애플리케이션 정리
                if hasattr(self, 'qt_app') and self.qt_app:
                    try:
                        self.qt_app.processEvents()  # 펜딩 이벤트 처리
                        self.qt_app.quit()
                    except:
                        pass
                    self.qt_app = None
                    
                logger.info("PyQt widgets cleaned up successfully")
            except Exception as e:
                logger.error(f"Error cleaning up PyQt widgets: {e}")
            finally:
                self.qt_widget = None
                self.qt_app = None
        
        # PySimpleGUI 창 제거
        if hasattr(self, 'sg_window') and self.sg_window:
            try:
                self.sg_window.close()
                self.sg_running = False
            except:
                pass
            self.sg_window = None
        
        # tkinter 창 제거
        if self.status_window:
            try:
                self.status_window.destroy()
            except:
                pass
            self.status_window = None
        
        # 설정 창 제거
        if hasattr(self, 'settings_window') and self.settings_window:
            try:
                self.settings_window.destroy()
            except:
                pass
            self.settings_window = None
        
        # 모든 상태 초기화
        self.status_label = None
        self.is_visible = False
        
        logger.info("Status window destroyed completely")
        logger.info("=== StatusWindow.destroy() completed ===\n")
    
    def hide_status_window(self):
        """상태 창 숨기기"""
        # 자동 숨김 모드 중지
        if hasattr(self, 'mouse_check_active'):
            self.mouse_check_active = False
            
        # 트리거 창 숨기기 (슬라이딩 패널)
        if hasattr(self, 'trigger_window') and self.trigger_window:
            self.trigger_window.destroy()
            self.trigger_window = None
            
        # 코너 버튼 숨기기
        if hasattr(self, 'corner_button') and self.corner_button:
            self.corner_button.destroy()
            self.corner_button = None
            
        # 팝업 창 숨기기
        if hasattr(self, 'popup_window') and self.popup_window:
            self.popup_window.destroy()
            self.popup_window = None
            
        # tkinter 창 숨기기
        if self.status_window:
            self.status_window.destroy()
            self.status_window = None
            self.status_label = None
            
        # PyQt 창 숨기기
        if hasattr(self, 'qt_widget') and self.qt_widget:
            self.qt_widget.hide()
            if hasattr(self, 'qt_timer'):
                self.qt_timer.stop()
            # PyQt 클릭 리스너 정리
            if hasattr(self, 'pyqt_mouse_listener'):
                try:
                    self.pyqt_mouse_listener.stop()
                    logger.info("PyQt mouse listener stopped")
                except:
                    pass
                
        # PySimpleGUI 창 숨기기
        if hasattr(self, 'sg_window') and self.sg_window:
            self.sg_running = False
            try:
                self.sg_window.close()
            except:
                pass
            
        self.is_visible = False
        logger.info("Status window hidden")
    
    def show_status_window(self):
        """상태 창 표시"""
        if not self.is_visible:
            self.create_status_window()
        elif self.status_window and self.status_window.winfo_exists():
            # tkinter 창이 있으면 다시 표시
            self.status_window.deiconify()
            self.status_window.lift()
        elif hasattr(self, 'qt_widget') and self.qt_widget:
            # PyQt 창이 있으면 다시 표시
            self.qt_widget.show()
            if hasattr(self, 'qt_timer'):
                self.qt_timer.start(5000)
        elif hasattr(self, 'sg_window') and self.sg_window:
            # PySimpleGUI 창이 있으면 다시 표시
            try:
                self.sg_window.un_hide()
                self.sg_running = True
            except:
                # 창이 닫혔으면 새로 생성
                self.create_status_window()
        logger.info("Status window shown")


class SettingsWindow:
    def __init__(self, status_window):
        self.settings_window = None
        self.status_window = status_window
        self.status_enabled = load_data('status_enabled', True)
        # 상호 참조 설정
        self.status_window.settings_window = self
        
    def show_settings(self):
        """설정 창 표시"""
        # 기존 설정 창이 있고 유효한지 확인
        if self.settings_window:
            try:
                if self.settings_window.winfo_exists():
                    self.settings_window.lift()
                    # 기존 창이 있는 경우에도 환경 설정 값을 업데이트
                    self.refresh_environment_setting()
                    return
            except:
                # 창이 유효하지 않으면 None으로 설정
                self.settings_window = None
            
        logger.info("Opening settings window...")
        
        # 설정 창이 열릴 때 편집 모드 활성화
        try:
            self.status_window.set_edit_mode(True)
        except Exception as e:
            logger.error(f"Error setting edit mode: {e}")
        
        self.settings_window = tk.Toplevel()
        self.settings_window.title("GeoMedical Helper - 설정")
        self.settings_window.geometry("900x700")  # 웹사이트 추가 부분이 보이도록 초기 크기 조정
        self.settings_window.resizable(False, True)  # 세로 크기 조절 가능
        
        # 메인 캔버스와 스크롤바 생성
        self.canvas = tk.Canvas(self.settings_window)
        scrollbar = ttk.Scrollbar(self.settings_window, orient="vertical", command=self.canvas.yview)
        self.scrollable_frame = ttk.Frame(self.canvas)
        
        self.scrollable_frame.bind(
            "<Configure>",
            lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all"))
        )
        
        self.canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
        self.canvas.configure(yscrollcommand=scrollbar.set)
        
        # 캔버스와 스크롤바 배치
        self.canvas.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")
        
        # 메인 프레임 (이제 스크롤 가능한 프레임 안에)
        main_frame = ttk.Frame(self.scrollable_frame, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 마우스 휠 스크롤 지원
        def _on_mousewheel(event):
            self.canvas.yview_scroll(int(-1*(event.delta/120)), "units")
        
        # 캔버스에 마우스 휠 이벤트 바인딩
        def bind_mousewheel(event):
            self.canvas.bind_all("<MouseWheel>", _on_mousewheel)
        
        def unbind_mousewheel(event):
            self.canvas.unbind_all("<MouseWheel>")
        
        self.canvas.bind('<Enter>', bind_mousewheel)
        self.canvas.bind('<Leave>', unbind_mousewheel)
        
        # 제목
        title_label = ttk.Label(main_frame, text="GeoMedical Helper 설정", font=('Arial', 12, 'bold'))
        title_label.pack(pady=(0, 20))
        
        # 상태 표시 설정
        status_frame = ttk.LabelFrame(main_frame, text="상태 표시", padding="10")
        status_frame.pack(fill=tk.X, pady=(0, 10))
        
        self.status_var = tk.BooleanVar(value=self.status_enabled)
        status_check = ttk.Checkbutton(
            status_frame,
            text="인터넷 상태 표시",
            variable=self.status_var,
            command=self.toggle_status_display
        )
        status_check.pack(anchor=tk.W)
        
        # 설명
        desc_label = ttk.Label(
            status_frame,
            text="• 인터넷 연결 상태, 네트워크 이름, IP 주소를 표시합니다.\n• 오토핫키 스타일 방식으로 완전한 클릭 통과를 구현합니다.\n• 10가지 표시 방식을 지원하여 어떤 환경에서도 작동합니다.",
            font=('Arial', 9),
            foreground='gray'
        )
        desc_label.pack(anchor=tk.W, pady=(5, 0))
        
        # 위치 조정 프레임
        position_frame = ttk.Frame(status_frame)
        position_frame.pack(fill=tk.X, pady=(10, 0))
        
        # 편집 모드 안내
        edit_mode_frame = ttk.Frame(position_frame)
        edit_mode_frame.pack(fill=tk.X, pady=(0, 10))
        
        # 편집 모드 표시
        self.edit_mode_label = ttk.Label(
            edit_mode_frame,
            text="🔓 편집 모드 활성화됨 - 상태 창을 드래그하여 이동 가능",
            font=('Arial', 9, 'bold'),
            foreground='#e74c3c'
        )
        self.edit_mode_label.pack(anchor=tk.W)
        
        # 위치 조정 안내
        position_info = ttk.Label(
            position_frame,
            text="• 상태 창의 빨간 테두리를 드래그하여 위치 조정\n• 설정 창을 닫으면 편집 모드가 해제됩니다\n• 일반 모드에서는 상태 창 뒤의 버튼을 클릭할 수 있습니다",
            font=('Arial', 8),
            foreground='gray'
        )
        position_info.pack(anchor=tk.W, pady=(0, 5))
        
        # 버튼 프레임
        button_frame = ttk.Frame(position_frame)
        button_frame.pack(fill=tk.X)
        
        reset_position_btn = ttk.Button(
            button_frame,
            text="위치 초기화",
            command=self.reset_status_position
        )
        reset_position_btn.pack(side=tk.LEFT)
        
        
        
        
        
        # 현재 위치 표시
        self.position_label = ttk.Label(
            position_frame,
            text="",
            font=('Arial', 8),
            foreground='gray'
        )
        self.position_label.pack(anchor=tk.W, pady=(5, 0))
        
        # 현재 위치 업데이트
        self.update_position_label()
        
        # 실행키 설정 프레임
        hotkey_frame = ttk.LabelFrame(main_frame, text="실행키 설정", padding="10")
        hotkey_frame.pack(fill=tk.X, pady=(10, 10))
        
        # 현재 설정된 실행키 표시
        current_hotkey = load_data('hotkey_type', 'mouse_wheel')
        hotkey_names = {
            'mouse_wheel': '마우스휠 버튼 (기본값)',
            'f1': 'F1 키',
            'f2': 'F2 키', 
            'f3': 'F3 키',
            'f4': 'F4 키',
            'click_status': '상태창 클릭'
        }
        
        # 실행키 선택 드롭다운
        hotkey_select_frame = ttk.Frame(hotkey_frame)
        hotkey_select_frame.pack(fill=tk.X, pady=(0, 10))
        
        hotkey_label = ttk.Label(hotkey_select_frame, text="실행키 선택:", font=('Arial', 9))
        hotkey_label.pack(side=tk.LEFT, padx=(0, 10))
        
        # 드롭다운 콤보박스
        self.hotkey_var = tk.StringVar(value=current_hotkey)
        self.hotkey_combo = ttk.Combobox(
            hotkey_select_frame,
            textvariable=self.hotkey_var,
            values=list(hotkey_names.values()),
            state='readonly',
            width=30
        )
        # 현재 값 설정
        self.hotkey_combo.set(hotkey_names.get(current_hotkey, '마우스휠 버튼 (기본값)'))
        self.hotkey_combo.pack(side=tk.LEFT)
        
        # 변경 이벤트 바인딩
        self.hotkey_combo.bind('<<ComboboxSelected>>', self.on_hotkey_selected)
        
        # 현재 실행키 표시 라벨
        self.current_key_label = ttk.Label(
            hotkey_frame,
            text=f"✓ 현재 활성화된 실행키: {hotkey_names.get(current_hotkey, '마우스휠 버튼')}",
            font=('Arial', 9, 'bold'),
            foreground='#27ae60'
        )
        self.current_key_label.pack(anchor=tk.W, pady=(5, 0))
        
        # 실행키 설명
        hotkey_desc = ttk.Label(
            hotkey_frame,
            text="• 마우스휠 버튼: 마우스 휠을 눌러서 실행 (권장)\n• 키보드: 선택한 키를 눌러서 실행\n• 상태창 클릭: 네트워크 상태 표시창을 클릭하여 실행",
            font=('Arial', 8),
            foreground='gray'
        )
        hotkey_desc.pack(anchor=tk.W, pady=(5, 0))
        
        
        # 사용 환경 선택 그룹
        env_frame = ttk.LabelFrame(main_frame, text="사용 환경", padding="10")
        env_frame.pack(fill=tk.X, pady=(20, 10))
        
        # 저장된 환경 설정을 GUI 표시용으로 변환
        saved_env = load_data('environment', 'office')
        env_display_map = {'office': '사무용', 'field': '현장용'}
        display_value = env_display_map.get(saved_env, '사무용')
        self.env_var = tk.StringVar(value=display_value)
        
        office_radio = ttk.Radiobutton(
            env_frame,
            text="사무용",
            variable=self.env_var,
            value="사무용",
            command=self.on_environment_changed
        )
        office_radio.pack(anchor=tk.W, pady=(0, 5))
        
        field_radio = ttk.Radiobutton(
            env_frame,
            text="현장용",
            variable=self.env_var,
            value="현장용",
            command=self.on_environment_changed
        )
        field_radio.pack(anchor=tk.W)
        
        # 웹사이트 관리 섹션
        website_frame = ttk.LabelFrame(main_frame, text="웹사이트 관리", padding="10")
        website_frame.pack(fill=tk.X, pady=(20, 10))
        
        # 현재 웹사이트 목록 표시
        self.websites_label = ttk.Label(website_frame, text="등록된 웹사이트:", font=('Arial', 10, 'bold'))
        self.websites_label.pack(anchor=tk.W, pady=(0, 5))
        
        # 웹사이트 목록을 표시할 프레임
        self.website_list_frame = ttk.Frame(website_frame)
        self.website_list_frame.pack(fill=tk.X, pady=(0, 10))
        
        # 웹사이트 목록 업데이트
        self.update_website_list()
        
        # 새 웹사이트 추가 섹션
        add_info_label = ttk.Label(website_frame, text="새 웹사이트 추가 (최대 7개까지 가능):", 
                                  font=('Arial', 9), foreground='gray')
        add_info_label.pack(anchor=tk.W, pady=(10, 5))
        
        add_frame = ttk.Frame(website_frame)
        add_frame.pack(fill=tk.X, pady=(0, 0))
        
        # 텍스트 입력
        ttk.Label(add_frame, text="표시 텍스트:").grid(row=0, column=0, sticky=tk.W, padx=(0, 5))
        self.website_text_var = tk.StringVar()
        self.website_text_entry = ttk.Entry(add_frame, textvariable=self.website_text_var, width=15)
        self.website_text_entry.grid(row=0, column=1, padx=(0, 10))
        
        # URL 입력
        ttk.Label(add_frame, text="주소(URL):").grid(row=0, column=2, sticky=tk.W, padx=(0, 5))
        self.website_url_var = tk.StringVar()
        self.website_url_entry = ttk.Entry(add_frame, textvariable=self.website_url_var, width=25)
        self.website_url_entry.grid(row=0, column=3, padx=(0, 10))
        
        # 추가 버튼
        self.add_website_btn = ttk.Button(add_frame, text="추가", command=self.add_website)
        self.add_website_btn.grid(row=0, column=4)
        
        # 창 닫기 이벤트
        self.settings_window.protocol("WM_DELETE_WINDOW", self.close_settings)
        
        # 초기 상태 설정
        if self.status_enabled:
            self.status_window.show_status_window()
        
        # 창 높이를 컨텐츠에 맞게 조절
        self.settings_window.after(100, self.adjust_window_height)  # UI가 완전히 로드된 후 실행
        
    def toggle_status_display(self):
        """상태 표시 토글"""
        self.status_enabled = self.status_var.get()
        save_data('status_enabled', self.status_enabled)
        
        if self.status_enabled:
            self.status_window.show_status_window()
        else:
            self.status_window.hide_status_window()
            
        logger.info(f"Status display toggled: {self.status_enabled}")
    
    def on_environment_changed(self):
        """사용 환경 변경 시 호출"""
        environment_display = self.env_var.get()
        # 한글 표시명을 영문 키로 변환
        environment_map = {'사무용': 'office', '현장용': 'field'}
        environment = environment_map.get(environment_display, 'office')
        save_data('environment', environment)
        logger.info(f"Environment changed to: {environment} ({environment_display})")
    
    def refresh_environment_setting(self):
        """환경 설정값을 최신으로 새로고침"""
        try:
            # 저장된 환경 설정을 다시 읽어와서 GUI에 반영
            saved_env = load_data('environment', 'office')
            env_display_map = {'office': '사무용', 'field': '현장용'}
            display_value = env_display_map.get(saved_env, '사무용')
            
            if hasattr(self, 'env_var') and self.env_var:
                self.env_var.set(display_value)
                logger.info(f"Environment setting refreshed: {saved_env} -> {display_value}")
                
            # 실행키 설정도 새로고침
            self.refresh_hotkey_setting()
                
        except Exception as e:
            logger.error(f"Error refreshing environment setting: {e}")
    
    def refresh_hotkey_setting(self):
        """실행키 설정값을 최신으로 새로고침"""
        try:
            current_hotkey = load_data('hotkey_type', 'mouse_wheel')
            if hasattr(self, 'hotkey_var') and self.hotkey_var:
                self.hotkey_var.set(current_hotkey)
                
                # 현재 실행키 레이블도 업데이트
                hotkey_names = {
                    'mouse_wheel': '마우스휠 버튼',
                    'f1': 'F1 키',
                    'f2': 'F2 키', 
                    'f3': 'F3 키',
                    'f4': 'F4 키',
                    'click_status': '상태 창 클릭'
                }
                
                if hasattr(self, 'current_key_label'):
                    self.current_key_label.config(
                        text=f"✓ 현재 활성화된 실행키: {hotkey_names.get(current_hotkey, '마우스휠 버튼')}"
                    )
                
                logger.info(f"Hotkey setting refreshed: {current_hotkey}")
        except Exception as e:
            logger.error(f"Error refreshing hotkey setting: {e}")
    
    def on_hotkey_selected(self, event=None):
        """드롭다운에서 실행키 선택 시 호출"""
        # 선택된 표시 이름을 실제 키 값으로 변환
        selected_name = self.hotkey_combo.get()
        hotkey_names = {
            'mouse_wheel': '마우스휠 버튼 (기본값)',
            'f1': 'F1 키',
            'f2': 'F2 키', 
            'f3': 'F3 키',
            'f4': 'F4 키',
            'click_status': '상태창 클릭'
        }
        
        # 역매핑으로 키 찾기
        hotkey_type = None
        for key, name in hotkey_names.items():
            if name == selected_name:
                hotkey_type = key
                break
        
        if hotkey_type:
            self.hotkey_var.set(hotkey_type)
            self.on_hotkey_changed()
    
    def on_hotkey_changed(self):
        """실행키 변경 시 호출 (실시간 적용)"""
        hotkey_type = self.hotkey_var.get()
        save_data('hotkey_type', hotkey_type)
        
        hotkey_names = {
            'mouse_wheel': '마우스휠 버튼 (기본값)',
            'f1': 'F1 키',
            'f2': 'F2 키', 
            'f3': 'F3 키',
            'f4': 'F4 키',
            'click_status': '상태창 클릭'
        }
        
        logger.info(f"Hotkey changed to: {hotkey_type} ({hotkey_names.get(hotkey_type, 'Unknown')})")
        
        # 현재 실행키 표시 업데이트
        if hasattr(self, 'current_key_label'):
            self.current_key_label.config(text=f"✓ 현재 활성화된 실행키: {hotkey_names.get(hotkey_type, '마우스휠 버튼')}")
        
        # 기존 리스너 정리 및 새 리스너 설정
        try:
            # RadialMenu 인스턴스가 있는지 확인
            if hasattr(self.status_window, 'radial_menu') and self.status_window.radial_menu:
                radial_menu = self.status_window.radial_menu
                
                # 모든 기존 리스너 정리 (전역 후크 포함)
                if hasattr(radial_menu, 'cleanup_listeners'):
                    radial_menu.cleanup_listeners()
                
                # 전역 후크도 추가로 정리 (확실하게)
                try:
                    import mouse
                    mouse.unhook_all()
                    logger.info("Additional global mouse hook cleanup")
                except:
                    pass
                    
                try:
                    import keyboard  
                    keyboard.unhook_all()
                    logger.info("Additional global keyboard hook cleanup")
                except:
                    pass
                
                # 새 리스너 설정
                setup_input_listener_for_instance(radial_menu, hotkey_type)
                
                # 성공 메시지
                messagebox.showinfo(
                    "실행키 변경 완료", 
                    f"실행키가 '{hotkey_names.get(hotkey_type, 'Unknown')}'으로 변경되었습니다.\n\n"
                    "변경사항이 즉시 적용되었습니다."
                )
            else:
                # RadialMenu가 없으면 재시작 필요
                messagebox.showinfo(
                    "실행키 변경", 
                    f"실행키가 '{hotkey_names.get(hotkey_type, 'Unknown')}'으로 변경되었습니다.\n\n"
                    "프로그램을 재시작하면 새로운 설정이 적용됩니다."
                )
                
        except Exception as e:
            logger.error(f"Error applying hotkey change: {e}")
            messagebox.showwarning(
                "실행키 변경", 
                f"실행키가 변경되었으나 즉시 적용하는데 실패했습니다.\n"
                f"프로그램을 재시작하면 새로운 설정이 적용됩니다.\n\n"
                f"오류: {str(e)}"
            )
    
    def update_website_list(self):
        """웹사이트 목록 업데이트"""
        # 기존 위젯들 제거
        for widget in self.website_list_frame.winfo_children():
            widget.destroy()
        
        # 현재 웹사이트 목록 가져오기
        custom_websites = load_data('custom_websites', [])
        
        # 라벨 텍스트 업데이트 (개수 표시)
        total_count = len(custom_websites) + 2  # 기본 지오봇, 사내메일 포함
        if hasattr(self, 'websites_label'):
            self.websites_label.config(text=f"등록된 웹사이트 ({total_count}/8):")
        
        # 기본 지오봇 표시
        default_label = ttk.Label(self.website_list_frame, 
                                 text="• 지오봇 (https://ai.geomedical.kr) [기본]",
                                 font=('Arial', 9))
        default_label.pack(anchor=tk.W)
        
        # 기본 사내메일 표시
        mail_label = ttk.Label(self.website_list_frame, 
                              text="• 사내메일 (https://mail.geolica.co.kr) [기본]",
                              font=('Arial', 9))
        mail_label.pack(anchor=tk.W)
        
        # 사용자 정의 웹사이트 표시
        for i, website in enumerate(custom_websites):
            website_frame = ttk.Frame(self.website_list_frame)
            website_frame.pack(fill=tk.X, pady=1)
            
            # 웹사이트 정보 표시
            info_text = f"• {website['text']} ({website['url']})"
            website_label = ttk.Label(website_frame, text=info_text, font=('Arial', 9))
            website_label.pack(side=tk.LEFT)
            
            # 삭제 버튼
            delete_btn = ttk.Button(website_frame, text="삭제", 
                                  command=lambda idx=i: self.delete_website(idx),
                                  width=6)
            delete_btn.pack(side=tk.RIGHT)
        
        # 스크롤 영역 업데이트
        self.settings_window.update_idletasks()  # UI 요소들의 크기 계산 완료 대기
        if hasattr(self, 'canvas'):
            self.canvas.configure(scrollregion=self.canvas.bbox("all"))
        
        # 동적 높이 조절
        self.adjust_window_height()
        
        # 추가 버튼 상태 업데이트 (7개 이상이면 비활성화)
        if hasattr(self, 'add_website_btn') and self.add_website_btn is not None:
            try:
                if len(custom_websites) >= 7:
                    self.add_website_btn.config(state='disabled', text="등록 제한")
                else:
                    self.add_website_btn.config(state='normal', text="추가")
            except Exception as e:
                logger.error(f"Error updating add button state: {e}")
        
        logger.info("Website list updated")
    
    def add_website(self):
        """새 웹사이트 추가"""
        text = self.website_text_var.get().strip()
        url = self.website_url_var.get().strip()
        
        if not text or not url:
            messagebox.showwarning("입력 오류", "표시 텍스트와 URL을 모두 입력해주세요.")
            return
        
        # URL 형식 검증 (간단한 검증)
        if not (url.startswith('http://') or url.startswith('https://')):
            url = 'https://' + url
        
        # 현재 웹사이트 목록 가져오기
        custom_websites = load_data('custom_websites', [])
        
        # 개수 제한 확인 (기본 지오봇 1개 + 사용자 정의 7개 = 최대 8개)
        if len(custom_websites) >= 7:
            messagebox.showwarning("등록 제한", "최대 7개의 웹사이트만 등록할 수 있습니다.\n(기본 지오봇 포함하여 총 8개)")
            return
        
        # 중복 검사
        for website in custom_websites:
            if website['text'] == text or website['url'] == url:
                messagebox.showwarning("중복 오류", "이미 등록된 웹사이트입니다.")
                return
        
        # 색상 생성 (랜덤)
        import random
        colors = ['#3498db', '#2ecc71', '#e74c3c', '#f39c12', '#9b59b6', '#1abc9c', '#e67e22', '#34495e']
        color = random.choice(colors)
        
        # 새 웹사이트 추가
        new_website = {
            "text": text,
            "url": url,
            "color": color
        }
        custom_websites.append(new_website)
        
        # 저장
        save_data('custom_websites', custom_websites)
        
        # 입력 필드 초기화
        self.website_text_var.set("")
        self.website_url_var.set("")
        
        # 목록 업데이트
        self.update_website_list()
        
        messagebox.showinfo("추가 완료", f"'{text}' 웹사이트가 추가되었습니다.")
        logger.info(f"New website added: {text} -> {url}")
    
    def delete_website(self, index):
        """웹사이트 삭제"""
        custom_websites = load_data('custom_websites', [])
        
        if 0 <= index < len(custom_websites):
            deleted_website = custom_websites[index]
            
            # 확인 대화상자
            if messagebox.askyesno("삭제 확인", 
                                 f"'{deleted_website['text']}' 웹사이트를 삭제하시겠습니까?"):
                custom_websites.pop(index)
                save_data('custom_websites', custom_websites)
                self.update_website_list()
                messagebox.showinfo("삭제 완료", f"'{deleted_website['text']}' 웹사이트가 삭제되었습니다.")
                logger.info(f"Website deleted: {deleted_website['text']}")
    
    def adjust_window_height(self):
        """웹사이트 개수에 따라 창 높이 자동 조절"""
        if not hasattr(self, 'canvas') or not self.settings_window:
            return
            
        try:
            # 스크롤 가능한 전체 컨텐츠의 높이 계산
            self.settings_window.update_idletasks()
            content_height = self.scrollable_frame.winfo_reqheight()
            
            # 최소/최대 높이 설정 (화면 크기 고려)
            min_height = 600
            screen_height = self.settings_window.winfo_screenheight()
            max_height = min(1200, int(screen_height * 0.8))  # 화면 높이의 80% 또는 1200px
            
            # 여백을 고려한 적절한 창 높이 계산
            # (컨텐츠 높이 + 여백 + 스크롤바 공간)
            desired_height = min(max(content_height + 100, min_height), max_height)
            
            # 현재 창 크기
            current_geometry = self.settings_window.geometry()
            current_width = int(current_geometry.split('x')[0])
            
            # 새 크기 적용 (너비는 유지, 높이만 조절)
            new_geometry = f"{current_width}x{desired_height}"
            self.settings_window.geometry(new_geometry)
            
            logger.info(f"Window height adjusted to: {desired_height} (content: {content_height})")
            
        except Exception as e:
            logger.error(f"Error adjusting window height: {e}")
    
    def reset_status_position(self):
        """상태 창 위치 초기화"""
        # 저장된 위치 정보 삭제
        save_data('status_position', None)
        
        # user_has_moved 플래그를 False로 설정하여 오른쪽 정렬 복원
        self.status_window.user_has_moved = False
        
        # 상태 창이 열려있으면 재생성
        if self.status_window.is_visible:
            self.status_window.hide_status_window()
            self.status_window.show_status_window()
        
        # 위치 라벨 업데이트
        self.update_position_label()
        
        logger.info("Status window position reset - right alignment restored")
        
    def move_status_window(self, dx, dy):
        """상태 창을 수동으로 이동"""
        if self.status_window.is_visible and self.status_window.status_window:
            try:
                # 현재 위치 가져오기
                current_x = self.status_window.status_window.winfo_x()
                current_y = self.status_window.status_window.winfo_y()
                
                # 새 위치 계산
                new_x = current_x + dx
                new_y = current_y + dy
                
                # 화면 경계 체크
                screen_width = self.status_window.status_window.winfo_screenwidth()
                screen_height = self.status_window.status_window.winfo_screenheight()
                
                # 창 크기
                window_width = 200
                window_height = 80
                
                # 경계 제한
                new_x = max(0, min(new_x, screen_width - window_width))
                new_y = max(0, min(new_y, screen_height - window_height))
                
                # 창 이동
                self.status_window.status_window.geometry(f"+{new_x}+{new_y}")
                
                # 위치 저장
                save_data('status_position', (new_x, new_y))
                
                # 위치 라벨 업데이트
                self.update_position_label()
                
                logger.info(f"Manually moved status window to ({new_x}, {new_y})")
                
            except Exception as e:
                logger.error(f"Manual move error: {e}")
    
    def update_position_label(self):
        """현재 위치 라벨 업데이트"""
        if hasattr(self, 'position_label'):
            position = load_data('status_position', None)
            if position:
                x, y = position
                self.position_label.config(text=f"현재 위치: ({x}, {y})")
            else:
                self.position_label.config(text="현재 위치: 기본값")
    
    def test_click_through(self):
        """클릭 통과 기능 테스트"""
        try:
            # 상태 창이 보이는 상태에서 클릭 통과 강제 적용
            if self.status_window.is_visible:
                self.status_window.set_click_through(True)
                
                # 메시지 박스로 테스트 안내
                messagebox.showinfo(
                    "클릭 통과 테스트",
                    "클릭 통과가 활성화되었습니다.\n\n"
                    "이제 상태 창 뒤에 있는 버튼을 클릭해보세요.\n"
                    "웹브라우저나 다른 프로그램을 열어서\n"
                    "상태 창 뒤의 버튼이 클릭되는지 확인하세요.\n\n"
                    "설정을 다시 열면 편집 모드로 돌아갑니다."
                )
            else:
                messagebox.showwarning("테스트 불가", "상태 창이 표시되어 있지 않습니다.")
                
        except Exception as e:
            logger.error(f"Click-through test error: {e}")
            messagebox.showerror("테스트 오류", f"클릭 통과 테스트 중 오류가 발생했습니다:\n{str(e)}")
    
    def recreate_status_window(self):
        """상태 창 재생성"""
        try:
            if self.status_window.is_visible:
                # 현재 상태 저장
                current_enabled = self.status_enabled
                
                # 창 숨기기
                self.status_window.hide_status_window()
                
                # 잠시 대기 후 다시 생성
                self.settings_window.after(500, lambda: self.restore_status_window(current_enabled))
                
                messagebox.showinfo("창 재생성", "상태 창을 재생성합니다.\n잠시만 기다려주세요.")
            else:
                messagebox.showwarning("재생성 불가", "상태 창이 표시되어 있지 않습니다.")
                
        except Exception as e:
            logger.error(f"Recreate status window error: {e}")
            messagebox.showerror("재생성 오류", f"상태 창 재생성 중 오류가 발생했습니다:\n{str(e)}")
    
    def restore_status_window(self, enabled):
        """상태 창 복원"""
        if enabled:
            self.status_window.show_status_window()
            # 편집 모드 재설정
            self.status_window.set_edit_mode(True)
    
    def on_method_changed(self, event):
        """클릭 통과 방식 변경 시"""
        try:
            method = self.click_through_method.get()
            save_data('click_through_method', method)
            
            # 상태 창이 표시 중이면 즉시 재생성
            if self.status_window.is_visible and not self.status_window.edit_mode:
                result = messagebox.askyesno(
                    "방식 변경", 
                    f"클릭 통과 방식을 '{method}'로 변경합니다.\n"
                    "지금 즉시 적용하시겠습니까?\n\n"
                    "'아니오'를 선택하면 설정 창을 닫을 때 적용됩니다."
                )
                
                if result:
                    # 즉시 적용
                    was_visible = self.status_window.is_visible
                    self.status_window.hide_status_window()
                    
                    if was_visible:
                        # 0.5초 후 새로운 방식으로 재생성
                        self.settings_window.after(500, lambda: self.status_window.show_status_window())
                
        except Exception as e:
            logger.error(f"Method change error: {e}")
    
    def try_pyqt_mode(self):
        """PyQt 모드 시도"""
        try:
            # PyQt5 설치 확인
            import PyQt5
            from PyQt5.QtWidgets import QApplication, QWidget, QLabel
            from PyQt5.QtCore import Qt
            from PyQt5.QtGui import QFont
            
            messagebox.showinfo(
                "PyQt 모드",
                "PyQt5가 설치되어 있습니다.\n"
                "PyQt 기반 상태 창을 생성할 수 있습니다.\n\n"
                "콤보박스에서 'pyqt'를 선택하고 창을 재생성하세요."
            )
            
        except ImportError:
            result = messagebox.askyesno(
                "PyQt5 설치 필요",
                "PyQt5가 설치되어 있지 않습니다.\n\n"
                "PyQt5는 클릭 통과 기능이 가장 안정적으로 작동합니다.\n"
                "설치하시겠습니까?\n\n"
                "명령어: pip install PyQt5"
            )
            
            if result:
                try:
                    import subprocess
                    import sys
                    subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'PyQt5'])
                    messagebox.showinfo("설치 완료", "PyQt5가 설치되었습니다.\n프로그램을 재시작해주세요.")
                except Exception as e:
                    messagebox.showerror("설치 실패", f"PyQt5 설치에 실패했습니다:\n{str(e)}")
        
        except Exception as e:
            logger.error(f"PyQt mode test error: {e}")
            messagebox.showerror("오류", f"PyQt 모드 테스트 중 오류가 발생했습니다:\n{str(e)}")
    
    def try_pysimplegui_mode(self):
        """PySimpleGUI 모드 시도"""
        try:
            # PySimpleGUI 설치 확인
            import PySimpleGUI as sg
            
            messagebox.showinfo(
                "PySimpleGUI 모드",
                "PySimpleGUI가 설치되어 있습니다.\n"
                "PySimpleGUI 기반 상태 창을 생성할 수 있습니다.\n\n"
                "콤보박스에서 'pysimplegui'를 선택하고 창을 재생성하세요."
            )
            
        except ImportError:
            result = messagebox.askyesno(
                "PySimpleGUI 설치 필요",
                "PySimpleGUI가 설치되어 있지 않습니다.\n\n"
                "PySimpleGUI는 간단하고 효과적인 GUI 라이브러리입니다.\n"
                "설치하시겠습니까?\n\n"
                "명령어: pip install PySimpleGUI"
            )
            
            if result:
                try:
                    import subprocess
                    import sys
                    subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'PySimpleGUI'])
                    messagebox.showinfo("설치 완료", "PySimpleGUI가 설치되었습니다.\n프로그램을 재시작해주세요.")
                except Exception as e:
                    messagebox.showerror("설치 실패", f"PySimpleGUI 설치에 실패했습니다:\n{str(e)}")
        
        except Exception as e:
            logger.error(f"PySimpleGUI mode test error: {e}")
            messagebox.showerror("오류", f"PySimpleGUI 모드 테스트 중 오류가 발생했습니다:\n{str(e)}")
    
    def close_settings(self):
        """설정 창 닫기"""
        try:
            # 설정 창이 닫힐 때 편집 모드 해제
            if self.status_window:
                self.status_window.set_edit_mode(False)
            
            # 설정 창 관련 참조들 안전하게 정리
            if self.settings_window:
                # 위젯 참조들 정리
                if hasattr(self, 'add_website_btn'):
                    self.add_website_btn = None
                if hasattr(self, 'websites_label'):
                    self.websites_label = None
                if hasattr(self, 'website_list_frame'):
                    self.website_list_frame = None
                if hasattr(self, 'canvas'):
                    self.canvas = None
                if hasattr(self, 'scrollable_frame'):
                    self.scrollable_frame = None
                    
                # 창 파괴
                self.settings_window.destroy()
                self.settings_window = None
                
        except Exception as e:
            logger.error(f"Error closing settings: {e}")
            # 강제로 설정 창 초기화
            self.settings_window = None
            
        logger.info("Settings window closed")


class RadialMenu:
    # 클래스 변수로 진행창 관리
    active_progress_windows = []
    def __init__(self):
        # 기존 진행창이 있으면 모두 닫기
        if RadialMenu.active_progress_windows:
            logger.info(f"Closing {len(RadialMenu.active_progress_windows)} active progress windows")
            for window in RadialMenu.active_progress_windows[:]:
                try:
                    window.destroy()
                except:
                    pass
            RadialMenu.active_progress_windows.clear()
        
        self.overlay = None
        self.background = None
        self.buttons = []
        self.mouse_x = 0
        self.mouse_y = 0
        self.status_window = StatusWindow()
        self.settings_window = SettingsWindow(self.status_window)
        self.active_listeners = []  # 활성 리스너 목록
        
        # 백그라운드 자산 모니터링 시작
        self.start_asset_monitoring()
    
    def cleanup_listeners(self):
        """기존 리스너 정리"""
        logger.info("Cleaning up existing listeners...")
        
        # pynput 리스너 정리
        for listener in self.active_listeners:
            try:
                if hasattr(listener, 'stop'):
                    listener.stop()
                    logger.info(f"Stopped listener: {type(listener).__name__}")
            except Exception as e:
                logger.error(f"Error stopping listener: {e}")
        
        self.active_listeners.clear()
        
        # StatusWindow의 PyQt 클릭 리스너 정리
        if hasattr(self, 'status_window') and self.status_window:
            if hasattr(self.status_window, 'pyqt_mouse_listener'):
                try:
                    self.status_window.pyqt_mouse_listener.stop()
                    logger.info("Stopped PyQt mouse listener")
                    # 리스너 참조 완전 제거
                    delattr(self.status_window, 'pyqt_mouse_listener')
                    logger.info("PyQt mouse listener reference removed")
                except Exception as e:
                    logger.error(f"Error stopping PyQt listener: {e}")
        
        # mouse/keyboard 라이브러리 이벤트 정리 (가능한 경우)
        try:
            import mouse
            mouse.unhook_all()
            logger.info("Cleared mouse hooks")
        except:
            pass
            
        try:
            import keyboard
            keyboard.unhook_all()
            logger.info("Cleared keyboard hooks")
        except:
            pass
        
    def create_menu(self, x, y):
        """원형 메뉴 생성"""
        logger.info(f"create_menu called at position ({x}, {y})")
        
        # 진행창이 열려있으면 모두 닫기
        if RadialMenu.active_progress_windows:
            logger.info(f"Closing {len(RadialMenu.active_progress_windows)} active progress windows before opening menu")
            for window in RadialMenu.active_progress_windows[:]:
                try:
                    window.destroy()
                except:
                    pass
            RadialMenu.active_progress_windows.clear()
        
        # 이미 열려있으면 닫고 새 위치에서 다시 열기
        was_open = False
        if self.overlay:
            logger.info("Menu already open, closing and reopening at new position...")
            was_open = True
            self.close_menu()
            # 메뉴가 이미 열려있었다면 잠시 대기 후 새 위치에서 열기
            if was_open:
                # 즉시 새 위치에서 열기 (토글이 아닌 재배치)
                pass
            
        self.mouse_x = x
        self.mouse_y = y
        
        # 오버레이 생성 (버튼 영역만큼만)
        self.overlay = tk.Toplevel()
        self.overlay.attributes('-topmost', True)
        self.overlay.overrideredirect(True)
        
        # 상태창에 라디얼 메뉴 활성 플래그 설정
        if hasattr(self, 'status_window') and self.status_window:
            self.status_window._radial_menu_active = True
            logger.info("Radial menu active flag set - status clicks will be blocked")
        
        # 윈도우 크기와 위치 설정 (버튼들이 들어갈 크기)
        window_size = 350  # 버튼 영역 크기 (확대)
        
        # 멀티 모니터 지원을 위한 가상 화면 정보 가져오기
        virtual_x = self.overlay.winfo_vrootx()
        virtual_y = self.overlay.winfo_vrooty()
        virtual_width = self.overlay.winfo_vrootwidth()
        virtual_height = self.overlay.winfo_vrootheight()
        
        # 실제 화면 좌표 계산 (모든 모니터 포함)
        window_x = x - window_size // 2
        window_y = y - window_size // 2
        
        # 화면 경계 체크 (멀티 모니터 고려)
        min_x = virtual_x
        min_y = virtual_y
        max_x = virtual_x + virtual_width - window_size
        max_y = virtual_y + virtual_height - window_size
        
        if window_x < min_x:
            window_x = min_x
        elif window_x > max_x:
            window_x = max_x
            
        if window_y < min_y:
            window_y = min_y
        elif window_y > max_y:
            window_y = max_y
        
        self.overlay.geometry(f"{window_size}x{window_size}+{window_x}+{window_y}")
        
        # 원형 GUI를 위한 투명 배경 설정 (메인 메뉴)
        self.overlay.attributes('-alpha', 0.9)  # 90% 투명도
        self.overlay.configure(bg='#191919')  # 투명 처리될 배경색
        # 지정된 색상을 투명하게 만들어 원형 효과 구현
        self.overlay.wm_attributes('-transparentcolor', '#191919')
        
        # 투명 배경 설정을 위한 전체 화면 오버레이
        self.background = tk.Toplevel()
        self.background.attributes('-topmost', True)
        self.background.attributes('-alpha', 0.01)  # 거의 투명하게
        self.background.overrideredirect(True)
        
        # 전체 가상 화면 크기로 설정
        self.background.geometry(f"{virtual_width}x{virtual_height}+{virtual_x}+{virtual_y}")
        
        # 배경 클릭 시 메뉴 닫기
        self.background.bind('<Button-1>', lambda e: self.close_menu())
        
        # 메뉴 창을 배경 위로 올리기
        self.overlay.lift()
        
        # 캔버스 생성 (투명 배경)
        self.canvas = tk.Canvas(self.overlay, highlightthickness=0, bg='#191919')
        self.canvas.pack(fill=tk.BOTH, expand=True)
        
        # 로컬 좌표로 변환
        self.local_x = window_size // 2
        self.local_y = window_size // 2
        
        # 현대적인 원형 배경 추가
        self.create_modern_circular_background()
        
        # 버튼 생성
        self.create_buttons()
        
        # 클릭 이벤트 바인딩 (캔버스에 바인딩)
        self.canvas.bind('<Button-1>', self.on_click)
        self.overlay.bind('<Escape>', lambda e: self.close_menu())
        
        # 포커스 설정 및 안정화
        self.overlay.focus_set()
        self.overlay.focus_force()
        
        # 윈도우 업데이트를 강제로 수행
        self.overlay.update_idletasks()
        self.overlay.update()
        
        logger.info("Menu created successfully")
        
    def create_buttons(self):
        """4개의 버튼을 원형으로 배치"""
        logger.info("Creating buttons...")
        
        radius = 110  # 중심에서 버튼까지의 거리 (확대)
        button_size = 80  # 버튼 크기 (확대)
        
        # 버튼 정보 (5개 - 테스트 버튼 추가)
        button_info = [
            {"text": "웹페이지", "color": "#3498db", "command": self.open_webpage},
            {"text": "탐색기", "color": "#2ecc71", "command": self.open_explorer},
            {"text": "점검", "color": "#e67e22", "command": self.perform_system_check},
            {"text": "자동조치", "color": "#f39c12", "command": self.open_auto_action},
            {"text": "설정", "color": "#9b59b6", "command": self.open_settings}
        ]
        
        # 중심 원 그리기
        center_size = 30
        center_circle = self.canvas.create_oval(
            self.local_x - center_size,
            self.local_y - center_size,
            self.local_x + center_size,
            self.local_y + center_size,
            fill='#34495e',
            outline='white',
            width=2,
            tags='center'
        )
        
        # 버튼 생성
        self.buttons = []
        for i, btn_info in enumerate(button_info):
            # 각도 계산 (위쪽부터 시작, 5개 버튼이므로 72도 간격)
            angle = (i * 72 - 90) * math.pi / 180
            
            # 버튼 위치 계산
            btn_x = self.local_x + radius * math.cos(angle)
            btn_y = self.local_y + radius * math.sin(angle)
            
            # 버튼 생성
            x1 = btn_x - button_size/2
            y1 = btn_y - button_size/2
            x2 = btn_x + button_size/2
            y2 = btn_y + button_size/2
            
            # 원형 버튼
            btn = self.canvas.create_oval(
                x1, y1, x2, y2,
                fill=btn_info["color"],
                outline='white',
                width=2,
                tags=f"button_{i}"
            )
            
            # 텍스트
            text = self.canvas.create_text(
                btn_x, btn_y,
                text=btn_info["text"],
                fill='white',
                font=('Arial', 10, 'bold'),
                tags=f"button_{i}"
            )
            
            # 버튼 정보 저장
            self.buttons.append({
                "id": btn,
                "text_id": text,
                "x": btn_x,
                "y": btn_y,
                "size": button_size,
                "command": btn_info["command"],
                "tag": f"button_{i}"
            })
            
            # 마우스 오버 효과 (캔버스 태그에 바인딩)
            # 클로저 문제를 해결하기 위해 즉시 실행 함수 사용
            self.canvas.tag_bind(f"button_{i}", '<Enter>', 
                (lambda tag: lambda e: self.on_button_hover(tag, True))(f"button_{i}"))
            self.canvas.tag_bind(f"button_{i}", '<Leave>', 
                (lambda tag: lambda e: self.on_button_hover(tag, False))(f"button_{i}"))
            self.canvas.tag_bind(f"button_{i}", '<Button-1>', 
                (lambda cmd: lambda e: self.on_button_click(cmd))(btn_info["command"]))
            
            logger.info(f"Button {i} ({btn_info['text']}) created at ({btn_x}, {btn_y}) with tag button_{i}")
        
        logger.info(f"Total {len(self.buttons)} buttons created")
        
        # 이벤트 바인딩 확인
        for i in range(len(button_info)):
            tag = f"button_{i}"
            bindings = self.canvas.tag_bind(tag)
            logger.debug(f"Button {i} bindings: {bindings}")
            if not bindings:
                logger.warning(f"Button {i} has no bindings!")
    
    def on_button_hover(self, tag, enter):
        """버튼 호버 효과 - 현대적인 스타일"""
        logger.debug(f"Button hover: tag={tag}, enter={enter}")
        try:
            # tag로 해당 버튼의 모든 요소들 찾기
            items = self.canvas.find_withtag(tag)
            
            if enter:
                # 마우스 진입 시: 색상 밝게 변경 + 살짝 확대 효과
                for item in items:
                    item_type = self.canvas.type(item)
                    if item_type == 'oval':  # 버튼 원형
                        # 원래 색상을 더 밝게 변경
                        current_fill = self.canvas.itemcget(item, 'fill')
                        self.canvas.itemconfig(item, fill=self._brighten_color(current_fill))
                        # 외곽선을 더 두드러지게
                        self.canvas.itemconfig(item, outline='#FFD700', width=3)
                    elif item_type == 'text':  # 버튼 텍스트
                        # 텍스트를 살짝 그림자 효과로
                        self.canvas.itemconfig(item, fill='#FFD700')
                logger.debug(f"Button {tag} modern hover effect applied")
            else:
                # 마우스 이탈 시: 원래 스타일로 복원
                for item in items:
                    item_type = self.canvas.type(item)
                    if item_type == 'oval':  # 버튼 원형
                        # 원래 색상으로 복원 - 버튼별 원래 색상을 찾아서 적용
                        original_color = self._get_original_button_color(tag)
                        self.canvas.itemconfig(item, fill=original_color)
                        self.canvas.itemconfig(item, outline='white', width=2)
                    elif item_type == 'text':  # 버튼 텍스트
                        self.canvas.itemconfig(item, fill='white')
                logger.debug(f"Button {tag} hover effect removed")
        except Exception as e:
            logger.error(f"Error in on_button_hover: {e}")
    
    def _brighten_color(self, color):
        """색상을 밝게 변경"""
        color_map = {
            '#e74c3c': '#FF6B6B',  # 빨간색 -> 밝은 빨간색
            '#f39c12': '#FFB84D',  # 주황색 -> 밝은 주황색  
            '#e67e22': '#FF8C42',  # 점검 주황색 -> 밝은 주황색
            '#27ae60': '#58D68D',  # 초록색 -> 밝은 초록색
            '#3498db': '#5DADE2',  # 파란색 -> 밝은 파란색
            '#9b59b6': '#BB8FCE',  # 보라색 -> 밝은 보라색
            '#34495e': '#5D6D7E',  # 회색 -> 밝은 회색
            '#2ecc71': '#58D68D',  # MES 초록색 -> 밝은 초록색
            '#1abc9c': '#5DDBCB'   # 청록색 -> 밝은 청록색
        }
        return color_map.get(color, '#FFFFFF')  # 기본값은 흰색
    
    def _get_original_button_color(self, tag):
        """버튼의 원래 색상 반환 (메인 메뉴와 서브메뉴 모두 지원)"""
        # 메인 메뉴 버튼 색상 (실제 button_info와 일치)
        main_button_colors = {
            'button_0': '#3498db',  # 웹페이지 (파란색)
            'button_1': '#2ecc71',  # 탐색기 (초록색)
            'button_2': '#e67e22',  # 점검 (주황색)
            'button_3': '#f39c12',  # 자동조치 (주황색)
            'button_4': '#9b59b6'   # 설정 (보라색)
        }
        
        # 서브메뉴 버튼 색상 (점검 메뉴의 6개 버튼)
        submenu_button_colors = {
            'button_0': '#3498db',  # 스캐너 (파란색)
            'button_1': '#2ecc71',  # MES (초록색)
            'button_2': '#e74c3c',  # GDRIVE (빨간색)
            'button_3': '#f39c12',  # 인터넷 (주황색)
            'button_4': '#9b59b6',  # PC정보 (보라색)
            'button_5': '#1abc9c'   # 소프트웨어 (청록색)
        }
        
        # 웹사이트 서브메뉴인지 확인 (buttons에 color 정보가 있으면)
        if hasattr(self, 'buttons') and len(self.buttons) > 0:
            # buttons 배열에서 해당 tag에 맞는 색상 찾기
            for button in self.buttons:
                if button.get("tag") == tag and "color" in button:
                    return button["color"]
        
        # 점검 서브메뉴인지 확인 (서브메뉴는 6개 버튼을 가지므로)
        if hasattr(self, 'buttons') and len(self.buttons) == 6:
            return submenu_button_colors.get(tag, '#34495e')
        else:
            return main_button_colors.get(tag, '#34495e')
    
    def create_modern_circular_background(self):
        """현대적인 원형 배경 생성"""
        # 메인 원형 배경 (블러 효과를 위한 다중 원)
        center_x = self.local_x
        center_y = self.local_y
        
        # 외부 블러 효과를 위한 여러 원 (350px 창에 맞게 조정)
        blur_layers = [
            {'radius': 175, 'color': '#2C3E50', 'alpha': 0.15},  # 가장 외부 (창 모서리까지)
            {'radius': 165, 'color': '#34495E', 'alpha': 0.25},  # 중간 (슬레이트)
            {'radius': 155, 'color': '#3F4F5F', 'alpha': 0.35},  # 내부 (진한 회색)
        ]
        
        # 블러 효과를 위한 다중 원 생성
        for layer in blur_layers:
            # tkinter에서는 직접적인 alpha 지원이 제한적이므로 색상 조합으로 투명도 효과 구현
            self.canvas.create_oval(
                center_x - layer['radius'], 
                center_y - layer['radius'],
                center_x + layer['radius'], 
                center_y + layer['radius'],
                fill=layer['color'],
                outline='',
                width=0,
                stipple='gray50'  # 패턴을 사용해 투명도 효과
            )
        
        # 메인 원형 배경 (그라데이션 효과를 위한 여러 원)
        gradient_layers = [
            {'radius': 140, 'color': '#4A5B6C'},  # 외부
            {'radius': 135, 'color': '#5D6E7F'},  # 중간
            {'radius': 130, 'color': '#708192'},  # 내부
        ]
        
        for layer in gradient_layers:
            self.canvas.create_oval(
                center_x - layer['radius'], 
                center_y - layer['radius'],
                center_x + layer['radius'], 
                center_y + layer['radius'],
                fill=layer['color'],
                outline='',
                width=0
            )
        
        # 글로우 효과를 위한 미세한 외곽선
        self.canvas.create_oval(
            center_x - 140, 
            center_y - 140,
            center_x + 140, 
            center_y + 140,
            fill='',
            outline='#85C1E9',  # 연한 파란색 글로우
            width=1
        )
        
        logger.info("Modern circular background created")
    
    def create_modern_circular_background_submenu(self):
        """서브메뉴용 현대적인 원형 배경 생성 (조금 더 큰 크기)"""
        # 메인 원형 배경 (블러 효과를 위한 다중 원)
        center_x = self.local_x
        center_y = self.local_y
        
        # 서브메뉴는 6개 버튼을 위해 조금 더 큰 배경
        # 외부 블러 효과를 위한 여러 원 (서브메뉴 350px 창에 맞게 조정)
        blur_layers = [
            {'radius': 175, 'color': '#1B2631', 'alpha': 0.15},  # 가장 외부 (창 모서리까지)
            {'radius': 165, 'color': '#2C3E50', 'alpha': 0.25},  # 중간 (어두운 네이비)
            {'radius': 155, 'color': '#34495E', 'alpha': 0.35},  # 내부 (슬레이트)
        ]
        
        # 블러 효과를 위한 다중 원 생성
        for layer in blur_layers:
            self.canvas.create_oval(
                center_x - layer['radius'], 
                center_y - layer['radius'],
                center_x + layer['radius'], 
                center_y + layer['radius'],
                fill=layer['color'],
                outline='',
                width=0,
                stipple='gray50'  # 패턴을 사용해 투명도 효과
            )
        
        # 서브메뉴 원형 배경 (그라데이션 효과를 위한 여러 원)
        gradient_layers = [
            {'radius': 140, 'color': '#3D5A80'},  # 외부 (약간 파란빛)
            {'radius': 135, 'color': '#4A6B94'},  # 중간
            {'radius': 130, 'color': '#577CA8'},  # 내부
        ]
        
        for layer in gradient_layers:
            self.canvas.create_oval(
                center_x - layer['radius'], 
                center_y - layer['radius'],
                center_x + layer['radius'], 
                center_y + layer['radius'],
                fill=layer['color'],
                outline='',
                width=0
            )
        
        # 글로우 효과를 위한 미세한 외곽선
        self.canvas.create_oval(
            center_x - 140, 
            center_y - 140,
            center_x + 140, 
            center_y + 140,
            fill='',
            outline='#7FB3D3',  # 연한 파란색 글로우 (서브메뉴용)
            width=1
        )
        
        logger.info("Modern circular background for submenu created")
    
    def create_modern_circular_background_website(self):
        """웹사이트 서브메뉴용 현대적인 원형 배경 생성"""
        # 메인 원형 배경 (블러 효과를 위한 다중 원)
        center_x = self.local_x
        center_y = self.local_y
        
        # 웹사이트 서브메뉴용 색상 팔레트 (초록색 계열)
        # 외부 블러 효과를 위한 여러 원
        blur_layers = [
            {'radius': 175, 'color': '#1B4332', 'alpha': 0.15},  # 가장 외부 (어두운 초록)
            {'radius': 165, 'color': '#2D5A3D', 'alpha': 0.25},  # 중간 
            {'radius': 155, 'color': '#40916C', 'alpha': 0.35},  # 내부
        ]
        
        # 블러 효과를 위한 다중 원 생성
        for layer in blur_layers:
            self.canvas.create_oval(
                center_x - layer['radius'], 
                center_y - layer['radius'],
                center_x + layer['radius'], 
                center_y + layer['radius'],
                fill=layer['color'],
                outline='',
                width=0,
                stipple='gray50'  # 패턴을 사용해 투명도 효과
            )
        
        # 메인 원형 배경 (그라데이션 효과를 위한 여러 원)
        gradient_layers = [
            {'radius': 140, 'color': '#52B788'},  # 외부 (밝은 초록)
            {'radius': 135, 'color': '#74C69D'},  # 중간
            {'radius': 130, 'color': '#95D5B2'},  # 내부
        ]
        
        for layer in gradient_layers:
            self.canvas.create_oval(
                center_x - layer['radius'], 
                center_y - layer['radius'],
                center_x + layer['radius'], 
                center_y + layer['radius'],
                fill=layer['color'],
                outline='',
                width=0
            )
        
        # 글로우 효과를 위한 미세한 외곽선
        self.canvas.create_oval(
            center_x - 140, 
            center_y - 140,
            center_x + 140, 
            center_y + 140,
            fill='',
            outline='#B7E4C7',  # 연한 초록색 글로우 (웹사이트용)
            width=1
        )
        
        logger.info("Modern circular background for website submenu created")
    
    def create_website_buttons(self):
        """웹사이트 버튼 생성"""
        logger.info("Creating website buttons...")
        
        # 웹사이트 데이터 로드
        websites = self.load_website_data()
        
        radius = 110  # 중심에서 버튼까지의 거리
        button_size = 70  # 버튼 크기
        
        # 중심 원 그리기
        center_size = 25
        center_circle = self.canvas.create_oval(
            self.local_x - center_size,
            self.local_y - center_size,
            self.local_x + center_size,
            self.local_y + center_size,
            fill='#34495e',
            outline='white',
            width=2
        )
        
        # 중심 텍스트
        self.canvas.create_text(
            self.local_x,
            self.local_y,
            text="웹사이트",
            font=('Arial', 9, 'bold'),
            fill='white'
        )
        
        # 버튼 생성
        self.buttons = []
        # 실제 표시할 버튼 개수 계산 (최대 8개)
        display_count = min(len(websites), 8)
        
        for i, website in enumerate(websites):
            if i >= 8:  # 최대 8개 버튼
                break
                
            # 각도 계산 (위쪽부터 시작, 실제 표시할 개수를 기준으로)
            angle = (i * (360 / display_count) - 90) * math.pi / 180
            
            # 버튼 위치 계산
            btn_x = self.local_x + radius * math.cos(angle)
            btn_y = self.local_y + radius * math.sin(angle)
            
            # 버튼 생성
            x1 = btn_x - button_size/2
            y1 = btn_y - button_size/2
            x2 = btn_x + button_size/2
            y2 = btn_y + button_size/2
            
            # 원형 버튼
            btn = self.canvas.create_oval(
                x1, y1, x2, y2,
                fill=website["color"],
                outline='white',
                width=2,
                tags=f"button_{i}"
            )
            
            # 버튼 텍스트
            text = self.canvas.create_text(
                btn_x, btn_y,
                text=website['text'],
                font=('Arial', 10, 'bold'),
                fill='white',
                tags=f"button_{i}"
            )
            
            # 버튼 정보 저장
            self.buttons.append({
                "id": btn,
                "text_id": text,
                "x": btn_x,
                "y": btn_y,
                "size": button_size,
                "command": lambda url=website['url']: self.open_website_url(url),
                "color": website['color'],
                "tag": f"button_{i}"
            })
            
            # 호버 이벤트 바인딩
            self.canvas.tag_bind(f"button_{i}", '<Enter>', 
                (lambda tag: lambda e: self.on_button_hover(tag, True))(f"button_{i}"))
            self.canvas.tag_bind(f"button_{i}", '<Leave>', 
                (lambda tag: lambda e: self.on_button_hover(tag, False))(f"button_{i}"))
            self.canvas.tag_bind(f"button_{i}", '<Button-1>', 
                (lambda cmd: lambda e: self.on_button_click(cmd))(lambda url=website['url']: self.open_website_url(url)))
            
            logger.info(f"Website button {i} ({website['text']}) created at ({btn_x}, {btn_y})")
        
        logger.info(f"Created {len(self.buttons)} website buttons")
    
    def load_website_data(self):
        """웹사이트 데이터 로드"""
        # 저장된 데이터 로드 시도
        custom_websites = load_data('custom_websites', [])
        
        # 기본 웹사이트 (지오봇, 사내메일)
        default_websites = [
            {"text": "지오봇", "url": "https://ai.geomedical.kr", "color": "#27AE60"},
            {"text": "사내메일", "url": "https://mail.geolica.co.kr", "color": "#3498db"}
        ]
        
        # 사용자 정의 웹사이트와 기본 웹사이트 합치기
        all_websites = default_websites + custom_websites
        
        return all_websites
    
    def open_website_url(self, url):
        """지정된 URL로 웹사이트 열기"""
        logger.info(f"Opening website: {url}")
        self.close_menu()
        webbrowser.open(url)
        logger.info(f"Website opened: {url}")
    
    def on_button_click(self, command):
        """버튼 클릭 처리"""
        logger.info(f"Button clicked, executing command: {command}")
        try:
            command()
            logger.info("Command executed successfully")
        except Exception as e:
            logger.error(f"Error executing command: {e}")
    
    def on_click(self, event):
        """클릭 이벤트 처리"""
        x, y = event.x, event.y
        logger.debug(f"Canvas click at ({x}, {y})")
        
        # 중앙 원 클릭 확인
        center_dist = math.sqrt((x - self.local_x)**2 + (y - self.local_y)**2)
        if center_dist <= 30:  # 중앙 원 크기
            logger.info("Center circle clicked, closing menu")
            self.close_menu()
            return
        
        # 버튼 클릭 확인
        for btn in self.buttons:
            btn_dist = math.sqrt((x - btn["x"])**2 + (y - btn["y"])**2)
            if btn_dist <= btn["size"] / 2:
                logger.info(f"Button clicked at ({btn['x']}, {btn['y']})")
                self.on_button_click(btn["command"])
                return
        
        # 빈 공간 클릭시 닫기
        logger.info("Empty space clicked, closing menu")
        self.close_menu()
    
    def close_menu(self):
        """메뉴 닫기"""
        logger.info("Closing menu...")
        if self.overlay:
            self.overlay.destroy()
            self.overlay = None
            logger.info("Overlay destroyed")
        if hasattr(self, 'background') and self.background:
            self.background.destroy()
            self.background = None
            logger.info("Background destroyed")
        self.buttons = []
        
        # 상태창에 라디얼 메뉴 비활성 플래그 설정
        if hasattr(self, 'status_window') and self.status_window:
            self.status_window._radial_menu_active = False
            logger.info("Radial menu active flag cleared - status clicks enabled")
        
        logger.info("Menu closed successfully")
    
    # 버튼 기능들
    def open_webpage(self):
        """웹사이트 서브메뉴 열기"""
        logger.info("Opening website submenu...")
        self.close_menu()
        # 웹사이트 서브메뉴 생성
        self.create_website_submenu(self.mouse_x, self.mouse_y)
    
    def open_explorer(self):
        """내 PC 탐색기 열기"""
        logger.info("Opening This PC...")
        self.close_menu()
        import subprocess
        if os.name == 'nt':  # Windows - 내 PC 열기
            subprocess.Popen('explorer ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}', shell=True)
        else:  # Linux/Mac
            subprocess.Popen(['xdg-open', os.path.expanduser('~')])
        logger.info("This PC opened")
    
    def check_internet(self):
        """인터넷 연결 상태 확인"""
        logger.info("Checking internet connection...")
        # 먼저 메뉴를 닫고 메시지박스 표시
        self.close_menu()
        
        def is_connected():
            try:
                # Google DNS에 연결 시도
                socket.create_connection(("8.8.8.8", 53), timeout=3)
                return True
            except OSError:
                return False
        
        if is_connected():
            logger.info("Internet connection: OK")
            
            # 네트워크 정보 가져오기
            network_info = self.get_detailed_network_info()
            
            message = f"인터넷 연결 상태: 정상 🟢\n\n{network_info}"
            messagebox.showinfo("인터넷 상태", message)
        else:
            logger.info("Internet connection: OFFLINE")
            messagebox.showwarning("인터넷 상태", "인터넷 연결 상태: 오프라인 🔴\n\n연결을 확인해 주세요.")
    
    def get_network_info(self):
        """네트워크 정보 가져오기"""
        try:
            # IP 주소 가져오기
            ip = self.get_local_ip()
            
            # 무선 네트워크 이름 가져오기
            ssid = self.get_wifi_ssid()
            
            if ssid:
                return f"WiFi ({ssid})"
            else:
                return f"유선 연결"
                
        except Exception as e:
            logger.error(f"Network info error: {e}")
            return "네트워크 정보를 가져올 수 없습니다."
    
    def get_detailed_network_info(self):
        """상세한 네트워크 정보 가져오기 (메시지박스용)"""
        try:
            # IP 주소 가져오기
            ip = self.get_local_ip()
            
            # 무선 네트워크 이름 가져오기
            ssid = self.get_wifi_ssid()
            
            if ssid:
                return f"네트워크: WiFi ({ssid})\nIP 주소: {ip}"
            else:
                return f"네트워크: 유선 연결\nIP 주소: {ip}"
                
        except Exception as e:
            logger.error(f"Detailed network info error: {e}")
            return "네트워크 정보를 가져올 수 없습니다."
    
    def get_local_ip(self):
        """로컬 IP 주소 가져오기"""
        try:
            # Google DNS에 연결하여 로컬 IP 확인
            with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
                s.connect(("8.8.8.8", 53))
                return s.getsockname()[0]
        except:
            return "IP 주소를 가져올 수 없음"
    
    def get_wifi_ssid(self):
        """현재 연결된 WiFi SSID 가져오기"""
        try:
            if platform.system() == "Windows":
                # Windows에서 현재 연결된 WiFi 정보 가져오기
                result = subprocess.run(
                    ["netsh", "wlan", "show", "interfaces"],
                    capture_output=True,
                    text=True,
                    encoding='cp949'
                )
                
                if result.returncode == 0:
                    # SSID 추출
                    for line in result.stdout.split('\n'):
                        if 'SSID' in line and 'BSSID' not in line:
                            ssid = line.split(':', 1)[1].strip()
                            if ssid:
                                return ssid
                                
            elif platform.system() == "Darwin":  # macOS
                result = subprocess.run(
                    ["/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport", "-I"],
                    capture_output=True,
                    text=True
                )
                
                if result.returncode == 0:
                    ssid_match = re.search(r'SSID: (.+)', result.stdout)
                    if ssid_match:
                        return ssid_match.group(1).strip()
                        
            elif platform.system() == "Linux":
                # Linux에서 iwgetid 명령어 사용
                result = subprocess.run(
                    ["iwgetid", "-r"],
                    capture_output=True,
                    text=True
                )
                
                if result.returncode == 0:
                    return result.stdout.strip()
                    
        except Exception as e:
            logger.error(f"WiFi SSID error: {e}")
            
        return None
    
    
    def network_recovery_step(self, step_num, command, description):
        """네트워크 복구 단계 실행"""
        try:
            logger.info(f"Step {step_num}: {description}")
            
            if isinstance(command, list):
                result = subprocess.run(
                    command,
                    capture_output=True,
                    text=True,
                    timeout=30
                )
            else:
                result = subprocess.run(
                    command,
                    shell=True,
                    capture_output=True,
                    text=True,
                    timeout=30
                )
            
            if result.returncode == 0:
                logger.info(f"Step {step_num} completed successfully")
                return True
            else:
                logger.warning(f"Step {step_num} failed: {result.stderr}")
                return False
                
        except Exception as e:
            logger.error(f"Step {step_num} error: {e}")
            return False
    
    def create_wifi_profile(self, ssid, password):
        """WiFi 프로필 XML 생성"""
        profile_xml = f'''<?xml version="1.0"?>
<WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">
   <name>{ssid}</name>
   <SSIDConfig>
       <SSID>
           <hex>{ssid.encode('utf-8').hex().upper()}</hex>
           <name>{ssid}</name>
       </SSID>
       <nonBroadcast>true</nonBroadcast>
   </SSIDConfig>
   <connectionType>ESS</connectionType>
   <connectionMode>manual</connectionMode>
   <MSM>
       <security>
           <authEncryption>
               <authentication>WPA2PSK</authentication>
               <encryption>AES</encryption>
               <useOneX>false</useOneX>
           </authEncryption>
           <sharedKey>
               <keyType>passPhrase</keyType>
               <protected>false</protected>
               <keyMaterial>{password}</keyMaterial>
           </sharedKey>
       </security>
   </MSM>
</WLANProfile>'''
        
        # 임시 프로필 파일 생성
        cache_dir = get_cache_dir()
        profile_file = os.path.join(cache_dir, f'{ssid}.xml')
        
        with open(profile_file, 'w', encoding='utf-8') as f:
            f.write(profile_xml)
        
        return profile_file
    
    def connect_to_wifi(self, ssid, password):
        """WiFi 연결"""
        try:
            logger.info(f"Attempting to connect to WiFi: {ssid}")
            
            # 기존 프로필 삭제
            subprocess.run(['netsh', 'wlan', 'delete', 'profile', f'name={ssid}'], 
                         capture_output=True, encoding='cp949')
            
            # 새 프로필 생성 및 추가
            profile_file = self.create_wifi_profile(ssid, password)
            add_result = subprocess.run(['netsh', 'wlan', 'add', 'profile', f'filename={profile_file}'], 
                       capture_output=True, text=True, encoding='cp949')
            
            # 임시 파일 삭제
            try:
                os.remove(profile_file)
            except:
                pass
            
            logger.info(f"Profile add result: {add_result.stdout}")
            
            # 연결 시도
            time.sleep(3)
            connect_result = subprocess.run(['netsh', 'wlan', 'connect', f'name={ssid}', 'ssid=' + ssid], 
                           capture_output=True, text=True, encoding='cp949')
            
            logger.info(f"Connection attempt: {connect_result.stdout}")
            
            if '연결 요청을 완료' in connect_result.stdout or 'connection request was completed' in connect_result.stdout:
                # 연결 상태 확인
                time.sleep(10)
                status_result = subprocess.run(['netsh', 'wlan', 'show', 'interface'], 
                                            capture_output=True, text=True, encoding='cp949')
                
                if '연결됨' in status_result.stdout or 'connected' in status_result.stdout.lower():
                    logger.info(f"Successfully connected to WiFi: {ssid}")
                    return True
            
            return False
            
        except Exception as e:
            logger.error(f"WiFi connection error: {e}")
            return False
    
    def auto_network_recovery(self):
        """네트워크 자동 복구 수행"""
        logger.info("Starting network auto recovery...")
        
        # 현재 사용 환경 확인
        env_setting = load_data('environment', 'office')  # 기본값: 사무용
        
        # WiFi 설정
        wifi_configs = {
            'office': {'ssid': 'GEO_NET', 'password': 'Geo21eye@'},
            'field': {'ssid': 'GEO_MES', 'password': 'geo123!@#'}
        }
        
        wifi_config = wifi_configs.get(env_setting, wifi_configs['office'])
        
        # 0단계: 네트워크 어댑터 활성화 (6단계 시작 전)
        logger.info("Step 0: 네트워크 어댑터 활성화")
        adapter_enabled = enable_network_adapters()
        if not adapter_enabled:
            logger.warning("Network adapter activation failed, but continuing with recovery...")
        
        # 5단계 네트워크 복구 과정 (고정 IP 환경을 위해 IP reset 제거)
        recovery_steps = [
            (1, "ipconfig /flushdns", "DNS 캐시 초기화"),
            (2, "ipconfig /release", "IP 주소 해제"),
            (3, "ipconfig /renew", "IP 주소 갱신"),
            (4, "netsh winsock reset", "Winsock 리셋"),
        ]
        
        # 1-4단계 실행
        for step_num, command, description in recovery_steps:
            success = self.network_recovery_step(step_num, command, description)
            if step_num == 4 and success:
                # Winsock reset 후 잠시 대기
                time.sleep(5)
        
        # 5단계: 무선 인터페이스 확인 및 WiFi 연결
        logger.info("Step 5: 무선 인터페이스 확인")
        
        # 무선 인터페이스 존재 여부 확인
        has_wifi = self.check_wifi_interface()
        
        if has_wifi:
            logger.info("Step 6: WiFi 연결 시도")
            wifi_success = self.connect_to_wifi(wifi_config['ssid'], wifi_config['password'])
            
            if wifi_success:
                # 연결 후 인터넷 확인
                time.sleep(10)
                if self.check_internet_connection():
                    logger.info("Network recovery completed successfully")
                    return True
        else:
            logger.info("No wireless interface found - skipping WiFi connection")
            # 유선 연결 확인
            time.sleep(5)
            if self.check_internet_connection():
                logger.info("Network recovery completed successfully (wired connection)")
                return True
        
        logger.warning("Network recovery failed")
        return False
    
    def start_network_monitor(self):
        """네트워크 상태 모니터링 및 자동 복구"""
        self.network_monitor_running = True
        
        def monitor_loop():
            check_interval = 30  # 30초마다 확인
            retry_interval = 60  # 복구 시도 후 1분 대기
            max_retries = 3
            retry_count = 0
            offline_detected = False
            
            logger.info("Network monitor started - checking every 30 seconds")
            
            while self.network_monitor_running:
                try:
                    # 먼저 원하지 않는 네트워크 연결 확인 및 처리
                    unwanted_network_disconnected = self.check_and_handle_unwanted_networks()
                    
                    if unwanted_network_disconnected:
                        logger.info("Unwanted network disconnected. Waiting before recovery...")
                        time.sleep(10)  # 연결 해제 후 잠시 대기
                        # 즉시 자동 복구 시도
                        recovery_success = self.auto_network_recovery()
                        if recovery_success:
                            logger.info("Successfully connected to proper network after unwanted network removal")
                        else:
                            logger.warning("Failed to connect to proper network after unwanted network removal")
                        continue
                    
                    # 인터넷 연결 확인
                    is_online = self.check_internet_connection()
                    
                    if not is_online:
                        if not offline_detected:
                            offline_detected = True
                            logger.warning("Internet connection lost. Starting recovery...")
                        
                        if retry_count < max_retries:
                            logger.info(f"Starting network recovery attempt {retry_count + 1}/{max_retries}")
                            recovery_success = self.auto_network_recovery()
                            
                            if recovery_success:
                                retry_count = 0  # 성공 시 재시도 카운트 초기화
                                offline_detected = False
                                logger.info("Network recovery successful - back online")
                            else:
                                retry_count += 1
                                logger.warning(f"Network recovery failed. Attempt {retry_count}/{max_retries}")
                                time.sleep(retry_interval)  # 실패 후 대기
                        else:
                            logger.error("Maximum retry attempts reached. Waiting for next cycle...")
                            retry_count = 0  # 재시도 카운트 초기화
                            time.sleep(retry_interval * 2)  # 더 긴 대기
                    else:
                        if offline_detected:
                            logger.info("Internet connection restored")
                            offline_detected = False
                            retry_count = 0
                        
                        time.sleep(check_interval)  # 정상 상태에서는 30초 대기
                    
                except Exception as e:
                    logger.error(f"Network monitor error: {e}")
                    time.sleep(60)  # 에러 시 1분 대기
        
        # 별도 스레드에서 모니터링 시작
        self.network_thread = threading.Thread(target=monitor_loop, daemon=True)
        self.network_thread.start()
        logger.info("Network monitor started")
    
    def stop_network_monitor(self):
        """네트워크 모니터링 중지"""
        logger.info("Stopping network monitor...")
        self.network_monitor_running = False
        if hasattr(self, 'network_thread'):
            # 스레드가 종료될 때까지 잠시 대기
            try:
                self.network_thread.join(timeout=1)
            except:
                pass
            logger.info("Network monitor stopped")
    
    def check_internet_connection(self):
        """인터넷 연결 확인 - RadialMenu용"""
        # StatusWindow의 메서드 사용
        return self.status_window.check_internet_connection()
    
    def check_wifi_interface(self):
        """무선 인터페이스 존재 여부 확인"""
        try:
            result = subprocess.run([
                'netsh', 'wlan', 'show', 'interfaces'
            ], capture_output=True, text=True, encoding='cp949', timeout=10)
            
            # "시스템에 무선 인터페이스가 없습니다" 메시지 확인
            if ("시스템에 무선 인터페이스가 없습니다" in result.stdout or
                "There is no wireless interface on the system" in result.stdout):
                logger.info("No wireless interface detected")
                return False
            
            # 정상적인 무선 인터페이스 정보가 있는지 확인
            if "이름" in result.stdout or "Name" in result.stdout:
                logger.info("Wireless interface detected")
                return True
            
            return False
            
        except Exception as e:
            logger.error(f"Error checking wireless interface: {e}")
            return False
    
    def get_current_wifi_ssid(self):
        """현재 연결된 WiFi SSID 확인"""
        try:
            result = subprocess.run([
                'netsh', 'wlan', 'show', 'interfaces'
            ], capture_output=True, text=True, encoding='cp949', timeout=10)
            
            lines = result.stdout.split('\n')
            for line in lines:
                line = line.strip()
                if 'SSID' in line and ':' in line:
                    # "SSID : GEO Mobile Wi-Fi" 형태에서 SSID 추출
                    ssid = line.split(':', 1)[1].strip()
                    if ssid and ssid != 'N/A':
                        return ssid
            
            return None
        except Exception as e:
            logger.error(f"Error getting current WiFi SSID: {e}")
            return None
    
    def get_current_ip_address(self):
        """현재 IP 주소 확인"""
        try:
            result = subprocess.run([
                'ipconfig'
            ], capture_output=True, text=True, encoding='cp949', timeout=10)
            
            lines = result.stdout.split('\n')
            for line in lines:
                line = line.strip()
                if 'IPv4' in line and ':' in line:
                    # "IPv4 주소 . . . . . . . . : 20.20.20.100" 형태에서 IP 추출
                    ip = line.split(':', 1)[1].strip()
                    if ip and not ip.startswith('169.254'):  # APIPA 주소 제외
                        return ip
            
            return None
        except Exception as e:
            logger.error(f"Error getting current IP address: {e}")
            return None
    
    def is_ip_in_range(self, ip_address, network_range):
        """IP 주소가 특정 네트워크 범위에 속하는지 확인"""
        try:
            import ipaddress
            
            # IP 주소와 네트워크 범위를 ipaddress 객체로 변환
            ip = ipaddress.ip_address(ip_address)
            network = ipaddress.ip_network(network_range, strict=False)
            
            return ip in network
        except Exception as e:
            logger.error(f"Error checking IP range: {e}")
            return False
    
    def disconnect_wifi_and_delete_profile(self, ssid):
        """WiFi 연결 끊기 및 프로필 삭제"""
        try:
            # WiFi 연결 끊기
            logger.info(f"Disconnecting from WiFi: {ssid}")
            disconnect_result = subprocess.run([
                'netsh', 'wlan', 'disconnect'
            ], capture_output=True, text=True, encoding='cp949', timeout=10)
            
            if disconnect_result.returncode == 0:
                logger.info("WiFi disconnected successfully")
            else:
                logger.warning(f"WiFi disconnect failed: {disconnect_result.stderr}")
            
            # 잠시 대기
            time.sleep(3)
            
            # WiFi 프로필 삭제
            logger.info(f"Deleting WiFi profile: {ssid}")
            delete_result = subprocess.run([
                'netsh', 'wlan', 'delete', 'profile', f'name={ssid}'
            ], capture_output=True, text=True, encoding='cp949', timeout=10)
            
            if delete_result.returncode == 0:
                logger.info(f"WiFi profile '{ssid}' deleted successfully")
                return True
            else:
                logger.warning(f"WiFi profile deletion failed: {delete_result.stderr}")
                return False
                
        except Exception as e:
            logger.error(f"Error disconnecting WiFi and deleting profile: {e}")
            return False
    
    def check_and_handle_unwanted_networks(self):
        """원하지 않는 네트워크 연결 확인 및 처리"""
        try:
            # 현재 연결된 SSID 확인
            current_ssid = self.get_current_wifi_ssid()
            current_ip = self.get_current_ip_address()
            
            logger.debug(f"Current SSID: {current_ssid}, Current IP: {current_ip}")
            
            # GEO Mobile Wi-Fi 연결 확인
            if current_ssid and current_ssid == "GEO Mobile Wi-Fi":
                logger.warning(f"Unwanted SSID detected: {current_ssid}")
                if self.disconnect_wifi_and_delete_profile(current_ssid):
                    logger.info("Successfully disconnected from GEO Mobile Wi-Fi")
                    return True
            
            # IP 주소가 20.20.20.1/21 범위인지 확인
            if current_ip and self.is_ip_in_range(current_ip, "20.20.20.0/21"):
                logger.warning(f"Unwanted IP range detected: {current_ip}")
                if current_ssid:
                    if self.disconnect_wifi_and_delete_profile(current_ssid):
                        logger.info(f"Successfully disconnected from network with unwanted IP: {current_ip}")
                        return True
                else:
                    # SSID를 찾을 수 없는 경우 단순히 연결 끊기만 수행
                    subprocess.run(['netsh', 'wlan', 'disconnect'], 
                                 capture_output=True, text=True, encoding='cp949', timeout=10)
                    logger.info("Disconnected from network with unwanted IP")
                    return True
            
            return False
            
        except Exception as e:
            logger.error(f"Error checking unwanted networks: {e}")
            return False
    
    def get_rust_info(self):
        """icons.db에서 RUST 정보 조회"""
        try:
            # icons.db 경로
            icon_db_path = r'C:\Users\Administrator\Desktop\item\instance\icons.db'
            
            if not os.path.exists(icon_db_path):
                logger.warning(f"Icon database not found: {icon_db_path}")
                return None
                
            # 컴퓨터 이름 가져오기
            hostname = platform.node()
            
            # 읽기 전용 모드로 연결
            conn = sqlite3.connect(
                f"file:{icon_db_path}?mode=ro",
                uri=True,
                timeout=5.0
            )
            
            cursor = conn.cursor()
            cursor.execute("SELECT remote_address FROM icon WHERE comp_no = ?", (hostname,))
            result = cursor.fetchone()
            conn.close()
            
            if result:
                return result[0]
            return None
            
        except Exception as e:
            logger.error(f"Error getting RUST info: {e}")
            return None
    
    def show_pc_info(self):
        """컴퓨터 정보 표시"""
        logger.info("Showing PC info...")
        # 먼저 메뉴를 닫고 메시지박스 표시
        self.close_menu()
        
        try:
            # CPU 정보
            cpu_percent = psutil.cpu_percent(interval=1)
            cpu_count = psutil.cpu_count()
            
            # 메모리 정보
            memory = psutil.virtual_memory()
            memory_total = round(memory.total / (1024**3), 2)
            memory_used = round(memory.used / (1024**3), 2)
            memory_percent = memory.percent
            
            # 디스크 정보
            disk = psutil.disk_usage('/')
            disk_total = round(disk.total / (1024**3), 2)
            disk_used = round(disk.used / (1024**3), 2)
            disk_percent = disk.percent
            
            # RUST 정보 가져오기
            rust_info = self.get_rust_info()
            rust_display = rust_info if rust_info else "정보 없음"
            
            # 시스템 정보
            system_info = f"""컴퓨터 정보
            
운영체제: {platform.system()} {platform.release()}
프로세서: {self.get_cpu_info()}
CPU 코어: {cpu_count}개
CPU 사용률: {cpu_percent}%

메모리: {memory_used}GB / {memory_total}GB ({memory_percent}%)
디스크: {disk_used}GB / {disk_total}GB ({disk_percent}%)

컴퓨터 이름: {platform.node()}
RUST: {rust_display}"""
            
            messagebox.showinfo("컴퓨터 정보", system_info)
            
        except Exception as e:
            messagebox.showerror("오류", f"정보를 가져올 수 없습니다.\n{str(e)}")
    
    def open_auto_action(self):
        """자동조치 서브메뉴 열기"""
        logger.info("Opening auto action submenu...")
        # 현재 메뉴 닫기 (서브메뉴 위치를 계산하기 위해 마우스 위치 저장)
        mouse_x = self.mouse_x
        mouse_y = self.mouse_y
        self.close_menu()
        
        # 자동조치 서브메뉴 생성
        self.create_auto_action_submenu(mouse_x, mouse_y)
    
    def create_auto_action_submenu(self, x, y):
        """자동조치 서브메뉴 생성"""
        logger.info(f"Creating auto action submenu at position ({x}, {y})")
        
        # 이미 열려있으면 닫기
        if self.overlay:
            logger.info("Auto action submenu already open, closing...")
            self.close_menu()
            return
        
        self.mouse_x = x
        self.mouse_y = y
        
        # 오버레이 생성
        self.overlay = tk.Toplevel()
        self.overlay.attributes('-topmost', True)
        self.overlay.overrideredirect(True)
        
        # 윈도우 크기와 위치 설정
        window_size = 350
        
        # 멀티 모니터 지원을 위한 가상 화면 정보 가져오기
        virtual_x = self.overlay.winfo_vrootx()
        virtual_y = self.overlay.winfo_vrooty()
        virtual_width = self.overlay.winfo_vrootwidth()
        virtual_height = self.overlay.winfo_vrootheight()
        
        # 클릭 위치 기준으로 창 위치 설정
        window_x = x - window_size // 2
        window_y = y - window_size // 2
        
        # 화면 경계 체크
        min_x = virtual_x
        min_y = virtual_y
        max_x = virtual_x + virtual_width - window_size
        max_y = virtual_y + virtual_height - window_size
        
        if window_x < min_x:
            window_x = min_x
        elif window_x > max_x:
            window_x = max_x
        
        if window_y < min_y:
            window_y = min_y
        elif window_y > max_y:
            window_y = max_y
        
        self.overlay.geometry(f"{window_size}x{window_size}+{window_x}+{window_y}")
        
        # 원형 GUI를 위한 투명 배경 설정
        self.overlay.attributes('-alpha', 0.9)
        self.overlay.configure(bg='#191919')
        self.overlay.wm_attributes('-transparentcolor', '#191919')
        
        # 투명 배경 설정을 위한 전체 화면 오버레이
        self.background = tk.Toplevel()
        self.background.attributes('-topmost', True)
        self.background.attributes('-alpha', 0.01)
        self.background.overrideredirect(True)
        
        # 전체 가상 화면 크기로 설정
        self.background.geometry(f"{virtual_width}x{virtual_height}+{virtual_x}+{virtual_y}")
        
        # 배경 클릭 시 메뉴 닫기
        self.background.bind('<Button-1>', lambda e: self.close_menu())
        
        # 캔버스 생성
        self.canvas = tk.Canvas(
            self.overlay,
            width=window_size,
            height=window_size,
            bg='#191919',
            highlightthickness=0
        )
        self.canvas.pack()
        
        # 로컬 좌표 설정
        self.local_x = window_size // 2
        self.local_y = window_size // 2
        
        # 현대적인 원형 배경 추가
        self.create_modern_circular_background_auto_action()
        
        # 자동조치 버튼 생성
        self.create_auto_action_buttons()
        
        # 클릭 이벤트 바인딩
        self.canvas.bind('<Button-1>', self.on_click)
        self.overlay.bind('<Escape>', lambda e: self.close_menu())
        
        # 포커스 설정
        self.overlay.focus_set()
        self.overlay.focus_force()
        
        # 윈도우 업데이트
        self.overlay.update_idletasks()
        
        logger.info("Auto action submenu created successfully")
        
        # 애니메이션 시작
        self.start_auto_action_animations()
    
    def start_asset_monitoring(self):
        """백그라운드 자산 모니터링 시작"""
        logger.info("Starting background asset monitoring...")
        
        def register_asset():
            """실제 자산 등록 실행"""
            try:
                import requests
                import json
                import datetime
                import uuid
                
                # 서버 URL
                server_url = "http://192.168.0.240:8800"
                
                # 시스템 정보 수집
                hostname = platform.node()
                
                # 네트워크 정보 수집 (UI 상태 표시와 동일한 로직 사용)
                try:
                    # 네트워크 상태 UI에서 사용하는 함수들을 직접 호출
                    ip_address = self.get_local_ip()
                    network_info = self.get_network_info()
                    
                    logger.info(f"🔍 UI 기반 IP 획득: {ip_address}")
                    logger.info(f"🌐 UI 기반 네트워크 정보: {network_info}")
                    
                    # MAC 주소 획득
                    mac_address = ':'.join(['{:02x}'.format((uuid.getnode() >> elements) & 0xff) 
                                          for elements in range(5, -1, -1)])
                    
                    # 연결 유형 결정 (UI와 동일한 로직)
                    if "WiFi" in network_info:
                        connection_type = "무선"
                        # SSID 추출
                        if "(" in network_info and ")" in network_info:
                            ssid = network_info[network_info.find("(")+1:network_info.find(")")]
                        else:
                            ssid = ""
                    elif "유선" in network_info:
                        connection_type = "유선"
                        ssid = ""
                    else:
                        connection_type = "미연결"
                        ssid = ""
                    
                    logger.info(f"🔌 연결 유형: {connection_type}")
                    if ssid:
                        logger.info(f"📡 SSID: {ssid}")
                        
                except Exception as e:
                    logger.error(f"❌ UI 기반 네트워크 정보 수집 실패: {e}")
                    # fallback
                    ip_address = "127.0.0.1"
                    mac_address = "00:00:00:00:00:00"
                    connection_type = "미연결"
                    ssid = ""
                
                # 하드웨어 정보 수집
                try:
                    import psutil
                    ram_info = psutil.virtual_memory()
                    disk_info = psutil.disk_usage('/')
                    
                    # CPU 정보 정확히 가져오기
                    cpu_info = self.get_cpu_info()
                    
                    # 설치된 소프트웨어 목록 수집
                    software_list = self.get_installed_software()
                    
                    # COM 포트 정보 수집
                    com_ports = []
                    try:
                        import serial.tools.list_ports
                        ports = serial.tools.list_ports.comports()
                        for port in ports:
                            com_ports.append({
                                "port": port.device,
                                "description": port.description,
                                "hwid": port.hwid,
                                "active": True
                            })
                    except ImportError:
                        pass
                    
                except ImportError:
                    # psutil이 없는 경우 기본값
                    ram_info = type('obj', (object,), {
                        'total': 8 * 1024**3, 'used': 4 * 1024**3, 'percent': 50.0
                    })()
                    cpu_info = "Unknown CPU"
                    disk_info = type('obj', (object,), {
                        'total': 256 * 1024**3, 'used': 128 * 1024**3, 'percent': 50.0
                    })()
                    software_list = [{"name": "Python", "version": platform.python_version()}]
                    com_ports = []
                
                # 네트워크 인터페이스 정보
                network_interfaces = [{
                    "name": "로컬 영역 연결",
                    "ip": ip_address,
                    "mac": mac_address,
                    "connected": True if ip_address != "127.0.0.1" else False
                }]
                
                # 자산 데이터 구성
                asset_data = {
                    "hostname": hostname,
                    "ip_address": ip_address,
                    "mac_address": mac_address,
                    "hardware_info": {
                        "cpu_info": cpu_info,
                        "ram_total": int(ram_info.total),
                        "ram_used": int(ram_info.used),
                        "ram_percent": float(ram_info.percent),
                        "disk_total": int(disk_info.total),
                        "disk_used": int(disk_info.used),
                        "disk_percent": float(disk_info.percent),
                        "gpu_info": "N/A",
                        "motherboard": "N/A"
                    },
                    "network_info": {
                        "interfaces": network_interfaces
                    },
                    "software_info": {
                        "software_list": software_list
                    },
                    "com_ports": {
                        "ports": com_ports
                    },
                    "system_status": {
                        "cpu_percent": 0.0,  # 실시간으로 계산하지 않음
                        "ram_percent": float(ram_info.percent),
                        "disk_percent": float(disk_info.percent),
                        "uptime": 0  # 실시간으로 계산하지 않음
                    }
                }
                
                # 서버로 데이터 전송
                response = requests.post(f"{server_url}/api/asset/update", json=asset_data, timeout=10)
                
                if response.status_code == 200:
                    response_data = response.json()
                    asset_id = response_data.get('asset_id', 'Unknown')
                    
                    messagebox.showinfo(
                        "자산 등록 완료", 
                        f"자산이 성공적으로 등록되었습니다!\n\n"
                        f"호스트명: {hostname}\n"
                        f"IP 주소: {ip_address}\n" 
                        f"자산 ID: {asset_id}\n\n"
                        f"대시보드에서 확인하세요:\n"
                        f"http://192.168.0.240:8800/dashboard"
                    )
                    
                    # 대시보드 자동 열기
                    try:
                        webbrowser.open("http://192.168.0.240:8800/dashboard")
                    except:
                        pass
                        
                else:
                    messagebox.showerror(
                        "자산 등록 실패", 
                        f"자산 등록에 실패했습니다.\n"
                        f"상태 코드: {response.status_code}\n"
                        f"응답: {response.text}"
                    )
                    
            except ImportError as e:
                messagebox.showerror(
                    "라이브러리 오류",
                    f"필요한 라이브러리가 없습니다: {str(e)}\n"
                    f"pip install requests 명령으로 설치해주세요."
                )
            except Exception as e:
                messagebox.showerror(
                    "오류 발생", 
                    f"자산 등록 중 오류가 발생했습니다:\n{str(e)}\n\n"
                    f"서버가 실행 중인지 확인해주세요.\n"
                    f"서버 실행: python server.py"
                )
        
        def background_monitoring():
            """백그라운드에서 반복 실행"""
            import random
            import time
            
            # 첫 번째 실행은 즉시 수행
            try:
                logger.info("Sending initial asset data...")
                register_asset_silent()
                logger.info("Initial asset data sent successfully")
            except Exception as e:
                logger.error(f"Initial asset data send failed: {e}")
            
            while True:
                try:
                    # app.exe가 실행 중이 아니면 종료
                    if not is_app_exe_running():
                        logger.info("App.exe not running, stopping background monitoring")
                        break
                    
                    # 빌드된 환경에서 종료 신호 확인
                    if '_app_stop_event' in globals() and globals()['_app_stop_event'].is_set():
                        logger.info("Received stop signal from app.exe, stopping background monitoring")
                        break
                    
                    # 30초 간격으로 자산 업데이트 (대시보드와 동기화)
                    interval = 30
                    logger.info(f"Next asset monitoring in {interval} seconds")
                    
                    # 1초 단위로 체크하면서 대기
                    for i in range(interval):
                        if not is_app_exe_running():
                            logger.info("App.exe not running, stopping background monitoring")
                            return
                        if '_app_stop_event' in globals() and globals()['_app_stop_event'].is_set():
                            logger.info("Received stop signal from app.exe, stopping background monitoring")
                            return
                        time.sleep(1)
                    
                    # 자산 데이터 전송 (메시지 박스 없이)
                    register_asset_silent()
                    
                except Exception as e:
                    logger.error(f"Background monitoring error: {e}")
                    # 오류 발생 시 5분 후 재시도
                    time.sleep(300)
        
        def is_app_exe_running():
            """app.exe 프로세스가 실행 중인지 확인"""
            try:
                import psutil
                for proc in psutil.process_iter(['name']):
                    try:
                        if proc.info['name'] and proc.info['name'].lower() == 'app.exe':
                            return True
                    except (psutil.NoSuchProcess, psutil.AccessDenied):
                        continue
                return False
            except ImportError:
                logger.warning("psutil not available, assuming app.exe is running")
                return True
            except Exception as e:
                logger.error(f"Error checking app.exe process: {e}")
                return True  # 오류 시 기본적으로 실행 중으로 가정
        
        def register_asset_silent():
            """메시지 박스 없이 자산 등록"""
            # app.exe 프로세스 확인
            if not is_app_exe_running():
                logger.info("App.exe not running, skipping asset update")
                return
            
            try:
                import requests
                import json
                import datetime
                import uuid
                
                # 서버 URL
                server_url = "http://192.168.0.240:8800"
                
                # 시스템 정보 수집
                hostname = platform.node()
                
                # 네트워크 정보 수집 (UI 상태 표시와 동일한 로직 사용)
                try:
                    # 네트워크 상태 UI에서 사용하는 함수들을 직접 호출
                    ip_address = self.get_local_ip()
                    network_info = self.get_network_info()
                    
                    logger.info(f"🔍 UI 기반 IP 획득: {ip_address}")
                    logger.info(f"🌐 UI 기반 네트워크 정보: {network_info}")
                    
                    # MAC 주소 획득
                    mac_address = ':'.join(['{:02x}'.format((uuid.getnode() >> elements) & 0xff) 
                                          for elements in range(5, -1, -1)])
                    
                    # 연결 유형 결정 (UI와 동일한 로직)
                    if "WiFi" in network_info:
                        connection_type = "무선"
                        # SSID 추출
                        if "(" in network_info and ")" in network_info:
                            ssid = network_info[network_info.find("(")+1:network_info.find(")")]
                        else:
                            ssid = ""
                    elif "유선" in network_info:
                        connection_type = "유선"
                        ssid = ""
                    else:
                        connection_type = "미연결"
                        ssid = ""
                    
                    logger.info(f"🔌 연결 유형: {connection_type}")
                    if ssid:
                        logger.info(f"📡 SSID: {ssid}")
                        
                except Exception as e:
                    logger.error(f"❌ UI 기반 네트워크 정보 수집 실패: {e}")
                    # fallback
                    ip_address = "127.0.0.1"
                    mac_address = "00:00:00:00:00:00"
                    connection_type = "미연결"
                    ssid = ""
                
                # 하드웨어 정보 수집
                try:
                    import psutil
                    ram_info = psutil.virtual_memory()
                    disk_info = psutil.disk_usage('/')
                    
                    # CPU 정보 정확히 가져오기
                    cpu_info = self.get_cpu_info()
                    
                    # 설치된 소프트웨어 목록 수집
                    software_list = self.get_installed_software()
                    
                    # COM 포트 정보 수집
                    com_ports = []
                    try:
                        import serial.tools.list_ports
                        ports = serial.tools.list_ports.comports()
                        for port in ports:
                            com_ports.append({
                                "port": port.device,
                                "description": port.description,
                                "hwid": port.hwid,
                                "active": True
                            })
                    except ImportError:
                        logger.warning("Serial library not available for COM port detection")
                    except Exception as e:
                        logger.error(f"COM port detection error: {e}")
                    
                    # 네트워크 인터페이스 정보 (UI 기반으로 단순화)
                    network_interfaces = [{
                        "name": network_info,  # UI에 표시되는 정보 그대로 사용
                        "ip": ip_address,
                        "mac": mac_address,
                        "connected": True if connection_type != "미연결" else False
                    }]
                    
                    logger.info(f"📡 인터페이스 정보: {network_info} -> {connection_type}")
                    
                    # 자산 데이터 구성
                    asset_data = {
                        "hostname": hostname,
                        "ip_address": ip_address,
                        "mac_address": mac_address,
                        "hardware_info": {
                            "cpu_info": cpu_info,
                            "ram_total": int(ram_info.total),
                            "ram_used": int(ram_info.used),
                            "ram_percent": float(ram_info.percent),
                            "disk_total": int(disk_info.total),
                            "disk_used": int(disk_info.used),
                            "disk_percent": float(disk_info.percent),
                            "gpu_info": "N/A",
                            "motherboard": "N/A"
                        },
                        "network_info": {
                            "interfaces": network_interfaces
                        },
                        "software_info": {
                            "software_list": software_list
                        },
                        "com_ports": {
                            "ports": com_ports
                        },
                        "system_status": {
                            "cpu_percent": 0.0,  # 실시간으로 계산하지 않음
                            "ram_percent": float(ram_info.percent),
                            "disk_percent": float(disk_info.percent),
                            "uptime": 0  # 실시간으로 계산하지 않음
                        }
                    }
                    
                    # 서버 연결 가능 여부 체크
                    def check_server_connectivity():
                        """서버 연결 가능 여부 확인"""
                        try:
                            import socket
                            # 포트 8800으로 TCP 연결 시도
                            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                            sock.settimeout(3)  # 3초 타임아웃
                            result = sock.connect_ex(('192.168.0.240', 8800))
                            sock.close()
                            return result == 0
                        except Exception as e:
                            logger.debug(f"Server connectivity check failed: {e}")
                            return False
                    
                    # 서버 연결 확인
                    if not check_server_connectivity():
                        logger.info("Server not available, skipping asset data transmission")
                        return  # 서버에 연결할 수 없으면 패스
                    
                    # 서버로 데이터 전송 (재시도 로직 포함)
                    max_retries = 3
                    retry_count = 0
                    
                    while retry_count < max_retries:
                        try:
                            logger.debug(f"Attempting to send asset data (attempt {retry_count + 1}/{max_retries})")
                            response = requests.post(f"{server_url}/api/asset/update", json=asset_data, timeout=10)
                            
                            if response.status_code == 200:
                                response_data = response.json()
                                asset_id = response_data.get('asset_id', 'Unknown')
                                logger.info(f"Asset data sent successfully - Asset ID: {asset_id}")
                                return  # 성공 시 함수 종료
                            else:
                                logger.warning(f"Asset data send failed - Status: {response.status_code} (attempt {retry_count + 1})")
                                
                        except requests.exceptions.RequestException as e:
                            logger.warning(f"Request failed: {e} (attempt {retry_count + 1})")
                        except Exception as e:
                            logger.warning(f"Unexpected error during transmission: {e} (attempt {retry_count + 1})")
                        
                        retry_count += 1
                        
                        # 재시도 전 잠시 대기 (마지막 시도가 아닐 경우)
                        if retry_count < max_retries:
                            import time
                            time.sleep(2)  # 2초 대기 후 재시도
                    
                    # 모든 재시도 실패 시
                    logger.error(f"Failed to send asset data after {max_retries} attempts, skipping until next interval")
                        
                except Exception as e:
                    logger.error(f"Silent asset registration error: {e}")
                    
            except ImportError as e:
                logger.error(f"Required library missing: {e}")
            except Exception as e:
                logger.error(f"Asset registration error: {e}")
        
        # 백그라운드 스레드에서 모니터링 시작
        threading.Thread(target=background_monitoring, daemon=True).start()
        logger.info("Background asset monitoring started")
    
    def get_cpu_info(self):
        """CPU 정보를 정확하게 가져오기"""
        try:
            # Windows에서 WMI를 통해 CPU 정보 가져오기
            import subprocess
            result = subprocess.run([
                'wmic', 'cpu', 'get', 'name', '/format:value'
            ], capture_output=True, text=True, shell=True)
            
            if result.returncode == 0:
                for line in result.stdout.split('\n'):
                    if line.startswith('Name='):
                        cpu_name = line.replace('Name=', '').strip()
                        if cpu_name:
                            return cpu_name
            
            # WMI가 실패하면 레지스트리에서 가져오기
            try:
                import winreg
                key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, 
                                   r"HARDWARE\DESCRIPTION\System\CentralProcessor\0")
                cpu_name, _ = winreg.QueryValueEx(key, "ProcessorNameString")
                winreg.CloseKey(key)
                return cpu_name.strip()
            except:
                pass
                
            # cpuid 명령어 시도 (powershell)
            try:
                result = subprocess.run([
                    'powershell', '-Command', 
                    'Get-WmiObject -Class Win32_Processor | Select-Object -ExpandProperty Name'
                ], capture_output=True, text=True, shell=True)
                
                if result.returncode == 0:
                    cpu_name = result.stdout.strip()
                    if cpu_name:
                        return cpu_name
            except:
                pass
                
        except Exception as e:
            logger.warning(f"CPU 정보 수집 실패: {e}")
        
        # 모든 방법이 실패하면 기본 platform 정보 사용
        return platform.processor() or "Unknown CPU"
    
    def get_installed_software(self):
        """설치된 소프트웨어 목록 가져오기 (Windows 설치/제거 프로그램 수준)"""
        software_list = []
        
        try:
            # Windows 레지스트리에서 설치된 프로그램 정보 가져오기
            import winreg
            
            # 64비트 프로그램들
            reg_paths = [
                r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
                r"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
            ]
            
            for reg_path in reg_paths:
                try:
                    registry_key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, reg_path)
                    
                    for i in range(winreg.QueryInfoKey(registry_key)[0]):
                        try:
                            subkey_name = winreg.EnumKey(registry_key, i)
                            subkey = winreg.OpenKey(registry_key, subkey_name)
                            
                            try:
                                display_name, _ = winreg.QueryValueEx(subkey, "DisplayName")
                                
                                # 1. SystemComponent 확인 (가장 중요한 필터)
                                try:
                                    system_component, _ = winreg.QueryValueEx(subkey, "SystemComponent")
                                    if system_component == 1:  # SystemComponent가 1이면 제어판에 표시되지 않음
                                        winreg.CloseKey(subkey)
                                        continue
                                except FileNotFoundError:
                                    pass  # SystemComponent가 없으면 일반 프로그램
                                
                                # 2. WindowsInstaller 확인
                                try:
                                    windows_installer, _ = winreg.QueryValueEx(subkey, "WindowsInstaller")
                                    if windows_installer == 1:
                                        # WindowsInstaller가 1인 경우 추가 필터링
                                        try:
                                            no_remove, _ = winreg.QueryValueEx(subkey, "NoRemove")
                                            if no_remove == 1:  # 제거할 수 없는 항목
                                                winreg.CloseKey(subkey)
                                                continue
                                        except FileNotFoundError:
                                            pass
                                except FileNotFoundError:
                                    pass
                                
                                # 3. ParentKeyName 확인 (업데이트나 패치)
                                try:
                                    parent_key, _ = winreg.QueryValueEx(subkey, "ParentKeyName")
                                    if parent_key:  # ParentKeyName이 있으면 업데이트/패치
                                        winreg.CloseKey(subkey)
                                        continue
                                except FileNotFoundError:
                                    pass
                                
                                # 3.5. ReleaseType 확인 (업데이트/패치 타입)
                                try:
                                    release_type, _ = winreg.QueryValueEx(subkey, "ReleaseType")
                                    if release_type and release_type.lower() in ['update', 'hotfix', 'security update']:
                                        winreg.CloseKey(subkey)
                                        continue
                                except FileNotFoundError:
                                    pass
                                
                                # 4. 시스템 업데이트, 보안 패치, 개발도구 컴포넌트 제외
                                display_lower = display_name.lower()
                                if any(skip in display_lower for skip in [
                                    # Windows 업데이트 관련
                                    'security update', 'hotfix', 'update for', 'kb', 'service pack',
                                    '보안 업데이트', '핫픽스', '서비스 팩',
                                    
                                    # Microsoft 런타임 및 재배포 가능 패키지
                                    'microsoft visual c++ 2', 'microsoft .net framework',
                                    'redistributable', 'runtime', 'directx',
                                    'microsoft visual c++ runtime',
                                    
                                    # 개발 도구 관련
                                    'windows software development kit', 'sdk',
                                    'microsoft sql server compact', 'sql server',
                                    'windows mobile', 'microsoft application error reporting',
                                    
                                    # Office 공유 구성 요소
                                    'microsoft office shared', 'office shared',
                                    'microsoft report viewer', 'report viewer',
                                    'microsoft office click-to-run',
                                    
                                    # Windows 기본 구성 요소
                                    'windows driver package', 'device driver',
                                    'microsoft silverlight', 'windows live',
                                    'microsoft games for windows',
                                    
                                    # 언어팩 및 기타
                                    'language pack', 'mui', 'lcid',
                                    'windows installer', 'msi development tools',
                                    
                                    # .NET Framework 세부
                                    '.net framework', 'dotnet',
                                    
                                    # Visual Studio 구성 요소
                                    'microsoft visual studio', 'vs_', 'buildtools',
                                    
                                    # Windows 앱 스토어 앱들 (일부)
                                    'ms-resource:', 'packagefamilyname'
                                ]):
                                    winreg.CloseKey(subkey)
                                    continue
                                
                                # 5. Microsoft 시스템 구성 요소 추가 필터링
                                if (display_lower.startswith('microsoft') and 
                                    any(sys_comp in display_lower for sys_comp in [
                                        'help viewer', 'sync framework', 'expression',
                                        'compact framework', 'enterprise library',
                                        'patterns & practices', 'chart controls',
                                        'xml core services', 'web deploy'
                                    ])):
                                    winreg.CloseKey(subkey)
                                    continue
                                
                                # 5. 빈 DisplayName 제외
                                if not display_name.strip():
                                    winreg.CloseKey(subkey)
                                    continue
                                
                                # 6. GUID만 있는 이름 제외 (예: {GUID} 형태)
                                if display_name.startswith('{') and display_name.endswith('}') and len(display_name) == 38:
                                    winreg.CloseKey(subkey)
                                    continue
                                
                                # 버전 정보 가져오기
                                try:
                                    version, _ = winreg.QueryValueEx(subkey, "DisplayVersion")
                                except FileNotFoundError:
                                    version = "Unknown"
                                
                                # 게시자 정보 가져오기
                                try:
                                    publisher, _ = winreg.QueryValueEx(subkey, "Publisher")
                                except FileNotFoundError:
                                    publisher = "Unknown"
                                
                                # 설치 날짜 가져오기 (여러 필드 확인)
                                install_date = None
                                
                                # 1. InstallDate 필드 확인
                                try:
                                    install_date_raw, _ = winreg.QueryValueEx(subkey, "InstallDate")
                                    if install_date_raw:
                                        # YYYYMMDD 형식을 YYYY-MM-DD로 변환
                                        if len(str(install_date_raw)) == 8:
                                            install_date = f"{install_date_raw[:4]}-{install_date_raw[4:6]}-{install_date_raw[6:8]}"
                                        else:
                                            install_date = str(install_date_raw)
                                except (FileNotFoundError, WindowsError):
                                    pass
                                
                                # 2. InstallLocation의 폴더 생성 날짜 확인
                                if not install_date or install_date == "Unknown":
                                    try:
                                        install_location, _ = winreg.QueryValueEx(subkey, "InstallLocation")
                                        if install_location and os.path.exists(install_location):
                                            # 폴더 생성 시간 가져오기
                                            created_time = os.path.getctime(install_location)
                                            install_date = datetime.datetime.fromtimestamp(created_time).strftime('%Y-%m-%d')
                                    except (FileNotFoundError, WindowsError, OSError):
                                        pass
                                
                                # 3. 레지스트리 키 자체의 마지막 수정 시간 사용
                                if not install_date or install_date == "Unknown":
                                    try:
                                        # Windows 레지스트리 키의 마지막 수정 시간
                                        # 이 방법은 정확도가 떨어질 수 있지만 대체 방법으로 사용
                                        key_info = winreg.QueryInfoKey(subkey)
                                        if key_info and len(key_info) > 2:
                                            # FILETIME을 datetime으로 변환
                                            filetime = key_info[2]
                                            if filetime:
                                                # Windows FILETIME은 1601년 1월 1일부터의 100나노초 단위
                                                # Python datetime은 1970년 1월 1일부터의 초 단위
                                                # 변환: (filetime / 10000000) - 11644473600
                                                timestamp = (filetime / 10000000.0) - 11644473600
                                                if timestamp > 0:
                                                    install_date = datetime.datetime.fromtimestamp(timestamp).strftime('%Y-%m-%d')
                                    except Exception:
                                        pass
                                
                                # 4. UninstallString의 실행 파일 생성 날짜 확인 (마지막 대안)
                                if not install_date or install_date == "Unknown":
                                    try:
                                        uninstall_string, _ = winreg.QueryValueEx(subkey, "UninstallString")
                                        if uninstall_string:
                                            # 실행 파일 경로 추출
                                            exe_path = uninstall_string.strip('"').split('"')[0]
                                            if not os.path.exists(exe_path):
                                                # 경로에서 실행 파일만 추출
                                                import shlex
                                                parts = shlex.split(uninstall_string)
                                                if parts and os.path.exists(parts[0]):
                                                    exe_path = parts[0]
                                            
                                            if os.path.exists(exe_path):
                                                created_time = os.path.getctime(exe_path)
                                                install_date = datetime.datetime.fromtimestamp(created_time).strftime('%Y-%m-%d')
                                    except (FileNotFoundError, WindowsError, OSError):
                                        pass
                                
                                # 최종적으로 날짜가 없으면 Unknown
                                if not install_date:
                                    install_date = "Unknown"
                                
                                software_list.append({
                                    "name": display_name,
                                    "version": version,
                                    "publisher": publisher,
                                    "install_date": install_date
                                })
                                
                            except FileNotFoundError:
                                pass
                            
                            winreg.CloseKey(subkey)
                            
                        except Exception:
                            continue
                    
                    winreg.CloseKey(registry_key)
                    
                except Exception as e:
                    logger.warning(f"레지스트리 경로 {reg_path} 접근 실패: {e}")
                    continue
                    
        except ImportError:
            logger.warning("winreg 모듈을 사용할 수 없습니다.")
        except Exception as e:
            logger.warning(f"소프트웨어 목록 수집 실패: {e}")
        
        # PowerShell이나 기본 소프트웨어는 추가하지 않음 (레지스트리만 사용)
        # appwiz.cpl과 동일한 수준을 유지
        
        # 중복 제거 및 정렬
        unique_software = []
        seen_names = set()
        
        for software in software_list:
            if software['name'] not in seen_names:
                unique_software.append(software)
                seen_names.add(software['name'])
        
        # 이름으로 정렬
        unique_software.sort(key=lambda x: x['name'].lower())
        
        logger.info(f"수집된 소프트웨어 개수: {len(unique_software)}")
        return unique_software

    def open_settings(self):
        """설정 창 열기"""
        logger.info("Opening settings...")
        self.close_menu()
        
        # 설정 버튼 클릭 직후 상태창 클릭 일시 무시
        if hasattr(self, 'status_window') and self.status_window:
            import time
            self.status_window._settings_button_clicked_time = time.time()
            logger.info("Settings button clicked - status clicks will be ignored for 1 second")
        
        try:
            # 기존 설정 창이 있다면 안전하게 닫기
            if self.settings_window.settings_window:
                logger.info("Existing settings window found, closing...")
                self.settings_window.close_settings()
                
            # 새로운 설정 창 열기
            self.settings_window.show_settings()
            
        except Exception as e:
            logger.error(f"Error opening settings: {e}")
            # 오류 발생 시 편집 모드 강제 해제
            try:
                if self.status_window:
                    self.status_window.set_edit_mode(False)
            except:
                pass
    
    def perform_system_check(self):
        """점검 서브메뉴 표시"""
        logger.info("Opening system check submenu...")
        # 현재 메뉴 닫기 (서브메뉴 위치를 계산하기 위해 마우스 위치 저장)
        mouse_x = self.mouse_x
        mouse_y = self.mouse_y
        self.close_menu()
        
        # 서브메뉴 생성
        self.create_submenu(mouse_x, mouse_y)
    
    def create_website_submenu(self, x, y):
        """웹사이트 서브메뉴 생성"""
        logger.info(f"create_website_submenu called at position ({x}, {y})")
        
        # 이미 열려있으면 닫기
        if self.overlay:
            logger.info("Website submenu already open, closing...")
            self.close_menu()
            return
        
        self.mouse_x = x
        self.mouse_y = y
        
        # 오버레이 생성
        self.overlay = tk.Toplevel()
        self.overlay.attributes('-topmost', True)
        self.overlay.overrideredirect(True)
        
        # 윈도우 크기와 위치 설정
        window_size = 350  # 웹사이트 버튼들을 위한 크기
        
        # 멀티 모니터 지원을 위한 가상 화면 정보 가져오기
        virtual_x = self.overlay.winfo_vrootx()
        virtual_y = self.overlay.winfo_vrooty()
        virtual_width = self.overlay.winfo_vrootwidth()
        virtual_height = self.overlay.winfo_vrootheight()
        
        # 실제 화면 좌표 계산
        window_x = x - window_size // 2
        window_y = y - window_size // 2
        
        # 화면 경계 체크
        min_x = virtual_x
        min_y = virtual_y
        max_x = virtual_x + virtual_width - window_size
        max_y = virtual_y + virtual_height - window_size
        
        if window_x < min_x:
            window_x = min_x
        elif window_x > max_x:
            window_x = max_x
        
        if window_y < min_y:
            window_y = min_y
        elif window_y > max_y:
            window_y = max_y
        
        self.overlay.geometry(f"{window_size}x{window_size}+{window_x}+{window_y}")
        
        # 원형 GUI를 위한 투명 배경 설정
        self.overlay.attributes('-alpha', 0.9)
        self.overlay.configure(bg='#191919')
        self.overlay.wm_attributes('-transparentcolor', '#191919')
        
        # 투명 배경 설정을 위한 전체 화면 오버레이
        self.background = tk.Toplevel()
        self.background.attributes('-topmost', True)
        self.background.attributes('-alpha', 0.01)
        self.background.overrideredirect(True)
        
        # 전체 가상 화면 크기로 설정
        self.background.geometry(f"{virtual_width}x{virtual_height}+{virtual_x}+{virtual_y}")
        
        # 배경 클릭 시 메뉴 닫기
        self.background.bind('<Button-1>', lambda e: self.close_menu())
        
        # 캔버스 생성
        self.canvas = tk.Canvas(
            self.overlay,
            width=window_size,
            height=window_size,
            bg='#191919',
            highlightthickness=0
        )
        self.canvas.pack()
        
        # 로컬 좌표 설정
        self.local_x = window_size // 2
        self.local_y = window_size // 2
        
        # 현대적인 원형 배경 추가
        self.create_modern_circular_background_website()
        
        # 웹사이트 버튼 생성
        self.create_website_buttons()
        
        # 클릭 이벤트 바인딩
        self.canvas.bind('<Button-1>', self.on_click)
        self.overlay.bind('<Escape>', lambda e: self.close_menu())
        
        # 포커스 설정
        self.overlay.focus_set()
        self.overlay.focus_force()
        
        # 윈도우 업데이트
        self.overlay.update_idletasks()
        
        logger.info("Website submenu created successfully")
    
    def create_submenu(self, x, y):
        """점검 서브메뉴 생성"""
        logger.info(f"Creating submenu at position ({x}, {y})")
        
        # 이미 열려있으면 닫기
        if self.overlay:
            logger.info("Submenu already open, closing...")
            self.close_menu()
            return
        
        self.mouse_x = x
        self.mouse_y = y
        
        # 오버레이 생성 (버튼 영역만큼만)
        self.overlay = tk.Toplevel()
        self.overlay.attributes('-topmost', True)
        self.overlay.overrideredirect(True)
        
        # 윈도우 크기와 위치 설정 (버튼들이 들어갈 크기)
        window_size = 350  # 6개 버튼을 위해 크기 확대
        
        # 멀티 모니터 지원을 위한 가상 화면 정보 가져오기
        virtual_x = self.overlay.winfo_vrootx()
        virtual_y = self.overlay.winfo_vrooty()
        virtual_width = self.overlay.winfo_vrootwidth()
        virtual_height = self.overlay.winfo_vrootheight()
        
        # 클릭 위치 기준으로 창 위치 설정
        window_x = x - window_size // 2
        window_y = y - window_size // 2
        
        # 화면 경계 체크
        max_x = virtual_x + virtual_width - window_size
        max_y = virtual_y + virtual_height - window_size
        
        if window_x < virtual_x:
            window_x = virtual_x
        elif window_x > max_x:
            window_x = max_x
        
        if window_y < virtual_y:
            window_y = virtual_y
        elif window_y > max_y:
            window_y = max_y
        
        self.overlay.geometry(f"{window_size}x{window_size}+{window_x}+{window_y}")
        
        # 원형 GUI를 위한 투명 배경 설정 (서브메뉴)
        self.overlay.attributes('-alpha', 0.9)  # 90% 투명도
        self.overlay.configure(bg='#191919')  # 투명 처리될 배경색
        # 지정된 색상을 투명하게 만들어 원형 효과 구현
        self.overlay.wm_attributes('-transparentcolor', '#191919')
        
        # 투명 배경 설정을 위한 전체 화면 오버레이
        self.background = tk.Toplevel()
        self.background.attributes('-topmost', True)
        self.background.attributes('-alpha', 0.01)
        self.background.overrideredirect(True)
        
        # 전체 가상 화면 크기로 설정
        self.background.geometry(f"{virtual_width}x{virtual_height}+{virtual_x}+{virtual_y}")
        
        # 배경 클릭 시 메뉴 닫기
        self.background.bind('<Button-1>', lambda e: self.close_menu())
        
        # 캔버스 생성 (투명 배경)
        self.canvas = tk.Canvas(
            self.overlay,
            width=window_size,
            height=window_size,
            bg='#191919',
            highlightthickness=0
        )
        self.canvas.pack()
        
        # 로컬 좌표 설정
        self.local_x = window_size // 2
        self.local_y = window_size // 2
        
        # 현대적인 원형 배경 추가 (서브메뉴용)
        self.create_modern_circular_background_submenu()
        
        # 서브메뉴 버튼 생성
        self.create_submenu_buttons()
        
        # 클릭 이벤트 바인딩
        self.canvas.bind('<Button-1>', self.on_click)
        self.overlay.bind('<Escape>', lambda e: self.close_menu())
        
        # 포커스 설정
        self.overlay.focus_set()
        self.overlay.focus_force()
        
        # 윈도우 업데이트
        self.overlay.update_idletasks()
        
        logger.info("Submenu created successfully")
    
    def create_submenu_buttons(self):
        """서브메뉴 버튼 생성 (3개)"""
        logger.info("Creating submenu buttons...")
        
        radius = 110  # 중심에서 버튼까지의 거리 (확대)
        button_size = 70  # 버튼 크기 (확대)
        
        # 서브메뉴 버튼 정보 (6개)
        button_info = [
            {"text": "스캐너", "color": "#3498db", "command": self.open_scanner},
            {"text": "MES", "color": "#2ecc71", "command": self.open_mes},
            {"text": "GDRIVE", "color": "#e74c3c", "command": self.open_gdrive},
            {"text": "인터넷", "color": "#f39c12", "command": self.check_internet},
            {"text": "PC정보", "color": "#9b59b6", "command": self.show_pc_info},
            {"text": "소프트웨어", "color": "#1abc9c", "command": self.show_software_list}
        ]
        
        # 중심 원 그리기
        center_size = 25
        center_circle = self.canvas.create_oval(
            self.local_x - center_size,
            self.local_y - center_size,
            self.local_x + center_size,
            self.local_y + center_size,
            fill='#34495e',
            outline='white',
            width=2
        )
        
        # 중심 텍스트
        self.canvas.create_text(
            self.local_x,
            self.local_y,
            text="점검",
            font=('Arial', 10, 'bold'),
            fill='white'
        )
        
        # 버튼 생성
        self.buttons = []
        for i, btn_info in enumerate(button_info):
            # 각도 계산 (위쪽부터 시작, 6개 버튼이므로 60도 간격)
            angle = (i * 60 - 90) * math.pi / 180
            
            # 버튼 위치 계산
            btn_x = self.local_x + radius * math.cos(angle)
            btn_y = self.local_y + radius * math.sin(angle)
            
            # 버튼 생성
            x1 = btn_x - button_size/2
            y1 = btn_y - button_size/2
            x2 = btn_x + button_size/2
            y2 = btn_y + button_size/2
            
            # 원형 버튼
            btn = self.canvas.create_oval(
                x1, y1, x2, y2,
                fill=btn_info['color'],
                outline='white',
                width=2,
                tags=f"button_{i}"
            )
            
            # 버튼 텍스트
            text = self.canvas.create_text(
                btn_x, btn_y,
                text=btn_info['text'],
                font=('Arial', 9, 'bold'),
                fill='white',
                tags=f"button_{i}"
            )
            
            # 버튼 정보 저장
            self.buttons.append({
                "id": btn,
                "text_id": text,
                "x": btn_x,
                "y": btn_y,
                "size": button_size,
                "command": btn_info['command'],
                "color": btn_info['color'],
                "tag": f"button_{i}"
            })
            
            # 호버 이벤트 바인딩
            self.canvas.tag_bind(f"button_{i}", '<Enter>', lambda e, tag=f"button_{i}": self.on_button_hover(tag, True))
            self.canvas.tag_bind(f"button_{i}", '<Leave>', lambda e, tag=f"button_{i}": self.on_button_hover(tag, False))
            # 클릭 이벤트 바인딩 추가
            self.canvas.tag_bind(f"button_{i}", '<Button-1>', 
                (lambda cmd: lambda e: self.on_button_click(cmd))(btn_info["command"]))
        
        logger.info(f"Created {len(self.buttons)} submenu buttons")
    
    def open_scanner(self):
        """스캐너 COM 포트 스캔"""
        logger.info("Scanning COM ports...")
        self.close_menu()
        
        try:
            import serial
            from serial.tools import list_ports
            
            def find_active_com_ports(baud_rate=9600):
                active_ports = []
                
                for port in list_ports.comports():
                    if port.device.upper() in ("COM1", "COM2"):
                        continue
                        
                    desc_lower = (port.description or "").lower()
                    hwid_lower = (port.hwid or "").lower()
                    
                    virtual_keywords = (
                        "virtual", "bluetooth", "com0com", "eltima", "null-modem",
                        "가상", "블루투스", "표준 직렬 over bluetooth"
                    )
                    if any(k in desc_lower for k in virtual_keywords) or "bthenum" in hwid_lower:
                        continue
                    
                    try:
                        ser = serial.Serial(port.device, baud_rate, timeout=0.2)
                        ser.close()
                        active_ports.append({
                            "port": port.device,
                            "description": port.description
                        })
                    except:
                        pass
                
                return active_ports
            
            # COM 포트 스캔 실행
            logger.info("Starting COM port scan...")
            ports = find_active_com_ports()
            
            # 결과 메시지 생성
            if ports:
                port_list = []
                for port in ports:
                    port_list.append(f"🔌 {port['port']}: {port['description']}")
                
                result_msg = f"🔍 스캐너 COM 포트 검색 결과\n\n"
                result_msg += f"발견된 포트: {len(ports)}개\n\n"
                result_msg += "\n".join(port_list)
                result_msg += f"\n\n※ COM1, COM2 및 가상 포트는 제외됨"
                
                msg_title = "스캐너 포트 검색 - 완료"
                
            else:
                result_msg = f"🔍 스캐너 COM 포트 검색 결과\n\n"
                result_msg += f"사용 가능한 COM 포트를 찾을 수 없습니다.\n\n"
                result_msg += f"확인 사항:\n"
                result_msg += f"• 스캐너가 PC에 연결되어 있는지 확인\n"
                result_msg += f"• USB 케이블 연결 상태 확인\n"
                result_msg += f"• 드라이버 설치 여부 확인\n"
                result_msg += f"• 다른 프로그램에서 포트를 사용 중인지 확인"
                
                msg_title = "스캐너 포트 검색 - 포트 없음"
            
            messagebox.showinfo(msg_title, result_msg)
            logger.info(f"COM port scan completed: {len(ports)} ports found")
            
        except ImportError:
            error_msg = f"🚫 스캐너 기능 오류\n\n"
            error_msg += f"pyserial 라이브러리가 설치되지 않았습니다.\n\n"
            error_msg += f"설치 방법:\n"
            error_msg += f"pip install pyserial\n\n"
            error_msg += f"설치 후 프로그램을 다시 실행하세요."
            
            messagebox.showerror("스캐너 - 라이브러리 오류", error_msg)
            logger.error("pyserial library not installed")
            
        except Exception as e:
            error_msg = f"🚫 스캐너 COM 포트 검색 오류\n\n"
            error_msg += f"오류 내용: {str(e)}\n\n"
            error_msg += f"가능한 원인:\n"
            error_msg += f"• 시스템 권한 부족\n"
            error_msg += f"• COM 포트 접근 제한\n"
            error_msg += f"• 하드웨어 문제"
            
            messagebox.showerror("스캐너 - 시스템 오류", error_msg)
            logger.error(f"Scanner COM port scan error: {e}")
    
    def open_mes(self):
        """MES 통신 테스트 (10.10.10.10)"""
        logger.info("Testing MES connection to 10.10.10.10...")
        self.close_menu()
        
        try:
            import socket
            import time
            
            target_ip = "10.10.10.10"
            test_port = 445  # SMB 포트로 테스트
            timeout = 3  # 3초 타임아웃
            
            start_time = time.time()
            
            # TCP 소켓 테스트
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(timeout)
            
            try:
                result = sock.connect_ex((target_ip, test_port))
                end_time = time.time()
                response_time = round((end_time - start_time) * 1000, 2)
                
                if result == 0:
                    status_msg = f"🟢 MES 서버 연결 성공\n\n서버: {target_ip}:{test_port}\n응답시간: {response_time}ms\n상태: 정상"
                    msg_title = "MES 통신 테스트 - 성공"
                else:
                    status_msg = f"🔴 MES 서버 연결 실패\n\n서버: {target_ip}:{test_port}\n응답시간: {response_time}ms\n상태: 연결 불가"
                    msg_title = "MES 통신 테스트 - 실패"
                    
            except socket.timeout:
                status_msg = f"🔴 MES 서버 연결 타임아웃\n\n서버: {target_ip}:{test_port}\n타임아웃: {timeout}초\n상태: 응답 없음"
                msg_title = "MES 통신 테스트 - 타임아웃"
            except Exception as e:
                status_msg = f"🔴 MES 서버 연결 오류\n\n서버: {target_ip}:{test_port}\n오류: {str(e)}\n상태: 연결 실패"
                msg_title = "MES 통신 테스트 - 오류"
            finally:
                sock.close()
                
        except Exception as e:
            status_msg = f"🔴 네트워크 테스트 실행 오류\n\n오류 내용: {str(e)}"
            msg_title = "MES 통신 테스트 - 시스템 오류"
            
        messagebox.showinfo(msg_title, status_msg)
        logger.info(f"MES connection test completed: {target_ip}")
    
    def open_gdrive(self):
        """GDRIVE 통신 테스트 (192.168.2.4)"""
        logger.info("Testing GDRIVE connection to 192.168.2.4...")
        self.close_menu()
        
        try:
            import socket
            import time
            
            target_ip = "192.168.2.4"
            test_port = 445  # SMB 포트로 테스트 (일반적인 파일 서버)
            timeout = 3  # 3초 타임아웃
            
            start_time = time.time()
            
            # TCP 소켓 테스트
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(timeout)
            
            try:
                result = sock.connect_ex((target_ip, test_port))
                end_time = time.time()
                response_time = round((end_time - start_time) * 1000, 2)
                
                if result == 0:
                    status_msg = f"🟢 GDRIVE 서버 연결 성공\n\n서버: {target_ip}:{test_port}\n응답시간: {response_time}ms\n상태: 정상"
                    msg_title = "GDRIVE 통신 테스트 - 성공"
                else:
                    # SMB가 안되면 ping으로 재시도
                    try:
                        import subprocess
                        ping_result = subprocess.run(
                            ["ping", "-n", "1", "-w", "3000", target_ip],
                            capture_output=True,
                            text=True
                        )
                        
                        if ping_result.returncode == 0:
                            status_msg = f"🟡 GDRIVE 서버 Ping 응답\n\n서버: {target_ip}\nSMB 포트: 연결 불가\nPing: 응답함\n상태: 부분 연결"
                            msg_title = "GDRIVE 통신 테스트 - 부분 성공"
                        else:
                            status_msg = f"🔴 GDRIVE 서버 연결 실패\n\n서버: {target_ip}:{test_port}\n응답시간: {response_time}ms\nPing: 응답 없음\n상태: 연결 불가"
                            msg_title = "GDRIVE 통신 테스트 - 실패"
                    except:
                        status_msg = f"🔴 GDRIVE 서버 연결 실패\n\n서버: {target_ip}:{test_port}\n응답시간: {response_time}ms\n상태: 연결 불가"
                        msg_title = "GDRIVE 통신 테스트 - 실패"
                    
            except socket.timeout:
                status_msg = f"🔴 GDRIVE 서버 연결 타임아웃\n\n서버: {target_ip}:{test_port}\n타임아웃: {timeout}초\n상태: 응답 없음"
                msg_title = "GDRIVE 통신 테스트 - 타임아웃"
            except Exception as e:
                status_msg = f"🔴 GDRIVE 서버 연결 오류\n\n서버: {target_ip}:{test_port}\n오류: {str(e)}\n상태: 연결 실패"
                msg_title = "GDRIVE 통신 테스트 - 오류"
            finally:
                sock.close()
                
        except Exception as e:
            status_msg = f"🔴 네트워크 테스트 실행 오류\n\n오류 내용: {str(e)}"
            msg_title = "GDRIVE 통신 테스트 - 시스템 오류"
            
        messagebox.showinfo(msg_title, status_msg)
        logger.info(f"GDRIVE connection test completed: {target_ip}")
    
    def show_software_list(self):
        """설치된 소프트웨어 목록 표시"""
        logger.info("Showing installed software list...")
        self.close_menu()
        
        try:
            import subprocess
            from datetime import datetime
            
            # 소프트웨어 목록을 담을 리스트
            software_list = []
            
            # Windows에서 설치된 프로그램 목록 가져오기
            if platform.system() == "Windows":
                try:
                    # PowerShell을 사용하여 레지스트리에서 직접 읽기 (appwiz.cpl과 동일한 목록)
                    logger.info("Getting software list from registry...")
                    ps_command = """
                    $programs = @()
                    
                    # 64비트 프로그램
                    $64bit = Get-ItemProperty "HKLM:\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*" -ErrorAction SilentlyContinue |
                        Where-Object { 
                            $_.DisplayName -and 
                            $_.DisplayName -ne "" -and
                            $_.SystemComponent -ne 1 -and
                            $_.ReleaseType -ne "Security Update" -and
                            $_.ReleaseType -ne "Update Rollup" -and
                            $_.ReleaseType -ne "Hotfix" -and
                            $_.ParentKeyName -eq $null -and
                            ($_.WindowsInstaller -ne 1 -or $_.NoRemove -ne 1)
                        } |
                        Select-Object DisplayName, InstallDate, DisplayVersion, Publisher
                    
                    # 32비트 프로그램 (64비트 시스템에서)
                    $32bit = Get-ItemProperty "HKLM:\\Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*" -ErrorAction SilentlyContinue |
                        Where-Object { 
                            $_.DisplayName -and 
                            $_.DisplayName -ne "" -and
                            $_.SystemComponent -ne 1 -and
                            $_.ReleaseType -ne "Security Update" -and
                            $_.ReleaseType -ne "Update Rollup" -and
                            $_.ReleaseType -ne "Hotfix" -and
                            $_.ParentKeyName -eq $null -and
                            ($_.WindowsInstaller -ne 1 -or $_.NoRemove -ne 1)
                        } |
                        Select-Object DisplayName, InstallDate, DisplayVersion, Publisher
                    
                    # 현재 사용자 프로그램 (제한된 경우만)
                    $user = Get-ItemProperty "HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*" -ErrorAction SilentlyContinue |
                        Where-Object { 
                            $_.DisplayName -and 
                            $_.DisplayName -ne "" -and
                            $_.SystemComponent -ne 1 -and
                            $_.ReleaseType -ne "Security Update" -and
                            $_.ReleaseType -ne "Update Rollup" -and
                            $_.ReleaseType -ne "Hotfix" -and
                            $_.ParentKeyName -eq $null
                        } |
                        Select-Object DisplayName, InstallDate, DisplayVersion, Publisher
                    
                    # 모든 프로그램 합치기
                    $programs += $64bit
                    $programs += $32bit
                    $programs += $user
                    
                    # 중복 제거 및 정렬 (DisplayName으로)
                    $uniquePrograms = @{}
                    $programs | ForEach-Object {
                        if ($_.DisplayName -and -not $uniquePrograms.ContainsKey($_.DisplayName)) {
                            $uniquePrograms[$_.DisplayName] = $_
                        }
                    }
                    
                    $uniquePrograms.Values | Sort-Object DisplayName | ForEach-Object {
                        # CSV 형식으로 출력 (구분자: |) - 날짜 필드 제거
                        Write-Output "$($_.DisplayName)|$($_.DisplayVersion)|$($_.Publisher)"
                    }
                    """
                    
                    result = subprocess.run(
                        ["powershell", "-ExecutionPolicy", "Bypass", "-Command", ps_command],
                        capture_output=True,
                        text=True,
                        encoding='cp949'  # Windows 한글 인코딩
                    )
                    
                    if result.returncode == 0 and result.stdout.strip():
                        lines = result.stdout.strip().split('\n')
                        for line in lines:
                            if line.strip() and '|' in line:
                                parts = line.strip().split('|')
                                if len(parts) >= 1:
                                    name = parts[0].strip()
                                    version = parts[1].strip() if len(parts) > 1 and parts[1].strip() else ""
                                    publisher = parts[2].strip() if len(parts) > 2 and parts[2].strip() else ""
                                    
                                    # 표시 형식 (설치일 제거)
                                    if version:
                                        display_text = f"{name} (v{version})"
                                    else:
                                        display_text = name
                                    
                                    if publisher:
                                        display_text += f" [{publisher}]"
                                    
                                    software_list.append(display_text)
                    else:
                        logger.error(f"PowerShell command failed: {result.stderr}")
                        software_list.append("소프트웨어 목록을 가져올 수 없습니다.")
                
                except Exception as e:
                    logger.error(f"Failed to get software list: {e}")
                    software_list.append(f"소프트웨어 목록을 가져오는 중 오류 발생: {str(e)}")
            
            else:
                software_list.append("Windows 이외의 시스템은 아직 지원되지 않습니다.")
            
            # 목록이 비어있으면 메시지 추가
            if not software_list:
                software_list.append("설치된 소프트웨어를 찾을 수 없습니다.")
            
            # 정렬
            software_list.sort()
            
            # 결과 창 표시
            software_window = tk.Toplevel()
            software_window.title("설치된 소프트웨어 목록")
            software_window.geometry("600x500")
            software_window.resizable(True, True)
            
            # 상단 라벨
            info_label = ttk.Label(
                software_window,
                text=f"총 {len(software_list)}개의 프로그램이 설치되어 있습니다.",
                font=('Arial', 10, 'bold')
            )
            info_label.pack(pady=10)
            
            # 스크롤 가능한 텍스트 영역
            text_area = scrolledtext.ScrolledText(
                software_window,
                wrap=tk.WORD,
                font=('Consolas', 9),
                padx=10,
                pady=10
            )
            text_area.pack(fill=tk.BOTH, expand=True, padx=10, pady=(0, 10))
            
            # 소프트웨어 목록 표시
            text_area.insert(tk.END, "\n".join(software_list))
            text_area.config(state=tk.DISABLED)
            
            # 닫기 버튼
            close_btn = ttk.Button(
                software_window,
                text="닫기",
                command=software_window.destroy
            )
            close_btn.pack(pady=(0, 10))
            
            logger.info(f"Displayed {len(software_list)} installed programs")
            
        except Exception as e:
            logger.error(f"Software list error: {e}")
            messagebox.showerror("오류", f"소프트웨어 목록을 가져오는 중 오류가 발생했습니다:\n{str(e)}")

    def create_modern_circular_background_auto_action(self):
            """자동조치 서브메뉴의 심플한 원형 배경 생성"""
            logger.info("Creating simple circular background for auto action submenu")
            
            center_x, center_y = self.local_x, self.local_y
            radius = 160
            
            # 1. 메인 배경 원 (어두운 회색)
            self.canvas.create_oval(
                center_x - radius, center_y - radius,
                center_x + radius, center_y + radius,
                fill='#1a1a1a', outline='', tags='background'
            )
            
            # 2. 내부 원 (조금 더 밝은 회색)
            inner_radius = radius - 20
            self.canvas.create_oval(
                center_x - inner_radius, center_y - inner_radius,
                center_x + inner_radius, center_y + inner_radius,
                fill='#2a2a2a', outline='', tags='background'
            )
            
            # 3. 중앙 원 (버튼 영역)
            core_radius = radius - 40
            self.canvas.create_oval(
                center_x - core_radius, center_y - core_radius,
                center_x + core_radius, center_y + core_radius,
                fill='#333333', outline='', tags='background'
            )
            
            # 4. 심플한 외곽 테두리 (단일 네온 컬러)
            self.canvas.create_oval(
                center_x - radius, center_y - radius,
                center_x + radius, center_y + radius,
                fill='', outline='#4a9eff', width=2,
                tags='background'
            )
            
            # 5. 내부 테두리 (얇은 라인)
            self.canvas.create_oval(
                center_x - inner_radius, center_y - inner_radius,
                center_x + inner_radius, center_y + inner_radius,
                fill='', outline='#4a9eff', width=1,
                tags='background'
            )
            
            # 6. 중앙 포인트 (작은 점)
            center_dot_radius = 3
            self.canvas.create_oval(
                center_x - center_dot_radius, center_y - center_dot_radius,
                center_x + center_dot_radius, center_y + center_dot_radius,
                fill='#4a9eff', outline='', tags='background'
            )
            
            logger.info("Simple background created")
    
    def blend_color(self, color1, color2, ratio):
        """두 색상을 블렌딩"""
        # 간단한 색상 블렌딩 (hex to hex)
        return color1  # 단순화
        

    def create_auto_action_buttons(self):
        """자동조치 버튼 생성"""
        logger.info("Creating auto action buttons...")
        
        # 자동조치 버튼 정보
        button_info = [
            {"text": "네트워크 Fix", "color": "#e74c3c", "command": self.network_fix},
            {"text": "브라우저 Fix", "color": "#3498db", "command": self.browser_fix},
            {"text": "프린터 Fix", "color": "#2ecc71", "command": self.printer_fix},
            {"text": "MES Fix", "color": "#f39c12", "command": self.mes_fix}
        ]
        
        radius = 110  # 중심에서 버튼까지의 거리
        button_size = 70  # 버튼 크기
        
        # 중심 원 그리기
        center_size = 25
        center_circle = self.canvas.create_oval(
            self.local_x - center_size,
            self.local_y - center_size,
            self.local_x + center_size,
            self.local_y + center_size,
            fill='#34495e',
            outline='white',
            width=2
        )
        
        # 중심 텍스트
        self.canvas.create_text(
            self.local_x,
            self.local_y,
            text="자동조치",
            font=('Arial', 9, 'bold'),
            fill='white'
        )
        
        # 버튼 생성
        self.buttons = []
        for i, btn_info in enumerate(button_info):
            # 각도 계산 (위쪽부터 시작)
            angle = (i * (360 / len(button_info)) - 90) * math.pi / 180
            
            # 버튼 위치 계산
            btn_x = self.local_x + radius * math.cos(angle)
            btn_y = self.local_y + radius * math.sin(angle)
            
            # 버튼 생성
            x1 = btn_x - button_size/2
            y1 = btn_y - button_size/2
            x2 = btn_x + button_size/2
            y2 = btn_y + button_size/2
            
            # 원형 버튼
            btn = self.canvas.create_oval(
                x1, y1, x2, y2,
                fill=btn_info["color"],
                outline='white',
                width=2,
                tags=f"button_{i}"
            )
            
            # 버튼 텍스트
            text = self.canvas.create_text(
                btn_x, btn_y,
                text=btn_info['text'],
                font=('Arial', 9, 'bold'),
                fill='white',
                tags=f"button_{i}"
            )
            
            # 버튼 정보 저장
            self.buttons.append({
                "id": btn,
                "text_id": text,
                "x": btn_x,
                "y": btn_y,
                "size": button_size,
                "command": btn_info["command"],
                "color": btn_info["color"],
                "tag": f"button_{i}"
            })
            
            # 호버 이벤트 바인딩
            self.canvas.tag_bind(f"button_{i}", '<Enter>', 
                (lambda tag: lambda e: self.on_button_hover(tag, True))(f"button_{i}"))
            self.canvas.tag_bind(f"button_{i}", '<Leave>', 
                (lambda tag: lambda e: self.on_button_hover(tag, False))(f"button_{i}"))
            self.canvas.tag_bind(f"button_{i}", '<Button-1>', 
                (lambda cmd: lambda e: self.on_button_click(cmd))(btn_info["command"]))
            
            logger.info(f"Auto action button {i} ({btn_info['text']}) created at ({btn_x}, {btn_y})")
        
        logger.info(f"Created {len(self.buttons)} auto action buttons")
    
    # Fix 기능들
    def network_fix(self):
        """네트워크 Fix - 수동으로 네트워크 복구 및 MES 통신 테스트"""
        logger.info("Network Fix initiated")
        self.close_menu()
        
        def run_network_fix():
            try:
                # 진행 상황을 보여주는 다이얼로그 생성
                progress_window = tk.Toplevel()
                progress_window.title("네트워크 Fix")
                
                # 진행창을 관리 리스트에 추가
                RadialMenu.active_progress_windows.append(progress_window)
                
                # 창이 닫힐 때 리스트에서 제거
                def on_window_close():
                    try:
                        RadialMenu.active_progress_windows.remove(progress_window)
                    except:
                        pass
                    progress_window.destroy()
                
                progress_window.protocol("WM_DELETE_WINDOW", on_window_close)
                progress_window.geometry("500x400")
                progress_window.resizable(False, False)
                progress_window.transient(self.overlay if self.overlay else None)
                progress_window.grab_set()
                
                # 텍스트 영역 생성
                text_area = scrolledtext.ScrolledText(progress_window, height=20, width=60)
                text_area.pack(fill='both', expand=True, padx=10, pady=10)
                
                def log_progress(message):
                    text_area.insert(tk.END, f"{message}\n")
                    text_area.see(tk.END)
                    progress_window.update()
                
                log_progress("🔧 네트워크 Fix 시작...")
                log_progress("=" * 50)
                
                # 인터넷 연결 상태 확인
                is_online = self.check_internet_connection()
                if is_online:
                    log_progress("✅ 현재 인터넷 연결 상태: 온라인")
                    log_progress("⚠️  오프라인이 아니지만 강제로 네트워크 복구를 진행합니다.")
                else:
                    log_progress("❌ 현재 인터넷 연결 상태: 오프라인")
                    log_progress("🔄 네트워크 자동 복구를 시작합니다.")
                
                log_progress("\n🚀 6단계 네트워크 복구 과정 시작...")
                
                # 네트워크 자동 복구 실행
                recovery_success = self.auto_network_recovery()
                
                if recovery_success:
                    log_progress("\n✅ 네트워크 복구 완료!")
                else:
                    log_progress("\n❌ 네트워크 복구 실패")
                
                # MES 통신 테스트
                log_progress("\n🔍 MES 통신 테스트 시작...")
                mes_result = self.test_mes_communication()
                
                if mes_result:
                    log_progress("✅ MES 통신 테스트 성공! 정상적으로 통신되고 있습니다.")
                else:
                    log_progress("❌ MES 통신 테스트 실패. MES 서버 연결을 확인해주세요.")
                
                log_progress("\n" + "=" * 50)
                log_progress("🎉 네트워크 Fix 완료!")
                
                # 완료 버튼 추가
                button_frame = tk.Frame(progress_window)
                button_frame.pack(pady=10)
                
                close_button = tk.Button(button_frame, text="닫기", 
                                       command=on_window_close,
                                       bg='#3498db', fg='white', font=('Arial', 10, 'bold'))
                close_button.pack()
                
            except Exception as e:
                logger.error(f"Network fix error: {e}")
                messagebox.showerror("오류", f"네트워크 Fix 중 오류가 발생했습니다:\n{str(e)}")
        
        # 별도 스레드에서 실행
        import threading
        threading.Thread(target=run_network_fix, daemon=True).start()
    
    def browser_fix(self):
        """브라우저 Fix - 크롬, 엣지 브라우저 캐시/쿠키 삭제"""
        logger.info("Browser Fix initiated")
        self.close_menu()
        
        def run_browser_fix():
            try:
                # 진행 상황을 보여주는 다이얼로그 생성
                progress_window = tk.Toplevel()
                progress_window.title("브라우저 Fix")
                
                # 진행창을 관리 리스트에 추가
                RadialMenu.active_progress_windows.append(progress_window)
                
                # 창이 닫힐 때 리스트에서 제거
                def on_window_close():
                    try:
                        RadialMenu.active_progress_windows.remove(progress_window)
                    except:
                        pass
                    progress_window.destroy()
                
                progress_window.protocol("WM_DELETE_WINDOW", on_window_close)
                progress_window.geometry("500x300")
                progress_window.resizable(False, False)
                progress_window.transient(self.overlay if self.overlay else None)
                progress_window.grab_set()
                
                # 텍스트 영역 생성
                text_area = scrolledtext.ScrolledText(progress_window, height=15, width=60)
                text_area.pack(fill='both', expand=True, padx=10, pady=10)
                
                def log_progress(message):
                    text_area.insert(tk.END, f"{message}\n")
                    text_area.see(tk.END)
                    progress_window.update()
                
                log_progress("🌐 브라우저 Fix 시작...")
                log_progress("=" * 50)
                
                # 브라우저 프로세스 종료
                log_progress("🔄 브라우저 프로세스 종료 중...")
                
                browser_processes = ['chrome.exe', 'msedge.exe', 'iexplore.exe']
                for process in browser_processes:
                    try:
                        result = subprocess.run(['taskkill', '/F', '/IM', process], 
                                              capture_output=True, text=True)
                        if result.returncode == 0:
                            log_progress(f"✅ {process} 프로세스 종료됨")
                        else:
                            log_progress(f"ℹ️  {process} 프로세스가 실행 중이 아님")
                    except Exception as e:
                        log_progress(f"⚠️  {process} 종료 중 오류: {e}")
                
                time.sleep(2)
                
                # Chrome 캐시/쿠키 삭제
                log_progress("\n🗑️  Chrome 캐시/쿠키 삭제 중...")
                chrome_paths = [
                    os.path.expanduser("~\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Cache"),
                    os.path.expanduser("~\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Cookies"),
                    os.path.expanduser("~\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Web Data")
                ]
                
                for path in chrome_paths:
                    try:
                        if os.path.exists(path):
                            if os.path.isdir(path):
                                import shutil
                                shutil.rmtree(path, ignore_errors=True)
                                log_progress(f"✅ Chrome: {os.path.basename(path)} 폴더 삭제됨")
                            else:
                                os.remove(path)
                                log_progress(f"✅ Chrome: {os.path.basename(path)} 파일 삭제됨")
                        else:
                            log_progress(f"ℹ️  Chrome: {os.path.basename(path)} 없음")
                    except Exception as e:
                        log_progress(f"⚠️  Chrome {os.path.basename(path)} 삭제 실패: {e}")
                
                # Edge 캐시/쿠키 삭제
                log_progress("\n🗑️  Edge 캐시/쿠키 삭제 중...")
                edge_paths = [
                    os.path.expanduser("~\\AppData\\Local\\Microsoft\\Edge\\User Data\\Default\\Cache"),
                    os.path.expanduser("~\\AppData\\Local\\Microsoft\\Edge\\User Data\\Default\\Cookies"),
                    os.path.expanduser("~\\AppData\\Local\\Microsoft\\Edge\\User Data\\Default\\Web Data")
                ]
                
                for path in edge_paths:
                    try:
                        if os.path.exists(path):
                            if os.path.isdir(path):
                                import shutil
                                shutil.rmtree(path, ignore_errors=True)
                                log_progress(f"✅ Edge: {os.path.basename(path)} 폴더 삭제됨")
                            else:
                                os.remove(path)
                                log_progress(f"✅ Edge: {os.path.basename(path)} 파일 삭제됨")
                        else:
                            log_progress(f"ℹ️  Edge: {os.path.basename(path)} 없음")
                    except Exception as e:
                        log_progress(f"⚠️  Edge {os.path.basename(path)} 삭제 실패: {e}")
                
                log_progress("\n" + "=" * 50)
                log_progress("🎉 브라우저 Fix 완료!")
                log_progress("ℹ️  브라우저를 다시 시작하면 캐시/쿠키가 초기화됩니다.")
                
                # 완료 버튼 추가
                button_frame = tk.Frame(progress_window)
                button_frame.pack(pady=10)
                
                close_button = tk.Button(button_frame, text="닫기", 
                                       command=on_window_close,
                                       bg='#3498db', fg='white', font=('Arial', 10, 'bold'))
                close_button.pack()
                
            except Exception as e:
                logger.error(f"Browser fix error: {e}")
                messagebox.showerror("오류", f"브라우저 Fix 중 오류가 발생했습니다:\n{str(e)}")
        
        # 별도 스레드에서 실행
        import threading
        threading.Thread(target=run_browser_fix, daemon=True).start()
    

    def printer_fix(self):
        """프린터 Fix - 레지스트리 수정 및 스풀러 재시작"""
        logger.info("Printer Fix initiated")
        self.close_menu()
        
        def run_printer_fix():
            try:
                # 진행 상황을 보여주는 다이얼로그 생성
                progress_window = tk.Toplevel()
                progress_window.title("프린터 Fix")
                
                # 진행창을 관리 리스트에 추가
                RadialMenu.active_progress_windows.append(progress_window)
                
                # 창이 닫힐 때 리스트에서 제거
                def on_window_close():
                    try:
                        RadialMenu.active_progress_windows.remove(progress_window)
                    except:
                        pass
                    progress_window.destroy()
                
                progress_window.protocol("WM_DELETE_WINDOW", on_window_close)
                progress_window.geometry("500x400")
                progress_window.resizable(False, False)
                progress_window.transient(self.overlay if self.overlay else None)
                progress_window.grab_set()
                
                # 텍스트 영역 생성
                text_area = scrolledtext.ScrolledText(progress_window, height=20, width=60)
                text_area.pack(fill='both', expand=True, padx=10, pady=10)
                
                def log_progress(message):
                    text_area.insert(tk.END, f"{message}\n")
                    text_area.see(tk.END)
                    progress_window.update()
                
                log_progress("🖨️  프린터 Fix 시작...")
                log_progress("=" * 50)
                
                # 1. 레지스트리 수정
                log_progress("🔧 프린터 레지스트리 설정 수정 중...")
                reg_command = [
                    'REG', 'ADD', 
                    'HKLM\\System\\CurrentControlSet\\Control\\Print',
                    '/v', 'RpcAuthnLevelPrivacyEnabled',
                    '/t', 'REG_DWORD',
                    '/d', '0',
                    '/f'
                ]
                
                try:
                    result = subprocess.run(reg_command, capture_output=True, text=True, timeout=30)
                    if result.returncode == 0:
                        log_progress("✅ 레지스트리 설정 수정 완료")
                    else:
                        log_progress(f"⚠️  레지스트리 수정 경고: {result.stderr.strip()}")
                except Exception as e:
                    log_progress(f"❌ 레지스트리 수정 실패: {e}")
                
                # 2. 스풀러 서비스 중지
                log_progress("\n🔄 Print Spooler 서비스 중지 중...")
                try:
                    result = subprocess.run(['net', 'stop', 'spooler'], 
                                          capture_output=True, text=True, timeout=30)
                    if result.returncode == 0:
                        log_progress("✅ Print Spooler 서비스 중지됨")
                    else:
                        log_progress(f"⚠️  Spooler 중지 경고: {result.stderr.strip()}")
                except Exception as e:
                    log_progress(f"❌ Spooler 중지 실패: {e}")
                
                time.sleep(3)
                
                # 3. 스풀러 서비스 시작
                log_progress("\n🚀 Print Spooler 서비스 시작 중...")
                try:
                    result = subprocess.run(['net', 'start', 'spooler'], 
                                          capture_output=True, text=True, timeout=30)
                    if result.returncode == 0:
                        log_progress("✅ Print Spooler 서비스 시작됨")
                    else:
                        log_progress(f"⚠️  Spooler 시작 경고: {result.stderr.strip()}")
                except Exception as e:
                    log_progress(f"❌ Spooler 시작 실패: {e}")
                
                # 4. 추가 프린터 장애 해결 작업
                log_progress("\n🔧 추가 프린터 장애 해결 작업...")
                
                # 프린터 대기열 정리
                spooler_path = "C:\\Windows\\System32\\spool\\PRINTERS"
                try:
                    if os.path.exists(spooler_path):
                        import glob
                        spool_files = glob.glob(os.path.join(spooler_path, "*"))
                        if spool_files:
                            for file in spool_files:
                                try:
                                    os.remove(file)
                                    log_progress(f"✅ 대기열 파일 삭제: {os.path.basename(file)}")
                                except:
                                    pass
                        else:
                            log_progress("ℹ️  프린터 대기열이 이미 비어있습니다")
                    else:
                        log_progress("ℹ️  프린터 대기열 폴더를 찾을 수 없습니다")
                except Exception as e:
                    log_progress(f"⚠️  대기열 정리 중 오류: {e}")
                
                log_progress("\n" + "=" * 50)
                log_progress("🎉 프린터 Fix 완료!")
                log_progress("ℹ️  프린터 문제가 해결되었습니다. 프린터를 다시 사용해보세요.")
                
                # 장애 시 추천 명령어
                log_progress("\n📋 장애 지속 시 추천 명령어:")
                log_progress("1. 프린터 드라이버 재설치")
                log_progress("2. rundll32 printui.dll,PrintUIEntry /k (프린터 새로고침)")
                log_progress("3. sfc /scannow (시스템 파일 검사)")
                
                # 완료 버튼 추가
                button_frame = tk.Frame(progress_window)
                button_frame.pack(pady=10)
                
                close_button = tk.Button(button_frame, text="닫기", 
                                       command=on_window_close,
                                       bg='#2ecc71', fg='white', font=('Arial', 10, 'bold'))
                close_button.pack()
                
            except Exception as e:
                logger.error(f"Printer fix error: {e}")
                messagebox.showerror("오류", f"프린터 Fix 중 오류가 발생했습니다:\n{str(e)}")
        
        # 별도 스레드에서 실행
        import threading
        threading.Thread(target=run_printer_fix, daemon=True).start()


    def mes_fix(self):
        """MES Fix - pf_profile.ini 파일의 IP 설정 수정"""
        logger.info("MES Fix initiated")
        self.close_menu()
        
        def run_mes_fix():
            try:
                # 진행 상황을 보여주는 다이얼로그 생성
                progress_window = tk.Toplevel()
                progress_window.title("MES Fix")
                
                # 진행창을 관리 리스트에 추가
                RadialMenu.active_progress_windows.append(progress_window)
                
                # 창이 닫힐 때 리스트에서 제거
                def on_window_close():
                    try:
                        RadialMenu.active_progress_windows.remove(progress_window)
                    except:
                        pass
                    progress_window.destroy()
                
                progress_window.protocol("WM_DELETE_WINDOW", on_window_close)
                progress_window.geometry("500x350")
                progress_window.resizable(False, False)
                progress_window.transient(self.overlay if self.overlay else None)
                progress_window.grab_set()
                
                # 텍스트 영역 생성
                text_area = scrolledtext.ScrolledText(progress_window, height=18, width=60)
                text_area.pack(fill='both', expand=True, padx=10, pady=10)
                
                def log_progress(message):
                    text_area.insert(tk.END, f"{message}\n")
                    text_area.see(tk.END)
                    progress_window.update()
                
                log_progress("🏭 MES Fix 시작...")
                log_progress("=" * 50)
                
                # 사용 환경 확인
                env_setting = load_data('environment', 'office')
                log_progress(f"현재 사용 환경: {env_setting}")
                
                # IP 설정 결정
                if env_setting == 'office':
                    target_ip = "192.168.0.250,14333"
                    env_name = "사무용"
                else:  # field
                    target_ip = "10.10.10.10,14333"
                    env_name = "현장용"
                
                log_progress(f"설정할 IP: {target_ip} ({env_name})")
                
                # pf_profile.ini 파일 경로
                profile_path = "C:\\geopop\\commlib\\pf_profile.ini"
                
                log_progress(f"\n📁 파일 경로: {profile_path}")
                
                # 파일 존재 확인
                if not os.path.exists(profile_path):
                    log_progress("❌ pf_profile.ini 파일을 찾을 수 없습니다!")
                    log_progress("   파일 경로를 확인해주세요.")
                    
                    # 장애 시 추천 사항
                    log_progress("\n📋 파일이 없을 때 해결방법:")
                    log_progress("1. MES 프로그램이 정상 설치되었는지 확인")
                    log_progress("2. C:\\geopop\\commlib\\ 폴더 존재 여부 확인")
                    log_progress("3. MES 프로그램 재설치 고려")
                    return
                
                log_progress("✅ pf_profile.ini 파일 발견")
                
                # 파일 백업
                backup_path = profile_path + ".backup"
                try:
                    import shutil
                    shutil.copy2(profile_path, backup_path)
                    log_progress(f"✅ 백업 파일 생성: {backup_path}")
                except Exception as e:
                    log_progress(f"⚠️  백업 생성 실패: {e}")
                
                # 파일 읽기 및 수정
                log_progress("\n🔧 IP 설정 수정 중...")
                try:
                    # 파일 인코딩 자동 감지
                    encodings_to_try = ['utf-8', 'cp949', 'euc-kr', 'latin-1']
                    lines = None
                    used_encoding = None
                    
                    for encoding in encodings_to_try:
                        try:
                            with open(profile_path, 'r', encoding=encoding) as f:
                                lines = f.readlines()
                                used_encoding = encoding
                                log_progress(f"✅ 파일 인코딩 감지: {encoding}")
                                break
                        except UnicodeDecodeError:
                            continue
                    
                    if lines is None:
                        log_progress("❌ 파일 인코딩을 감지할 수 없습니다!")
                        return
                    
                    # [SERVER] 섹션 찾기 및 IP 수정
                    in_server_section = False
                    modified = False
                    
                    for i, line in enumerate(lines):
                        line_stripped = line.strip()
                        
                        if line_stripped == '[SERVER]':
                            in_server_section = True
                            log_progress("✅ [SERVER] 섹션 발견")
                            continue
                        
                        if in_server_section:
                            if line_stripped.startswith('[') and line_stripped.endswith(']'):
                                # 다른 섹션 시작
                                in_server_section = False
                                continue
                            
                            if line_stripped.startswith('IP='):
                                old_ip = line_stripped[3:]
                                lines[i] = f"IP={target_ip}\n"
                                log_progress(f"✅ IP 설정 변경: {old_ip} → {target_ip}")
                                modified = True
                                break
                    
                    if not modified:
                        log_progress("❌ IP= 설정을 찾을 수 없습니다!")
                        log_progress("\n📋 IP 설정이 없을 때 해결방법:")
                        log_progress("1. [SERVER] 섹션 존재 여부 확인")
                        log_progress("2. 파일 형식이 올바른지 확인")
                        log_progress("3. MES 설정 파일 복원 고려")
                        return
                    
                    # 파일 저장 (원본 인코딩 유지)
                    with open(profile_path, 'w', encoding=used_encoding) as f:
                        f.writelines(lines)
                    
                    log_progress("✅ 파일 저장 완료")
                    
                except Exception as e:
                    log_progress(f"❌ 파일 수정 실패: {e}")
                    log_progress("\n📋 파일 수정 실패 시 해결방법:")
                    log_progress("1. 관리자 권한으로 프로그램 실행")
                    log_progress("2. 파일이 사용 중인지 확인 후 종료")
                    log_progress("3. 백업 파일에서 복원")
                    return
                
                log_progress("\n" + "=" * 50)
                log_progress("🎉 MES Fix 완료!")
                log_progress(f"ℹ️  MES 서버 IP가 {env_name} 환경에 맞게 설정되었습니다.")
                log_progress("ℹ️  MES 프로그램을 재시작하세요.")
                
                # 완료 버튼 추가
                button_frame = tk.Frame(progress_window)
                button_frame.pack(pady=10)
                
                close_button = tk.Button(button_frame, text="닫기", 
                                       command=on_window_close,
                                       bg='#f39c12', fg='white', font=('Arial', 10, 'bold'))
                close_button.pack()
                
            except Exception as e:
                logger.error(f"MES fix error: {e}")
                messagebox.showerror("오류", f"MES Fix 중 오류가 발생했습니다:\n{str(e)}")
        
        # 별도 스레드에서 실행
        import threading
        threading.Thread(target=run_mes_fix, daemon=True).start()



    def start_auto_action_animations(self):
        """자동조치 서브메뉴 심플 애니메이션 시작"""
        if not hasattr(self, 'canvas') or not self.canvas:
            return
            
        # 페이드인 효과
        self.fade_in_animation()
        
        # 심플한 테두리 펄스 효과
        self.simple_border_pulse()
    
    def fade_in_animation(self, alpha=0.1):
        """페이드인 애니메이션"""
        if not hasattr(self, 'overlay') or not self.overlay:
            return
            
        if alpha < 0.9:
            self.overlay.attributes('-alpha', alpha)
            self.overlay.after(20, lambda: self.fade_in_animation(alpha + 0.1))
        else:
            self.overlay.attributes('-alpha', 0.9)
    
    def pulse_animation(self, scale=1.0, growing=True):
        """버튼 펄스 애니메이션"""
        if not hasattr(self, 'canvas') or not self.canvas:
            return
            
        try:
            # 모든 버튼에 펄스 효과
            for i in range(4):
                button_tag = f'button_{i}_glow'
                items = self.canvas.find_withtag(button_tag)
                if items:
                    for item in items:
                        coords = self.canvas.coords(item)
                        if len(coords) == 4:
                            center_x = (coords[0] + coords[2]) / 2
                            center_y = (coords[1] + coords[3]) / 2
                            size = (coords[2] - coords[0]) / 2
                            
                            new_size = size * scale
                            self.canvas.coords(item,
                                center_x - new_size, center_y - new_size,
                                center_x + new_size, center_y + new_size)
            
            # 다음 프레임 계산
            if growing:
                new_scale = scale + 0.02
                if new_scale > 1.1:
                    new_scale = 1.1
                    growing = False
            else:
                new_scale = scale - 0.02
                if new_scale < 0.9:
                    new_scale = 0.9
                    growing = True
            
            # 계속 애니메이션
            self.overlay.after(50, lambda: self.pulse_animation(new_scale, growing))
            
        except:
            pass
    
    def rotation_animation(self, angle=0):
        """배경 회전 애니메이션"""
        if not hasattr(self, 'canvas') or not self.canvas:
            return
            
        try:
            import math
            center_x, center_y = self.local_x, self.local_y
            
            # 회전하는 장식 선들 업데이트
            line_items = self.canvas.find_withtag('rotating_line')
            for item in line_items:
                self.canvas.delete(item)
            
            # 새로운 각도로 선 그리기
            for i in range(12):
                base_angle = i * 30 + angle
                rad = math.radians(base_angle)
                x1 = center_x + math.cos(rad) * 60
                y1 = center_y + math.sin(rad) * 60
                x2 = center_x + math.cos(rad) * 130
                y2 = center_y + math.sin(rad) * 130
                
                # 색상 변화
                color_val = int(abs(math.sin(rad)) * 100 + 50)
                line_color = f"#{color_val:02x}{color_val:02x}ff"
                
                self.canvas.create_line(
                    x1, y1, x2, y2,
                    fill=line_color, width=2, tags='rotating_line'
                )
            
            # 다음 프레임
            new_angle = (angle + 1) % 360
            self.overlay.after(30, lambda: self.rotation_animation(new_angle))
            
        except:
            pass
    def radar_sweep_animation(self, angle=0):
        """레이더 스윕 애니메이션"""
        if not hasattr(self, 'canvas') or not self.canvas:
            return
            
        try:
            import math
            center_x, center_y = self.local_x, self.local_y
            radius = 160
            
            # 기존 스윕 제거
            self.canvas.delete('radar_sweep')
            
            # 스윕 라인 (밝은 선)
            rad = math.radians(angle)
            x1 = center_x + math.cos(rad) * 20
            y1 = center_y + math.sin(rad) * 20
            x2 = center_x + math.cos(rad) * radius
            y2 = center_y + math.sin(rad) * radius
            
            self.canvas.create_line(
                x1, y1, x2, y2,
                fill='#00ffff', width=3, tags='radar_sweep'
            )
            
            # 스윕 트레일 (페이딩 효과)
            for i in range(5):
                trail_angle = angle - (i + 1) * 5
                trail_rad = math.radians(trail_angle)
                tx1 = center_x + math.cos(trail_rad) * 20
                ty1 = center_y + math.sin(trail_rad) * 20
                tx2 = center_x + math.cos(trail_rad) * radius
                ty2 = center_y + math.sin(trail_rad) * radius
                
                # 페이딩 색상
                alpha = 1.0 - (i * 0.2)
                trail_color = f"#00{int(255*alpha):02x}{int(255*alpha):02x}"
                
                self.canvas.create_line(
                    tx1, ty1, tx2, ty2,
                    fill=trail_color, width=max(1, 3-i), tags='radar_sweep'
                )
            
            # 다음 프레임
            new_angle = (angle + 3) % 360
            self.overlay.after(50, lambda: self.radar_sweep_animation(new_angle))
            
        except:
            pass
    
    def data_stream_animation(self):
        """데이터 스트림 애니메이션"""
        if not hasattr(self, 'canvas') or not self.canvas:
            return
            
        try:
            import random
            import math
            center_x, center_y = self.local_x, self.local_y
            
            # 기존 스트림 점들 제거
            self.canvas.delete('data_stream')
            
            # 새로운 스트림 점들 생성
            for _ in range(30):
                angle = random.randint(0, 360)
                distance = random.randint(40, 150)
                rad = math.radians(angle)
                dx = center_x + math.cos(rad) * distance
                dy = center_y + math.sin(rad) * distance
                
                # 랜덤 크기와 색상
                dot_size = random.randint(1, 2)
                colors = ['#00ffff', '#ff00ff', '#ffff00', '#00ff00']
                dot_color = random.choice(colors)
                
                self.canvas.create_oval(
                    dx - dot_size, dy - dot_size,
                    dx + dot_size, dy + dot_size,
                    fill=dot_color, outline='', tags='data_stream'
                )
                
                # 움직이는 점들 (궤도를 따라)
                trail_distance = distance - 5
                if trail_distance > 30:
                    trail_rad = math.radians(angle + 5)
                    tx = center_x + math.cos(trail_rad) * trail_distance
                    ty = center_y + math.sin(trail_rad) * trail_distance
                    
                    self.canvas.create_oval(
                        tx - 1, ty - 1, tx + 1, ty + 1,
                        fill=dot_color, outline='', tags='data_stream'
                    )
            
            # 다음 프레임
            self.overlay.after(100, self.data_stream_animation)
            
        except:
            pass
    
    def pulse_ring_animation(self, radius=50):
        """펄스 링 애니메이션"""
        if not hasattr(self, 'canvas') or not self.canvas:
            return
            
        try:
            center_x, center_y = self.local_x, self.local_y
            
            # 기존 펄스 링 제거
            self.canvas.delete('pulse_ring')
            
            # 펄스 링 생성 (확장되면서 페이드)
            max_radius = 160
            if radius < max_radius:
                # 투명도 계산
                alpha = 1.0 - (radius / max_radius)
                color_val = int(255 * alpha)
                ring_color = f"#{color_val:02x}{color_val:02x}ff"
                
                # 링 그리기
                self.canvas.create_oval(
                    center_x - radius, center_y - radius,
                    center_x + radius, center_y + radius,
                    fill='', outline=ring_color, width=2,
                    tags='pulse_ring'
                )
                
                # 다음 프레임
                new_radius = radius + 3
                self.overlay.after(30, lambda: self.pulse_ring_animation(new_radius))
            else:
                # 다시 시작
                self.overlay.after(500, lambda: self.pulse_ring_animation(50))
            
        except:
            pass
    def simple_border_pulse(self, alpha=0.3, growing=True):
        """심플한 테두리 펄스 애니메이션"""
        if not hasattr(self, 'canvas') or not self.canvas:
            return
            
        try:
            center_x, center_y = self.local_x, self.local_y
            radius = 160
            
            # 기존 펄스 테두리 제거
            self.canvas.delete('pulse_border')
            
            # 투명도에 따른 색상 계산
            color_intensity = int(74 + (157 - 74) * alpha)  # #4a9eff 기준
            pulse_color = f"#{color_intensity:02x}{color_intensity + 30:02x}ff"
            
            # 펄스 테두리 생성
            self.canvas.create_oval(
                center_x - radius - 2, center_y - radius - 2,
                center_x + radius + 2, center_y + radius + 2,
                fill='', outline=pulse_color, width=3,
                tags='pulse_border'
            )
            
            # 다음 프레임 계산
            if growing:
                new_alpha = alpha + 0.03
                if new_alpha > 0.8:
                    new_alpha = 0.8
                    growing = False
            else:
                new_alpha = alpha - 0.03
                if new_alpha < 0.3:
                    new_alpha = 0.3
                    growing = True
            
            # 계속 애니메이션
            self.overlay.after(100, lambda: self.simple_border_pulse(new_alpha, growing))
            
        except:
            pass
    def test_mes_communication(self):
        """MES 통신 테스트"""
        try:
            # 현재 환경 설정에 따른 MES 서버 정보
            env_setting = load_data('environment', 'office')
            
            if env_setting == 'office':
                mes_server = "192.168.0.250"
                mes_port = 14333
            else:  # field
                mes_server = "10.10.10.10"
                mes_port = 14333
            
            # 간단한 TCP 연결 테스트
            import socket
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(5)  # 5초 타임아웃
            
            try:
                result = sock.connect_ex((mes_server, mes_port))
                sock.close()
                return result == 0  # 0이면 연결 성공
            except Exception:
                return False
            
        except Exception as e:
            logger.error(f"MES communication test error: {e}")
            return False

    def auto_temp_cleanup(self):
        """자동 임시파일 삭제"""
        logger.info("Auto temp cleanup initiated")
        self.close_menu()
        messagebox.showinfo("자동 임시파일 삭제", "임시파일 삭제를 시작합니다.")
    
    def auto_registry_cleanup(self):
        """자동 레지스트리 정리"""
        logger.info("Auto registry cleanup initiated")
        self.close_menu()
        messagebox.showinfo("자동 레지스트리 정리", "레지스트리 정리를 시작합니다.")
    
    def auto_system_optimize(self):
        """자동 시스템 최적화"""
        logger.info("Auto system optimize initiated")
        self.close_menu()
        messagebox.showinfo("자동 시스템 최적화", "시스템 최적화를 시작합니다.")
    
    def auto_virus_scan(self):
        """자동 바이러스 검사"""
        logger.info("Auto virus scan initiated")
        self.close_menu()
        messagebox.showinfo("자동 바이러스 검사", "바이러스 검사를 시작합니다.")


def setup_input_listener():
    """입력 리스너 설정 (실행키 설정에 따라 동적 변경)"""
    try:
        # 먼저 pynput 시도
        from pynput import mouse as pynput_mouse
        from pynput import keyboard as pynput_keyboard
        use_pynput = True
        logger.info("Using pynput library for input handling")
    except ImportError:
        # pynput이 없으면 mouse/keyboard 라이브러리 사용
        try:
            import mouse
            import keyboard
            use_pynput = False
            logger.info("Using mouse/keyboard libraries for input handling")
        except ImportError as e:
            logger.error(f"Failed to import input libraries: {e}")
            from tkinter import messagebox
            messagebox.showerror("라이브러리 오류", 
                               "입력 라이브러리를 로드할 수 없습니다.\n"
                               "다음 명령으로 설치해주세요:\n"
                               "pip install pynput")
            raise
    
    radial_menu = RadialMenu()
    hotkey_type = load_data('hotkey_type', 'mouse_wheel')
    
    def show_radial_menu():
        """라디얼 메뉴 표시"""
        if use_pynput:
            # pynput 사용 시 현재 마우스 위치 가져오기
            controller = pynput_mouse.Controller()
            x, y = controller.position
        else:
            # mouse 라이브러리 사용
            x, y = mouse.get_position()
        
        logger.info(f"Hotkey triggered at ({x}, {y}) - type: {hotkey_type}")
        radial_menu.create_menu(x, y)
    
    # 실행키 타입에 따른 이벤트 등록
    if use_pynput:
        # pynput 사용
        if hotkey_type == 'mouse_wheel':
            # 마우스 휠 클릭 이벤트
            def on_click(x, y, button, pressed):
                if button == pynput_mouse.Button.middle and pressed:
                    show_radial_menu()
            
            mouse_listener = pynput_mouse.Listener(on_click=on_click)
            mouse_listener.start()
            logger.info("Pynput mouse wheel click listener setup completed")
            
        elif hotkey_type in ['f1', 'f2', 'f3', 'f4']:
            # F1~F4 키 이벤트
            from pynput.keyboard import Key, KeyCode
            key_map = {
                'f1': Key.f1,
                'f2': Key.f2, 
                'f3': Key.f3,
                'f4': Key.f4
            }
            target_key = key_map[hotkey_type]
            
            def on_press(key):
                if key == target_key:
                    show_radial_menu()
            
            kbd_listener = pynput_keyboard.Listener(on_press=on_press)
            kbd_listener.start()
            logger.info(f"Pynput {hotkey_type.upper()} key listener setup completed")
            
        elif hotkey_type == 'click_status':
            # 상태창 클릭은 StatusWindow 클래스에서 처리
            logger.info("Status window click mode - no global listener needed")
            
        else:
            # 기본값: 마우스 휠 클릭
            def on_click(x, y, button, pressed):
                if button == pynput_mouse.Button.middle and pressed:
                    show_radial_menu()
            
            mouse_listener = pynput_mouse.Listener(on_click=on_click)
            mouse_listener.start()
            logger.info("Pynput default mouse wheel click listener setup completed")
            
    else:
        # 기존 mouse/keyboard 라이브러리 사용
        if hotkey_type == 'mouse_wheel':
            mouse.on_middle_click(show_radial_menu)
            logger.info("Mouse wheel click listener setup completed")
            
        elif hotkey_type in ['f1', 'f2', 'f3', 'f4']:
            key_name = hotkey_type.upper()
            keyboard.on_press_key(key_name, lambda _: show_radial_menu())
            logger.info(f"{key_name} key listener setup completed")
            
        elif hotkey_type == 'click_status':
            logger.info("Status window click mode - no global listener needed")
            
        else:
            mouse.on_middle_click(show_radial_menu)
            logger.info("Default mouse wheel click listener setup completed")
    
    return radial_menu


def setup_input_listener_for_instance(radial_menu, hotkey_type):
    """특정 RadialMenu 인스턴스에 대해 입력 리스너 설정"""
    logger.info(f"Setting up input listener for hotkey type: {hotkey_type}")
    
    # 먼저 기존 리스너 정리
    if hasattr(radial_menu, 'cleanup_listeners'):
        radial_menu.cleanup_listeners()
    
    try:
        # 먼저 pynput 시도
        from pynput import mouse as pynput_mouse
        from pynput import keyboard as pynput_keyboard
        use_pynput = True
        logger.info("Using pynput library for input handling")
    except ImportError:
        # pynput이 없으면 mouse/keyboard 라이브러리 사용
        try:
            import mouse
            import keyboard
            use_pynput = False
            logger.info("Using mouse/keyboard libraries for input handling")
        except ImportError as e:
            logger.error(f"Failed to import input libraries: {e}")
            return
    
    def show_radial_menu():
        """라디얼 메뉴 표시"""
        if use_pynput:
            controller = pynput_mouse.Controller()
            x, y = controller.position
        else:
            x, y = mouse.get_position()
        
        logger.info(f"Hotkey triggered at ({x}, {y}) - type: {hotkey_type}")
        radial_menu.create_menu(x, y)
    
    # 실행키 타입에 따른 이벤트 등록
    if use_pynput:
        if hotkey_type == 'mouse_wheel':
            def on_click(x, y, button, pressed):
                if button == pynput_mouse.Button.middle and pressed:
                    show_radial_menu()
            
            mouse_listener = pynput_mouse.Listener(on_click=on_click)
            mouse_listener.start()
            radial_menu.active_listeners.append(mouse_listener)
            logger.info("Pynput mouse wheel click listener setup completed")
            
        elif hotkey_type in ['f1', 'f2', 'f3', 'f4']:
            from pynput.keyboard import Key, KeyCode
            key_map = {
                'f1': Key.f1,
                'f2': Key.f2, 
                'f3': Key.f3,
                'f4': Key.f4
            }
            target_key = key_map[hotkey_type]
            
            def on_press(key):
                if key == target_key:
                    show_radial_menu()
            
            kbd_listener = pynput_keyboard.Listener(on_press=on_press)
            kbd_listener.start()
            radial_menu.active_listeners.append(kbd_listener)
            logger.info(f"Pynput {hotkey_type.upper()} key listener setup completed")
            
        elif hotkey_type == 'click_status':
            logger.info("Status window click mode - setting up PyQt click listener if needed")
            # PyQt 창이 있는 경우 클릭 리스너 재설정
            if hasattr(radial_menu, 'status_window') and radial_menu.status_window:
                status_window = radial_menu.status_window
                if hasattr(status_window, 'qt_widget') and status_window.qt_widget:
                    # PyQt 창의 현재 위치와 크기 가져오기
                    x = status_window.qt_widget.x()
                    y = status_window.qt_widget.y() 
                    width = status_window.qt_widget.width()
                    height = status_window.qt_widget.height()
                    # PyQt 클릭 리스너 재설정
                    if hasattr(status_window, 'setup_pyqt_click_listener'):
                        status_window.setup_pyqt_click_listener(x, y, width, height)
            
        else:
            # 기본값: 마우스 휠 클릭
            def on_click(x, y, button, pressed):
                if button == pynput_mouse.Button.middle and pressed:
                    show_radial_menu()
            
            mouse_listener = pynput_mouse.Listener(on_click=on_click)
            mouse_listener.start()
            radial_menu.active_listeners.append(mouse_listener)
            logger.info("Pynput default mouse wheel click listener setup completed")
            
    else:
        # 기존 mouse/keyboard 라이브러리 사용
        if hotkey_type == 'mouse_wheel':
            mouse.on_middle_click(show_radial_menu)
        elif hotkey_type in ['f1', 'f2', 'f3', 'f4']:
            keyboard.on_press_key(hotkey_type.upper(), lambda _: show_radial_menu())
        elif hotkey_type == 'ctrl_space':
            try:
                keyboard.add_hotkey('ctrl+space', show_radial_menu, suppress=True)
            except Exception as e:
                logger.error(f"Failed to register Ctrl+Space: {e}")
                def check_ctrl_space():
                    if keyboard.is_pressed('ctrl') and keyboard.is_pressed('space'):
                        show_radial_menu()
                keyboard.on_press_key('space', lambda _: check_ctrl_space())
        elif hotkey_type == 'alt_space':
            try:
                keyboard.add_hotkey('alt+space', show_radial_menu, suppress=True)
            except Exception as e:
                logger.error(f"Failed to register Alt+Space: {e}")
                def check_alt_space():
                    if keyboard.is_pressed('alt') and keyboard.is_pressed('space'):
                        show_radial_menu()
                keyboard.on_press_key('space', lambda _: check_alt_space())
        elif hotkey_type == 'click_status':
            logger.info("Status window click mode - no global listener needed")
        else:
            mouse.on_middle_click(show_radial_menu)
    
    def create_auto_action_buttons(self):
        """자동조치 버튼 생성"""
        logger.info("Creating auto action buttons...")
        
        # 자동조치 버튼 정보
        button_info = [
            {"text": "네트워크 Fix", "color": "#e74c3c", "command": self.network_fix},
            {"text": "브라우저 Fix", "color": "#3498db", "command": self.browser_fix},
            {"text": "프린터 Fix", "color": "#2ecc71", "command": self.printer_fix},
            {"text": "MES Fix", "color": "#f39c12", "command": self.mes_fix}
        ]
        
        radius = 110  # 중심에서 버튼까지의 거리
        button_size = 70  # 버튼 크기
        
        # 중심 원 그리기
        center_size = 25
        center_circle = self.canvas.create_oval(
            self.local_x - center_size,
            self.local_y - center_size,
            self.local_x + center_size,
            self.local_y + center_size,
            fill='#34495e',
            outline='white',
            width=2
        )
        
        # 중심 텍스트
        self.canvas.create_text(
            self.local_x,
            self.local_y,
            text="자동조치",
            font=('Arial', 9, 'bold'),
            fill='white'
        )
        
        # 버튼 생성
        self.buttons = []
        for i, btn_info in enumerate(button_info):
            # 각도 계산 (위쪽부터 시작)
            angle = (i * (360 / len(button_info)) - 90) * math.pi / 180
            
            # 버튼 위치 계산
            btn_x = self.local_x + radius * math.cos(angle)
            btn_y = self.local_y + radius * math.sin(angle)
            
            # 버튼 생성
            x1 = btn_x - button_size/2
            y1 = btn_y - button_size/2
            x2 = btn_x + button_size/2
            y2 = btn_y + button_size/2
            
            # 원형 버튼
            btn = self.canvas.create_oval(
                x1, y1, x2, y2,
                fill=btn_info["color"],
                outline='white',
                width=2,
                tags=f"button_{i}"
            )
            
            # 버튼 텍스트
            text = self.canvas.create_text(
                btn_x, btn_y,
                text=btn_info['text'],
                font=('Arial', 9, 'bold'),
                fill='white',
                tags=f"button_{i}"
            )
            
            # 버튼 정보 저장
            self.buttons.append({
                "id": btn,
                "text_id": text,
                "x": btn_x,
                "y": btn_y,
                "size": button_size,
                "command": btn_info["command"],
                "color": btn_info["color"],
                "tag": f"button_{i}"
            })
            
            # 호버 이벤트 바인딩
            self.canvas.tag_bind(f"button_{i}", '<Enter>', 
                (lambda tag: lambda e: self.on_button_hover(tag, True))(f"button_{i}"))
            self.canvas.tag_bind(f"button_{i}", '<Leave>', 
                (lambda tag: lambda e: self.on_button_hover(tag, False))(f"button_{i}"))
            self.canvas.tag_bind(f"button_{i}", '<Button-1>', 
                (lambda cmd: lambda e: self.on_button_click(cmd))(btn_info["command"]))
            
            logger.info(f"Auto action button {i} ({btn_info['text']}) created at ({btn_x}, {btn_y})")
        
        logger.info(f"Created {len(self.buttons)} auto action buttons")
    
    # Fix 기능들
    def network_fix(self):
        """네트워크 Fix - 수동으로 네트워크 복구 및 MES 통신 테스트"""
        logger.info("Network Fix initiated")
        self.close_menu()
        
        def run_network_fix():
            try:
                # 진행 상황을 보여주는 다이얼로그 생성
                progress_window = tk.Toplevel()
                progress_window.title("네트워크 Fix")
                
                # 진행창을 관리 리스트에 추가
                RadialMenu.active_progress_windows.append(progress_window)
                
                # 창이 닫힐 때 리스트에서 제거
                def on_window_close():
                    try:
                        RadialMenu.active_progress_windows.remove(progress_window)
                    except:
                        pass
                    progress_window.destroy()
                
                progress_window.protocol("WM_DELETE_WINDOW", on_window_close)
                progress_window.geometry("500x400")
                progress_window.resizable(False, False)
                progress_window.transient(self.overlay if self.overlay else None)
                progress_window.grab_set()
                
                # 텍스트 영역 생성
                text_area = scrolledtext.ScrolledText(progress_window, height=20, width=60)
                text_area.pack(fill='both', expand=True, padx=10, pady=10)
                
                def log_progress(message):
                    text_area.insert(tk.END, f"{message}\n")
                    text_area.see(tk.END)
                    progress_window.update()
                
                log_progress("🔧 네트워크 Fix 시작...")
                log_progress("=" * 50)
                
                # 인터넷 연결 상태 확인
                is_online = self.check_internet_connection()
                if is_online:
                    log_progress("✅ 현재 인터넷 연결 상태: 온라인")
                    log_progress("⚠️  오프라인이 아니지만 강제로 네트워크 복구를 진행합니다.")
                else:
                    log_progress("❌ 현재 인터넷 연결 상태: 오프라인")
                    log_progress("🔄 네트워크 자동 복구를 시작합니다.")
                
                log_progress("\n🚀 6단계 네트워크 복구 과정 시작...")
                
                # 네트워크 자동 복구 실행
                recovery_success = self.auto_network_recovery()
                
                if recovery_success:
                    log_progress("\n✅ 네트워크 복구 완료!")
                else:
                    log_progress("\n❌ 네트워크 복구 실패")
                
                # MES 통신 테스트
                log_progress("\n🔍 MES 통신 테스트 시작...")
                mes_result = self.test_mes_communication()
                
                if mes_result:
                    log_progress("✅ MES 통신 테스트 성공! 정상적으로 통신되고 있습니다.")
                else:
                    log_progress("❌ MES 통신 테스트 실패. MES 서버 연결을 확인해주세요.")
                
                log_progress("\n" + "=" * 50)
                log_progress("🎉 네트워크 Fix 완료!")
                
                # 완료 버튼 추가
                button_frame = tk.Frame(progress_window)
                button_frame.pack(pady=10)
                
                close_button = tk.Button(button_frame, text="닫기", 
                                       command=on_window_close,
                                       bg='#3498db', fg='white', font=('Arial', 10, 'bold'))
                close_button.pack()
                
            except Exception as e:
                logger.error(f"Network fix error: {e}")
                messagebox.showerror("오류", f"네트워크 Fix 중 오류가 발생했습니다:\n{str(e)}")
        
        # 별도 스레드에서 실행
        import threading
        threading.Thread(target=run_network_fix, daemon=True).start()
    
    def browser_fix(self):
        """브라우저 Fix - 크롬, 엣지 브라우저 캐시/쿠키 삭제"""
        logger.info("Browser Fix initiated")
        self.close_menu()
        
        def run_browser_fix():
            try:
                # 진행 상황을 보여주는 다이얼로그 생성
                progress_window = tk.Toplevel()
                progress_window.title("브라우저 Fix")
                
                # 진행창을 관리 리스트에 추가
                RadialMenu.active_progress_windows.append(progress_window)
                
                # 창이 닫힐 때 리스트에서 제거
                def on_window_close():
                    try:
                        RadialMenu.active_progress_windows.remove(progress_window)
                    except:
                        pass
                    progress_window.destroy()
                
                progress_window.protocol("WM_DELETE_WINDOW", on_window_close)
                progress_window.geometry("500x300")
                progress_window.resizable(False, False)
                progress_window.transient(self.overlay if self.overlay else None)
                progress_window.grab_set()
                
                # 텍스트 영역 생성
                text_area = scrolledtext.ScrolledText(progress_window, height=15, width=60)
                text_area.pack(fill='both', expand=True, padx=10, pady=10)
                
                def log_progress(message):
                    text_area.insert(tk.END, f"{message}\n")
                    text_area.see(tk.END)
                    progress_window.update()
                
                log_progress("🌐 브라우저 Fix 시작...")
                log_progress("=" * 50)
                
                # 브라우저 프로세스 종료
                log_progress("🔄 브라우저 프로세스 종료 중...")
                
                browser_processes = ['chrome.exe', 'msedge.exe', 'iexplore.exe']
                for process in browser_processes:
                    try:
                        result = subprocess.run(['taskkill', '/F', '/IM', process], 
                                              capture_output=True, text=True)
                        if result.returncode == 0:
                            log_progress(f"✅ {process} 프로세스 종료됨")
                        else:
                            log_progress(f"ℹ️  {process} 프로세스가 실행 중이 아님")
                    except Exception as e:
                        log_progress(f"⚠️  {process} 종료 중 오류: {e}")
                
                time.sleep(2)
                
                # Chrome 캐시/쿠키 삭제
                log_progress("\n🗑️  Chrome 캐시/쿠키 삭제 중...")
                chrome_paths = [
                    os.path.expanduser("~\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Cache"),
                    os.path.expanduser("~\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Cookies"),
                    os.path.expanduser("~\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Web Data")
                ]
                
                for path in chrome_paths:
                    try:
                        if os.path.exists(path):
                            if os.path.isdir(path):
                                import shutil
                                shutil.rmtree(path, ignore_errors=True)
                                log_progress(f"✅ Chrome: {os.path.basename(path)} 폴더 삭제됨")
                            else:
                                os.remove(path)
                                log_progress(f"✅ Chrome: {os.path.basename(path)} 파일 삭제됨")
                        else:
                            log_progress(f"ℹ️  Chrome: {os.path.basename(path)} 없음")
                    except Exception as e:
                        log_progress(f"⚠️  Chrome {os.path.basename(path)} 삭제 실패: {e}")
                
                # Edge 캐시/쿠키 삭제
                log_progress("\n🗑️  Edge 캐시/쿠키 삭제 중...")
                edge_paths = [
                    os.path.expanduser("~\\AppData\\Local\\Microsoft\\Edge\\User Data\\Default\\Cache"),
                    os.path.expanduser("~\\AppData\\Local\\Microsoft\\Edge\\User Data\\Default\\Cookies"),
                    os.path.expanduser("~\\AppData\\Local\\Microsoft\\Edge\\User Data\\Default\\Web Data")
                ]
                
                for path in edge_paths:
                    try:
                        if os.path.exists(path):
                            if os.path.isdir(path):
                                import shutil
                                shutil.rmtree(path, ignore_errors=True)
                                log_progress(f"✅ Edge: {os.path.basename(path)} 폴더 삭제됨")
                            else:
                                os.remove(path)
                                log_progress(f"✅ Edge: {os.path.basename(path)} 파일 삭제됨")
                        else:
                            log_progress(f"ℹ️  Edge: {os.path.basename(path)} 없음")
                    except Exception as e:
                        log_progress(f"⚠️  Edge {os.path.basename(path)} 삭제 실패: {e}")
                
                log_progress("\n" + "=" * 50)
                log_progress("🎉 브라우저 Fix 완료!")
                log_progress("ℹ️  브라우저를 다시 시작하면 캐시/쿠키가 초기화됩니다.")
                
                # 완료 버튼 추가
                button_frame = tk.Frame(progress_window)
                button_frame.pack(pady=10)
                
                close_button = tk.Button(button_frame, text="닫기", 
                                       command=on_window_close,
                                       bg='#3498db', fg='white', font=('Arial', 10, 'bold'))
                close_button.pack()
                
            except Exception as e:
                logger.error(f"Browser fix error: {e}")
                messagebox.showerror("오류", f"브라우저 Fix 중 오류가 발생했습니다:\n{str(e)}")
        
        # 별도 스레드에서 실행
        import threading
        threading.Thread(target=run_browser_fix, daemon=True).start()
    

    def printer_fix(self):
        """프린터 Fix - 레지스트리 수정 및 스풀러 재시작"""
        logger.info("Printer Fix initiated")
        self.close_menu()
        
        def run_printer_fix():
            try:
                # 진행 상황을 보여주는 다이얼로그 생성
                progress_window = tk.Toplevel()
                progress_window.title("프린터 Fix")
                
                # 진행창을 관리 리스트에 추가
                RadialMenu.active_progress_windows.append(progress_window)
                
                # 창이 닫힐 때 리스트에서 제거
                def on_window_close():
                    try:
                        RadialMenu.active_progress_windows.remove(progress_window)
                    except:
                        pass
                    progress_window.destroy()
                
                progress_window.protocol("WM_DELETE_WINDOW", on_window_close)
                progress_window.geometry("500x400")
                progress_window.resizable(False, False)
                progress_window.transient(self.overlay if self.overlay else None)
                progress_window.grab_set()
                
                # 텍스트 영역 생성
                text_area = scrolledtext.ScrolledText(progress_window, height=20, width=60)
                text_area.pack(fill='both', expand=True, padx=10, pady=10)
                
                def log_progress(message):
                    text_area.insert(tk.END, f"{message}\n")
                    text_area.see(tk.END)
                    progress_window.update()
                
                log_progress("🖨️  프린터 Fix 시작...")
                log_progress("=" * 50)
                
                # 1. 레지스트리 수정
                log_progress("🔧 프린터 레지스트리 설정 수정 중...")
                reg_command = [
                    'REG', 'ADD', 
                    'HKLM\\System\\CurrentControlSet\\Control\\Print',
                    '/v', 'RpcAuthnLevelPrivacyEnabled',
                    '/t', 'REG_DWORD',
                    '/d', '0',
                    '/f'
                ]
                
                try:
                    result = subprocess.run(reg_command, capture_output=True, text=True, timeout=30)
                    if result.returncode == 0:
                        log_progress("✅ 레지스트리 설정 수정 완료")
                    else:
                        log_progress(f"⚠️  레지스트리 수정 경고: {result.stderr.strip()}")
                except Exception as e:
                    log_progress(f"❌ 레지스트리 수정 실패: {e}")
                
                # 2. 스풀러 서비스 중지
                log_progress("\n🔄 Print Spooler 서비스 중지 중...")
                try:
                    result = subprocess.run(['net', 'stop', 'spooler'], 
                                          capture_output=True, text=True, timeout=30)
                    if result.returncode == 0:
                        log_progress("✅ Print Spooler 서비스 중지됨")
                    else:
                        log_progress(f"⚠️  Spooler 중지 경고: {result.stderr.strip()}")
                except Exception as e:
                    log_progress(f"❌ Spooler 중지 실패: {e}")
                
                time.sleep(3)
                
                # 3. 스풀러 서비스 시작
                log_progress("\n🚀 Print Spooler 서비스 시작 중...")
                try:
                    result = subprocess.run(['net', 'start', 'spooler'], 
                                          capture_output=True, text=True, timeout=30)
                    if result.returncode == 0:
                        log_progress("✅ Print Spooler 서비스 시작됨")
                    else:
                        log_progress(f"⚠️  Spooler 시작 경고: {result.stderr.strip()}")
                except Exception as e:
                    log_progress(f"❌ Spooler 시작 실패: {e}")
                
                # 4. 추가 프린터 장애 해결 작업
                log_progress("\n🔧 추가 프린터 장애 해결 작업...")
                
                # 프린터 대기열 정리
                spooler_path = "C:\\Windows\\System32\\spool\\PRINTERS"
                try:
                    if os.path.exists(spooler_path):
                        import glob
                        spool_files = glob.glob(os.path.join(spooler_path, "*"))
                        if spool_files:
                            for file in spool_files:
                                try:
                                    os.remove(file)
                                    log_progress(f"✅ 대기열 파일 삭제: {os.path.basename(file)}")
                                except:
                                    pass
                        else:
                            log_progress("ℹ️  프린터 대기열이 이미 비어있습니다")
                    else:
                        log_progress("ℹ️  프린터 대기열 폴더를 찾을 수 없습니다")
                except Exception as e:
                    log_progress(f"⚠️  대기열 정리 중 오류: {e}")
                
                log_progress("\n" + "=" * 50)
                log_progress("🎉 프린터 Fix 완료!")
                log_progress("ℹ️  프린터 문제가 해결되었습니다. 프린터를 다시 사용해보세요.")
                
                # 장애 시 추천 명령어
                log_progress("\n📋 장애 지속 시 추천 명령어:")
                log_progress("1. 프린터 드라이버 재설치")
                log_progress("2. rundll32 printui.dll,PrintUIEntry /k (프린터 새로고침)")
                log_progress("3. sfc /scannow (시스템 파일 검사)")
                
                # 완료 버튼 추가
                button_frame = tk.Frame(progress_window)
                button_frame.pack(pady=10)
                
                close_button = tk.Button(button_frame, text="닫기", 
                                       command=on_window_close,
                                       bg='#2ecc71', fg='white', font=('Arial', 10, 'bold'))
                close_button.pack()
                
            except Exception as e:
                logger.error(f"Printer fix error: {e}")
                messagebox.showerror("오류", f"프린터 Fix 중 오류가 발생했습니다:\n{str(e)}")
        
        # 별도 스레드에서 실행
        import threading
        threading.Thread(target=run_printer_fix, daemon=True).start()


    def mes_fix(self):
        """MES Fix - pf_profile.ini 파일의 IP 설정 수정"""
        logger.info("MES Fix initiated")
        self.close_menu()
        
        def run_mes_fix():
            try:
                # 진행 상황을 보여주는 다이얼로그 생성
                progress_window = tk.Toplevel()
                progress_window.title("MES Fix")
                
                # 진행창을 관리 리스트에 추가
                RadialMenu.active_progress_windows.append(progress_window)
                
                # 창이 닫힐 때 리스트에서 제거
                def on_window_close():
                    try:
                        RadialMenu.active_progress_windows.remove(progress_window)
                    except:
                        pass
                    progress_window.destroy()
                
                progress_window.protocol("WM_DELETE_WINDOW", on_window_close)
                progress_window.geometry("500x350")
                progress_window.resizable(False, False)
                progress_window.transient(self.overlay if self.overlay else None)
                progress_window.grab_set()
                
                # 텍스트 영역 생성
                text_area = scrolledtext.ScrolledText(progress_window, height=18, width=60)
                text_area.pack(fill='both', expand=True, padx=10, pady=10)
                
                def log_progress(message):
                    text_area.insert(tk.END, f"{message}\n")
                    text_area.see(tk.END)
                    progress_window.update()
                
                log_progress("🏭 MES Fix 시작...")
                log_progress("=" * 50)
                
                # 사용 환경 확인
                env_setting = load_data('environment', 'office')
                log_progress(f"현재 사용 환경: {env_setting}")
                
                # IP 설정 결정
                if env_setting == 'office':
                    target_ip = "192.168.0.250,14333"
                    env_name = "사무용"
                else:  # field
                    target_ip = "10.10.10.10,14333"
                    env_name = "현장용"
                
                log_progress(f"설정할 IP: {target_ip} ({env_name})")
                
                # pf_profile.ini 파일 경로
                profile_path = "C:\\geopop\\commlib\\pf_profile.ini"
                
                log_progress(f"\n📁 파일 경로: {profile_path}")
                
                # 파일 존재 확인
                if not os.path.exists(profile_path):
                    log_progress("❌ pf_profile.ini 파일을 찾을 수 없습니다!")
                    log_progress("   파일 경로를 확인해주세요.")
                    
                    # 장애 시 추천 사항
                    log_progress("\n📋 파일이 없을 때 해결방법:")
                    log_progress("1. MES 프로그램이 정상 설치되었는지 확인")
                    log_progress("2. C:\\geopop\\commlib\\ 폴더 존재 여부 확인")
                    log_progress("3. MES 프로그램 재설치 고려")
                    return
                
                log_progress("✅ pf_profile.ini 파일 발견")
                
                # 파일 백업
                backup_path = profile_path + ".backup"
                try:
                    import shutil
                    shutil.copy2(profile_path, backup_path)
                    log_progress(f"✅ 백업 파일 생성: {backup_path}")
                except Exception as e:
                    log_progress(f"⚠️  백업 생성 실패: {e}")
                
                # 파일 읽기 및 수정
                log_progress("\n🔧 IP 설정 수정 중...")
                try:
                    # 파일 인코딩 자동 감지
                    encodings_to_try = ['utf-8', 'cp949', 'euc-kr', 'latin-1']
                    lines = None
                    used_encoding = None
                    
                    for encoding in encodings_to_try:
                        try:
                            with open(profile_path, 'r', encoding=encoding) as f:
                                lines = f.readlines()
                                used_encoding = encoding
                                log_progress(f"✅ 파일 인코딩 감지: {encoding}")
                                break
                        except UnicodeDecodeError:
                            continue
                    
                    if lines is None:
                        log_progress("❌ 파일 인코딩을 감지할 수 없습니다!")
                        return
                    
                    # [SERVER] 섹션 찾기 및 IP 수정
                    in_server_section = False
                    modified = False
                    
                    for i, line in enumerate(lines):
                        line_stripped = line.strip()
                        
                        if line_stripped == '[SERVER]':
                            in_server_section = True
                            log_progress("✅ [SERVER] 섹션 발견")
                            continue
                        
                        if in_server_section:
                            if line_stripped.startswith('[') and line_stripped.endswith(']'):
                                # 다른 섹션 시작
                                in_server_section = False
                                continue
                            
                            if line_stripped.startswith('IP='):
                                old_ip = line_stripped[3:]
                                lines[i] = f"IP={target_ip}\n"
                                log_progress(f"✅ IP 설정 변경: {old_ip} → {target_ip}")
                                modified = True
                                break
                    
                    if not modified:
                        log_progress("❌ IP= 설정을 찾을 수 없습니다!")
                        log_progress("\n📋 IP 설정이 없을 때 해결방법:")
                        log_progress("1. [SERVER] 섹션 존재 여부 확인")
                        log_progress("2. 파일 형식이 올바른지 확인")
                        log_progress("3. MES 설정 파일 복원 고려")
                        return
                    
                    # 파일 저장 (원본 인코딩 유지)
                    with open(profile_path, 'w', encoding=used_encoding) as f:
                        f.writelines(lines)
                    
                    log_progress("✅ 파일 저장 완료")
                    
                except Exception as e:
                    log_progress(f"❌ 파일 수정 실패: {e}")
                    log_progress("\n📋 파일 수정 실패 시 해결방법:")
                    log_progress("1. 관리자 권한으로 프로그램 실행")
                    log_progress("2. 파일이 사용 중인지 확인 후 종료")
                    log_progress("3. 백업 파일에서 복원")
                    return
                
                log_progress("\n" + "=" * 50)
                log_progress("🎉 MES Fix 완료!")
                log_progress(f"ℹ️  MES 서버 IP가 {env_name} 환경에 맞게 설정되었습니다.")
                log_progress("ℹ️  MES 프로그램을 재시작하세요.")
                
                # 완료 버튼 추가
                button_frame = tk.Frame(progress_window)
                button_frame.pack(pady=10)
                
                close_button = tk.Button(button_frame, text="닫기", 
                                       command=on_window_close,
                                       bg='#f39c12', fg='white', font=('Arial', 10, 'bold'))
                close_button.pack()
                
            except Exception as e:
                logger.error(f"MES fix error: {e}")
                messagebox.showerror("오류", f"MES Fix 중 오류가 발생했습니다:\n{str(e)}")
        
        # 별도 스레드에서 실행
        import threading
        threading.Thread(target=run_mes_fix, daemon=True).start()



    def start_auto_action_animations(self):
        """자동조치 서브메뉴 심플 애니메이션 시작"""
        if not hasattr(self, 'canvas') or not self.canvas:
            return
            
        # 페이드인 효과
        self.fade_in_animation()
        
        # 심플한 테두리 펄스 효과
        self.simple_border_pulse()
    
    def fade_in_animation(self, alpha=0.1):
        """페이드인 애니메이션"""
        if not hasattr(self, 'overlay') or not self.overlay:
            return
            
        if alpha < 0.9:
            self.overlay.attributes('-alpha', alpha)
            self.overlay.after(20, lambda: self.fade_in_animation(alpha + 0.1))
        else:
            self.overlay.attributes('-alpha', 0.9)
    
    def pulse_animation(self, scale=1.0, growing=True):
        """버튼 펄스 애니메이션"""
        if not hasattr(self, 'canvas') or not self.canvas:
            return
            
        try:
            # 모든 버튼에 펄스 효과
            for i in range(4):
                button_tag = f'button_{i}_glow'
                items = self.canvas.find_withtag(button_tag)
                if items:
                    for item in items:
                        coords = self.canvas.coords(item)
                        if len(coords) == 4:
                            center_x = (coords[0] + coords[2]) / 2
                            center_y = (coords[1] + coords[3]) / 2
                            size = (coords[2] - coords[0]) / 2
                            
                            new_size = size * scale
                            self.canvas.coords(item,
                                center_x - new_size, center_y - new_size,
                                center_x + new_size, center_y + new_size)
            
            # 다음 프레임 계산
            if growing:
                new_scale = scale + 0.02
                if new_scale > 1.1:
                    new_scale = 1.1
                    growing = False
            else:
                new_scale = scale - 0.02
                if new_scale < 0.9:
                    new_scale = 0.9
                    growing = True
            
            # 계속 애니메이션
            self.overlay.after(50, lambda: self.pulse_animation(new_scale, growing))
            
        except:
            pass
    
    def rotation_animation(self, angle=0):
        """배경 회전 애니메이션"""
        if not hasattr(self, 'canvas') or not self.canvas:
            return
            
        try:
            import math
            center_x, center_y = self.local_x, self.local_y
            
            # 회전하는 장식 선들 업데이트
            line_items = self.canvas.find_withtag('rotating_line')
            for item in line_items:
                self.canvas.delete(item)
            
            # 새로운 각도로 선 그리기
            for i in range(12):
                base_angle = i * 30 + angle
                rad = math.radians(base_angle)
                x1 = center_x + math.cos(rad) * 60
                y1 = center_y + math.sin(rad) * 60
                x2 = center_x + math.cos(rad) * 130
                y2 = center_y + math.sin(rad) * 130
                
                # 색상 변화
                color_val = int(abs(math.sin(rad)) * 100 + 50)
                line_color = f"#{color_val:02x}{color_val:02x}ff"
                
                self.canvas.create_line(
                    x1, y1, x2, y2,
                    fill=line_color, width=2, tags='rotating_line'
                )
            
            # 다음 프레임
            new_angle = (angle + 1) % 360
            self.overlay.after(30, lambda: self.rotation_animation(new_angle))
            
        except:
            pass
    def test_mes_communication(self):
        """MES 통신 테스트"""
        try:
            # 현재 환경 설정에 따른 MES 서버 정보
            env_setting = load_data('environment', 'office')
            
            if env_setting == 'office':
                mes_server = "192.168.0.250"
                mes_port = 14333
            else:  # field
                mes_server = "10.10.10.10"
                mes_port = 14333
            
            # 간단한 TCP 연결 테스트
            import socket
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(5)  # 5초 타임아웃
            
            try:
                result = sock.connect_ex((mes_server, mes_port))
                sock.close()
                return result == 0  # 0이면 연결 성공
            except Exception:
                return False
            
        except Exception as e:
            logger.error(f"MES communication test error: {e}")
            return False

    def auto_temp_cleanup(self):
        """자동 임시파일 삭제"""
        logger.info("Auto temp cleanup initiated")
        self.close_menu()
        messagebox.showinfo("자동 임시파일 삭제", "임시파일 삭제를 시작합니다.")
    
    def auto_registry_cleanup(self):
        """자동 레지스트리 정리"""
        logger.info("Auto registry cleanup initiated")
        self.close_menu()
        messagebox.showinfo("자동 레지스트리 정리", "레지스트리 정리를 시작합니다.")
    
    def auto_system_optimize(self):
        """자동 시스템 최적화"""
        logger.info("Auto system optimize initiated")
        self.close_menu()
        messagebox.showinfo("자동 시스템 최적화", "시스템 최적화를 시작합니다.")
    
    def auto_virus_scan(self):
        """자동 바이러스 검사"""
        logger.info("Auto virus scan initiated")
        self.close_menu()
        messagebox.showinfo("자동 바이러스 검사", "바이러스 검사를 시작합니다.")


def cleanup_all_ui():
    """모든 UI 리소스 정리 (스레드 재시작 시 사용) - 강화된 버전"""
    global radial_menu, status_window
    
    logger.info("Starting comprehensive UI resource cleanup...")
    
    # 1. RadialMenu 정리 (먼저 처리)
    if 'radial_menu' in globals() and radial_menu:
        try:
            logger.info("Cleaning up RadialMenu...")
            
            # 네트워크 모니터 중지
            if hasattr(radial_menu, 'stop_network_monitor'):
                radial_menu.stop_network_monitor()
            
            # 메뉴 닫기
            if hasattr(radial_menu, 'close_menu'):
                radial_menu.close_menu()
            
            # 리스너 정리 (먼저 처리)
            if hasattr(radial_menu, 'cleanup_listeners'):
                radial_menu.cleanup_listeners()
            
            # StatusWindow 정리
            if hasattr(radial_menu, 'status_window') and radial_menu.status_window:
                logger.info("Destroying RadialMenu's StatusWindow...")
                radial_menu.status_window.destroy()
                radial_menu.status_window = None
            
            # SettingsWindow 정리
            if hasattr(radial_menu, 'settings_window') and radial_menu.settings_window:
                if hasattr(radial_menu.settings_window, 'settings_window') and radial_menu.settings_window.settings_window:
                    try:
                        radial_menu.settings_window.settings_window.destroy()
                    except:
                        pass
                radial_menu.settings_window = None
                
            # 활성 프로그레스 윈도우 정리
            if hasattr(radial_menu, 'active_progress_windows'):
                for window in list(radial_menu.active_progress_windows):
                    try:
                        window.destroy()
                    except:
                        pass
                radial_menu.active_progress_windows.clear()
                
            logger.info("RadialMenu cleanup completed")
                
        except Exception as e:
            logger.error(f"Error cleaning up RadialMenu: {e}")
    
    # 2. 독립적인 StatusWindow 정리
    if 'status_window' in globals() and status_window:
        try:
            logger.info("Cleaning up independent StatusWindow...")
            status_window.destroy()
        except Exception as e:
            logger.error(f"Error cleaning up StatusWindow: {e}")
    
    # 3. 모든 tkinter 최상위 창 강제 정리
    try:
        import tkinter as tk
        logger.info("Cleaning up all Tkinter windows...")
        
        # 기본 루트가 있으면 모든 자식 창 정리
        if hasattr(tk, '_default_root') and tk._default_root:
            children = list(tk._default_root.winfo_children())
            for child in children:
                if isinstance(child, tk.Toplevel):
                    try:
                        child.destroy()
                        logger.info(f"Destroyed Toplevel window: {child}")
                    except Exception as e:
                        logger.error(f"Error destroying Toplevel: {e}")
        
        # 숨어있는 창들도 찾아서 정리
        try:
            all_windows = tk._default_root.winfo_children() if tk._default_root else []
            for window in all_windows:
                try:
                    if hasattr(window, 'destroy'):
                        window.destroy()
                except:
                    pass
        except:
            pass
            
    except Exception as e:
        logger.error(f"Error cleaning up tkinter windows: {e}")
    
    # 4. PyQt 애플리케이션 정리
    try:
        from PyQt5.QtWidgets import QApplication
        if QApplication.instance():
            logger.info("Cleaning up PyQt application...")
            app = QApplication.instance()
            
            # 모든 위젯 찾아서 정리
            all_widgets = app.allWidgets()
            for widget in all_widgets:
                try:
                    widget.hide()
                    widget.close()
                    widget.deleteLater()
                except:
                    pass
            
            # 이벤트 처리 및 종료
            app.processEvents()
            app.quit()
            logger.info("PyQt application cleaned up")
            
    except ImportError:
        # PyQt5가 설치되지 않은 경우
        pass
    except Exception as e:
        logger.error(f"Error cleaning up PyQt: {e}")
    
    # 5. PySimpleGUI 정리
    try:
        import PySimpleGUI as sg
        # 모든 열려있는 창 닫기
        sg.Window.close_all()
        logger.info("PySimpleGUI windows closed")
    except ImportError:
        pass
    except Exception as e:
        logger.error(f"Error cleaning up PySimpleGUI: {e}")
    
    # 6. 전역 리스너 정리 (확실하게)
    try:
        # mouse 라이브러리 후크 정리
        try:
            import mouse
            mouse.unhook_all()
            logger.info("Mouse hooks cleaned up")
        except:
            pass
            
        # keyboard 라이브러리 후크 정리
        try:
            import keyboard
            keyboard.unhook_all()
            logger.info("Keyboard hooks cleaned up")
        except:
            pass
            
        # pynput 리스너 정리는 이미 RadialMenu에서 처리됨
            
    except Exception as e:
        logger.error(f"Error cleaning up global listeners: {e}")
    
    # 7. 전역 변수 정리
    globals()['radial_menu'] = None
    globals()['status_window'] = None
    
    # 8. 강제 가비지 컬렉션 (여러 번 실행)
    import gc
    for i in range(3):  # 3회 반복 실행
        collected = gc.collect()
        logger.info(f"Garbage collection pass {i+1}: collected {collected} objects")
    
    logger.info("Comprehensive UI cleanup completed successfully")

def main():
    """메인 함수"""
    # 종료 신호 확인
    if '_app_stop_event' in globals() and globals()['_app_stop_event'].is_set():
        logger.info("Stop event detected, cleaning up before start...")
        cleanup_all_ui()
    
    logger.info("Starting GeoMedical Helper...")
    
    # 루트 윈도우 생성 (숨김)
    root = tk.Tk()
    root.withdraw()  # 메인 윈도우 숨기기
    set_root(root)
    
    # 버전 정보 출력 (main.py 자체 버전 사용)
    logger.info(f"GeoMedical Helper v{MAIN_VERSION} Started")
    print(f"GeoMedical Helper v{MAIN_VERSION} Started")
    
    try:
        # mouse 라이브러리 확인
        import mouse
        
        # 기존 인스턴스가 있으면 먼저 정리
        if 'radial_menu' in globals() and globals()['radial_menu'] is not None:
            logger.info("Found existing radial_menu instance, cleaning up first...")
            cleanup_all_ui()
            time.sleep(1)  # 정리가 완료될 때까지 대기
        
        # RadialMenu 인스턴스 생성
        radial_menu = RadialMenu()
        
        # 상태창과 라디얼 메뉴 상호 참조 설정
        radial_menu.status_window.radial_menu = radial_menu
        
        # 입력 리스너 설정 (실행키에 따라 동적 변경)
        hotkey_type = load_data('hotkey_type', 'mouse_wheel')
        setup_input_listener_for_instance(radial_menu, hotkey_type)
        
        # 네트워크 모니터링 시작
        logger.info("Initializing network monitoring...")
        radial_menu.start_network_monitor()
        
        # 초기 연결 상태 확인
        initial_connection = radial_menu.check_internet_connection()
        logger.info(f"Initial internet connection status: {'ONLINE' if initial_connection else 'OFFLINE'}")
        
        # 상태 표시 창 초기화
        if radial_menu.settings_window.status_enabled:
            radial_menu.status_window.show_status_window()
        
        # 실행키에 따른 동적 안내 메시지
        hotkey_type = load_data('hotkey_type', 'mouse_wheel')
        hotkey_messages = {
            'mouse_wheel': '마우스 휠 버튼을 클릭하면 퀵 메뉴가 나타납니다.',
            'f1': 'F1 키를 누르면 퀵 메뉴가 나타납니다.',
            'f2': 'F2 키를 누르면 퀵 메뉴가 나타납니다.',
            'f3': 'F3 키를 누르면 퀵 메뉴가 나타납니다.',
            'f4': 'F4 키를 누르면 퀵 메뉴가 나타납니다.',
            'click_status': '네트워크 상태 표시창을 클릭하면 퀵 메뉴가 나타납니다.'
        }
        
        hotkey_message = hotkey_messages.get(hotkey_type, '마우스 휠 버튼을 클릭하면 퀵 메뉴가 나타납니다.')
        
        # 안내 메시지
        messagebox.showinfo(
            f"GeoMedical Helper v{MAIN_VERSION}", 
            "프로그램이 시작되었습니다.\n\n"
            f"{hotkey_message}\n"
            "설정 버튼을 통해 실행키와 상태 표시를 설정할 수 있습니다.\n\n"
            "종료하려면 시스템 트레이에서 종료하거나\n"
            "작업 관리자를 사용하세요."
        )
        
        # 메인 루프 실행
        root.mainloop()
        
    except ImportError:
        messagebox.showerror(
            "라이브러리 오류",
            "mouse 라이브러리가 설치되어 있지 않습니다.\n\n"
            "다음 명령어로 설치해주세요:\n"
            "pip install mouse\n\n"
            "관리자 권한이 필요할 수 있습니다."
        )
        
    except Exception as e:
        messagebox.showerror("오류", f"프로그램 실행 중 오류가 발생했습니다.\n{str(e)}")
        report_error(e, "Main execution")
    
    finally:
        # 종료 시 모든 UI 정리
        logger.info("Main function ending, cleaning up UI...")
        cleanup_all_ui()


# psutil이 없는 경우를 위한 대체 구현
if 'psutil' not in globals():
    class psutil:
        @staticmethod
        def cpu_percent(interval=1):
            return 0
        
        @staticmethod
        def cpu_count():
            return os.cpu_count() or 1
        
        @staticmethod
        def virtual_memory():
            class Memory:
                total = 8 * 1024**3
                used = 4 * 1024**3
                percent = 50
            return Memory()
        
        @staticmethod
        def disk_usage(path):
            class Disk:
                total = 256 * 1024**3
                used = 128 * 1024**3
                percent = 50
            return Disk()
    
    def create_modern_circular_background_auto_action(self):
            """자동조치 서브메뉴의 심플한 원형 배경 생성"""
            logger.info("Creating simple circular background for auto action submenu")
            
            center_x, center_y = self.local_x, self.local_y
            radius = 160
            
            # 1. 메인 배경 원 (어두운 회색)
            self.canvas.create_oval(
                center_x - radius, center_y - radius,
                center_x + radius, center_y + radius,
                fill='#1a1a1a', outline='', tags='background'
            )
            
            # 2. 내부 원 (조금 더 밝은 회색)
            inner_radius = radius - 20
            self.canvas.create_oval(
                center_x - inner_radius, center_y - inner_radius,
                center_x + inner_radius, center_y + inner_radius,
                fill='#2a2a2a', outline='', tags='background'
            )
            
            # 3. 중앙 원 (버튼 영역)
            core_radius = radius - 40
            self.canvas.create_oval(
                center_x - core_radius, center_y - core_radius,
                center_x + core_radius, center_y + core_radius,
                fill='#333333', outline='', tags='background'
            )
            
            # 4. 심플한 외곽 테두리 (단일 네온 컬러)
            self.canvas.create_oval(
                center_x - radius, center_y - radius,
                center_x + radius, center_y + radius,
                fill='', outline='#4a9eff', width=2,
                tags='background'
            )
            
            # 5. 내부 테두리 (얇은 라인)
            self.canvas.create_oval(
                center_x - inner_radius, center_y - inner_radius,
                center_x + inner_radius, center_y + inner_radius,
                fill='', outline='#4a9eff', width=1,
                tags='background'
            )
            
            # 6. 중앙 포인트 (작은 점)
            center_dot_radius = 3
            self.canvas.create_oval(
                center_x - center_dot_radius, center_y - center_dot_radius,
                center_x + center_dot_radius, center_y + center_dot_radius,
                fill='#4a9eff', outline='', tags='background'
            )
            
            logger.info("Simple background created")
    
    def blend_color(self, color1, color2, ratio):
        """두 색상을 블렌딩"""
        # 간단한 색상 블렌딩 (hex to hex)
        return color1  # 단순화
        

    def create_auto_action_buttons(self):
        """자동조치 버튼 생성"""
        logger.info("Creating auto action buttons...")
        
        # 자동조치 버튼 정보
        button_info = [
            {"text": "네트워크 Fix", "color": "#e74c3c", "command": self.network_fix},
            {"text": "브라우저 Fix", "color": "#3498db", "command": self.browser_fix},
            {"text": "프린터 Fix", "color": "#2ecc71", "command": self.printer_fix},
            {"text": "MES Fix", "color": "#f39c12", "command": self.mes_fix}
        ]
        
        radius = 110  # 중심에서 버튼까지의 거리
        button_size = 70  # 버튼 크기
        
        # 중심 원 그리기
        center_size = 25
        center_circle = self.canvas.create_oval(
            self.local_x - center_size,
            self.local_y - center_size,
            self.local_x + center_size,
            self.local_y + center_size,
            fill='#34495e',
            outline='white',
            width=2
        )
        
        # 중심 텍스트
        self.canvas.create_text(
            self.local_x,
            self.local_y,
            text="자동조치",
            font=('Arial', 9, 'bold'),
            fill='white'
        )
        
        # 버튼 생성
        self.buttons = []
        for i, btn_info in enumerate(button_info):
            # 각도 계산 (위쪽부터 시작)
            angle = (i * (360 / len(button_info)) - 90) * math.pi / 180
            
            # 버튼 위치 계산
            btn_x = self.local_x + radius * math.cos(angle)
            btn_y = self.local_y + radius * math.sin(angle)
            
            # 버튼 생성
            x1 = btn_x - button_size/2
            y1 = btn_y - button_size/2
            x2 = btn_x + button_size/2
            y2 = btn_y + button_size/2
            
            # 원형 버튼
            btn = self.canvas.create_oval(
                x1, y1, x2, y2,
                fill=btn_info["color"],
                outline='white',
                width=2,
                tags=f"button_{i}"
            )
            
            # 버튼 텍스트
            text = self.canvas.create_text(
                btn_x, btn_y,
                text=btn_info['text'],
                font=('Arial', 9, 'bold'),
                fill='white',
                tags=f"button_{i}"
            )
            
            # 버튼 정보 저장
            self.buttons.append({
                "id": btn,
                "text_id": text,
                "x": btn_x,
                "y": btn_y,
                "size": button_size,
                "command": btn_info["command"],
                "color": btn_info["color"],
                "tag": f"button_{i}"
            })
            
            # 호버 이벤트 바인딩
            self.canvas.tag_bind(f"button_{i}", '<Enter>', 
                (lambda tag: lambda e: self.on_button_hover(tag, True))(f"button_{i}"))
            self.canvas.tag_bind(f"button_{i}", '<Leave>', 
                (lambda tag: lambda e: self.on_button_hover(tag, False))(f"button_{i}"))
            self.canvas.tag_bind(f"button_{i}", '<Button-1>', 
                (lambda cmd: lambda e: self.on_button_click(cmd))(btn_info["command"]))
            
            logger.info(f"Auto action button {i} ({btn_info['text']}) created at ({btn_x}, {btn_y})")
        
        logger.info(f"Created {len(self.buttons)} auto action buttons")
    
    # Fix 기능들
    def network_fix(self):
        """네트워크 Fix - 수동으로 네트워크 복구 및 MES 통신 테스트"""
        logger.info("Network Fix initiated")
        self.close_menu()
        
        def run_network_fix():
            try:
                # 진행 상황을 보여주는 다이얼로그 생성
                progress_window = tk.Toplevel()
                progress_window.title("네트워크 Fix")
                
                # 진행창을 관리 리스트에 추가
                RadialMenu.active_progress_windows.append(progress_window)
                
                # 창이 닫힐 때 리스트에서 제거
                def on_window_close():
                    try:
                        RadialMenu.active_progress_windows.remove(progress_window)
                    except:
                        pass
                    progress_window.destroy()
                
                progress_window.protocol("WM_DELETE_WINDOW", on_window_close)
                progress_window.geometry("500x400")
                progress_window.resizable(False, False)
                progress_window.transient(self.overlay if self.overlay else None)
                progress_window.grab_set()
                
                # 텍스트 영역 생성
                text_area = scrolledtext.ScrolledText(progress_window, height=20, width=60)
                text_area.pack(fill='both', expand=True, padx=10, pady=10)
                
                def log_progress(message):
                    text_area.insert(tk.END, f"{message}\n")
                    text_area.see(tk.END)
                    progress_window.update()
                
                log_progress("🔧 네트워크 Fix 시작...")
                log_progress("=" * 50)
                
                # 인터넷 연결 상태 확인
                is_online = self.check_internet_connection()
                if is_online:
                    log_progress("✅ 현재 인터넷 연결 상태: 온라인")
                    log_progress("⚠️  오프라인이 아니지만 강제로 네트워크 복구를 진행합니다.")
                else:
                    log_progress("❌ 현재 인터넷 연결 상태: 오프라인")
                    log_progress("🔄 네트워크 자동 복구를 시작합니다.")
                
                log_progress("\n🚀 6단계 네트워크 복구 과정 시작...")
                
                # 네트워크 자동 복구 실행
                recovery_success = self.auto_network_recovery()
                
                if recovery_success:
                    log_progress("\n✅ 네트워크 복구 완료!")
                else:
                    log_progress("\n❌ 네트워크 복구 실패")
                
                # MES 통신 테스트
                log_progress("\n🔍 MES 통신 테스트 시작...")
                mes_result = self.test_mes_communication()
                
                if mes_result:
                    log_progress("✅ MES 통신 테스트 성공! 정상적으로 통신되고 있습니다.")
                else:
                    log_progress("❌ MES 통신 테스트 실패. MES 서버 연결을 확인해주세요.")
                
                log_progress("\n" + "=" * 50)
                log_progress("🎉 네트워크 Fix 완료!")
                
                # 완료 버튼 추가
                button_frame = tk.Frame(progress_window)
                button_frame.pack(pady=10)
                
                close_button = tk.Button(button_frame, text="닫기", 
                                       command=on_window_close,
                                       bg='#3498db', fg='white', font=('Arial', 10, 'bold'))
                close_button.pack()
                
            except Exception as e:
                logger.error(f"Network fix error: {e}")
                messagebox.showerror("오류", f"네트워크 Fix 중 오류가 발생했습니다:\n{str(e)}")
        
        # 별도 스레드에서 실행
        import threading
        threading.Thread(target=run_network_fix, daemon=True).start()
    
    def browser_fix(self):
        """브라우저 Fix - 크롬, 엣지 브라우저 캐시/쿠키 삭제"""
        logger.info("Browser Fix initiated")
        self.close_menu()
        
        def run_browser_fix():
            try:
                # 진행 상황을 보여주는 다이얼로그 생성
                progress_window = tk.Toplevel()
                progress_window.title("브라우저 Fix")
                
                # 진행창을 관리 리스트에 추가
                RadialMenu.active_progress_windows.append(progress_window)
                
                # 창이 닫힐 때 리스트에서 제거
                def on_window_close():
                    try:
                        RadialMenu.active_progress_windows.remove(progress_window)
                    except:
                        pass
                    progress_window.destroy()
                
                progress_window.protocol("WM_DELETE_WINDOW", on_window_close)
                progress_window.geometry("500x300")
                progress_window.resizable(False, False)
                progress_window.transient(self.overlay if self.overlay else None)
                progress_window.grab_set()
                
                # 텍스트 영역 생성
                text_area = scrolledtext.ScrolledText(progress_window, height=15, width=60)
                text_area.pack(fill='both', expand=True, padx=10, pady=10)
                
                def log_progress(message):
                    text_area.insert(tk.END, f"{message}\n")
                    text_area.see(tk.END)
                    progress_window.update()
                
                log_progress("🌐 브라우저 Fix 시작...")
                log_progress("=" * 50)
                
                # 브라우저 프로세스 종료
                log_progress("🔄 브라우저 프로세스 종료 중...")
                
                browser_processes = ['chrome.exe', 'msedge.exe', 'iexplore.exe']
                for process in browser_processes:
                    try:
                        result = subprocess.run(['taskkill', '/F', '/IM', process], 
                                              capture_output=True, text=True)
                        if result.returncode == 0:
                            log_progress(f"✅ {process} 프로세스 종료됨")
                        else:
                            log_progress(f"ℹ️  {process} 프로세스가 실행 중이 아님")
                    except Exception as e:
                        log_progress(f"⚠️  {process} 종료 중 오류: {e}")
                
                time.sleep(2)
                
                # Chrome 캐시/쿠키 삭제
                log_progress("\n🗑️  Chrome 캐시/쿠키 삭제 중...")
                chrome_paths = [
                    os.path.expanduser("~\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Cache"),
                    os.path.expanduser("~\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Cookies"),
                    os.path.expanduser("~\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Web Data")
                ]
                
                for path in chrome_paths:
                    try:
                        if os.path.exists(path):
                            if os.path.isdir(path):
                                import shutil
                                shutil.rmtree(path, ignore_errors=True)
                                log_progress(f"✅ Chrome: {os.path.basename(path)} 폴더 삭제됨")
                            else:
                                os.remove(path)
                                log_progress(f"✅ Chrome: {os.path.basename(path)} 파일 삭제됨")
                        else:
                            log_progress(f"ℹ️  Chrome: {os.path.basename(path)} 없음")
                    except Exception as e:
                        log_progress(f"⚠️  Chrome {os.path.basename(path)} 삭제 실패: {e}")
                
                # Edge 캐시/쿠키 삭제
                log_progress("\n🗑️  Edge 캐시/쿠키 삭제 중...")
                edge_paths = [
                    os.path.expanduser("~\\AppData\\Local\\Microsoft\\Edge\\User Data\\Default\\Cache"),
                    os.path.expanduser("~\\AppData\\Local\\Microsoft\\Edge\\User Data\\Default\\Cookies"),
                    os.path.expanduser("~\\AppData\\Local\\Microsoft\\Edge\\User Data\\Default\\Web Data")
                ]
                
                for path in edge_paths:
                    try:
                        if os.path.exists(path):
                            if os.path.isdir(path):
                                import shutil
                                shutil.rmtree(path, ignore_errors=True)
                                log_progress(f"✅ Edge: {os.path.basename(path)} 폴더 삭제됨")
                            else:
                                os.remove(path)
                                log_progress(f"✅ Edge: {os.path.basename(path)} 파일 삭제됨")
                        else:
                            log_progress(f"ℹ️  Edge: {os.path.basename(path)} 없음")
                    except Exception as e:
                        log_progress(f"⚠️  Edge {os.path.basename(path)} 삭제 실패: {e}")
                
                log_progress("\n" + "=" * 50)
                log_progress("🎉 브라우저 Fix 완료!")
                log_progress("ℹ️  브라우저를 다시 시작하면 캐시/쿠키가 초기화됩니다.")
                
                # 완료 버튼 추가
                button_frame = tk.Frame(progress_window)
                button_frame.pack(pady=10)
                
                close_button = tk.Button(button_frame, text="닫기", 
                                       command=on_window_close,
                                       bg='#3498db', fg='white', font=('Arial', 10, 'bold'))
                close_button.pack()
                
            except Exception as e:
                logger.error(f"Browser fix error: {e}")
                messagebox.showerror("오류", f"브라우저 Fix 중 오류가 발생했습니다:\n{str(e)}")
        
        # 별도 스레드에서 실행
        import threading
        threading.Thread(target=run_browser_fix, daemon=True).start()
    

    def printer_fix(self):
        """프린터 Fix - 레지스트리 수정 및 스풀러 재시작"""
        logger.info("Printer Fix initiated")
        self.close_menu()
        
        def run_printer_fix():
            try:
                # 진행 상황을 보여주는 다이얼로그 생성
                progress_window = tk.Toplevel()
                progress_window.title("프린터 Fix")
                
                # 진행창을 관리 리스트에 추가
                RadialMenu.active_progress_windows.append(progress_window)
                
                # 창이 닫힐 때 리스트에서 제거
                def on_window_close():
                    try:
                        RadialMenu.active_progress_windows.remove(progress_window)
                    except:
                        pass
                    progress_window.destroy()
                
                progress_window.protocol("WM_DELETE_WINDOW", on_window_close)
                progress_window.geometry("500x400")
                progress_window.resizable(False, False)
                progress_window.transient(self.overlay if self.overlay else None)
                progress_window.grab_set()
                
                # 텍스트 영역 생성
                text_area = scrolledtext.ScrolledText(progress_window, height=20, width=60)
                text_area.pack(fill='both', expand=True, padx=10, pady=10)
                
                def log_progress(message):
                    text_area.insert(tk.END, f"{message}\n")
                    text_area.see(tk.END)
                    progress_window.update()
                
                log_progress("🖨️  프린터 Fix 시작...")
                log_progress("=" * 50)
                
                # 1. 레지스트리 수정
                log_progress("🔧 프린터 레지스트리 설정 수정 중...")
                reg_command = [
                    'REG', 'ADD', 
                    'HKLM\\System\\CurrentControlSet\\Control\\Print',
                    '/v', 'RpcAuthnLevelPrivacyEnabled',
                    '/t', 'REG_DWORD',
                    '/d', '0',
                    '/f'
                ]
                
                try:
                    result = subprocess.run(reg_command, capture_output=True, text=True, timeout=30)
                    if result.returncode == 0:
                        log_progress("✅ 레지스트리 설정 수정 완료")
                    else:
                        log_progress(f"⚠️  레지스트리 수정 경고: {result.stderr.strip()}")
                except Exception as e:
                    log_progress(f"❌ 레지스트리 수정 실패: {e}")
                
                # 2. 스풀러 서비스 중지
                log_progress("\n🔄 Print Spooler 서비스 중지 중...")
                try:
                    result = subprocess.run(['net', 'stop', 'spooler'], 
                                          capture_output=True, text=True, timeout=30)
                    if result.returncode == 0:
                        log_progress("✅ Print Spooler 서비스 중지됨")
                    else:
                        log_progress(f"⚠️  Spooler 중지 경고: {result.stderr.strip()}")
                except Exception as e:
                    log_progress(f"❌ Spooler 중지 실패: {e}")
                
                time.sleep(3)
                
                # 3. 스풀러 서비스 시작
                log_progress("\n🚀 Print Spooler 서비스 시작 중...")
                try:
                    result = subprocess.run(['net', 'start', 'spooler'], 
                                          capture_output=True, text=True, timeout=30)
                    if result.returncode == 0:
                        log_progress("✅ Print Spooler 서비스 시작됨")
                    else:
                        log_progress(f"⚠️  Spooler 시작 경고: {result.stderr.strip()}")
                except Exception as e:
                    log_progress(f"❌ Spooler 시작 실패: {e}")
                
                # 4. 추가 프린터 장애 해결 작업
                log_progress("\n🔧 추가 프린터 장애 해결 작업...")
                
                # 프린터 대기열 정리
                spooler_path = "C:\\Windows\\System32\\spool\\PRINTERS"
                try:
                    if os.path.exists(spooler_path):
                        import glob
                        spool_files = glob.glob(os.path.join(spooler_path, "*"))
                        if spool_files:
                            for file in spool_files:
                                try:
                                    os.remove(file)
                                    log_progress(f"✅ 대기열 파일 삭제: {os.path.basename(file)}")
                                except:
                                    pass
                        else:
                            log_progress("ℹ️  프린터 대기열이 이미 비어있습니다")
                    else:
                        log_progress("ℹ️  프린터 대기열 폴더를 찾을 수 없습니다")
                except Exception as e:
                    log_progress(f"⚠️  대기열 정리 중 오류: {e}")
                
                log_progress("\n" + "=" * 50)
                log_progress("🎉 프린터 Fix 완료!")
                log_progress("ℹ️  프린터 문제가 해결되었습니다. 프린터를 다시 사용해보세요.")
                
                # 장애 시 추천 명령어
                log_progress("\n📋 장애 지속 시 추천 명령어:")
                log_progress("1. 프린터 드라이버 재설치")
                log_progress("2. rundll32 printui.dll,PrintUIEntry /k (프린터 새로고침)")
                log_progress("3. sfc /scannow (시스템 파일 검사)")
                
                # 완료 버튼 추가
                button_frame = tk.Frame(progress_window)
                button_frame.pack(pady=10)
                
                close_button = tk.Button(button_frame, text="닫기", 
                                       command=on_window_close,
                                       bg='#2ecc71', fg='white', font=('Arial', 10, 'bold'))
                close_button.pack()
                
            except Exception as e:
                logger.error(f"Printer fix error: {e}")
                messagebox.showerror("오류", f"프린터 Fix 중 오류가 발생했습니다:\n{str(e)}")
        
        # 별도 스레드에서 실행
        import threading
        threading.Thread(target=run_printer_fix, daemon=True).start()


    def mes_fix(self):
        """MES Fix - pf_profile.ini 파일의 IP 설정 수정"""
        logger.info("MES Fix initiated")
        self.close_menu()
        
        def run_mes_fix():
            try:
                # 진행 상황을 보여주는 다이얼로그 생성
                progress_window = tk.Toplevel()
                progress_window.title("MES Fix")
                
                # 진행창을 관리 리스트에 추가
                RadialMenu.active_progress_windows.append(progress_window)
                
                # 창이 닫힐 때 리스트에서 제거
                def on_window_close():
                    try:
                        RadialMenu.active_progress_windows.remove(progress_window)
                    except:
                        pass
                    progress_window.destroy()
                
                progress_window.protocol("WM_DELETE_WINDOW", on_window_close)
                progress_window.geometry("500x350")
                progress_window.resizable(False, False)
                progress_window.transient(self.overlay if self.overlay else None)
                progress_window.grab_set()
                
                # 텍스트 영역 생성
                text_area = scrolledtext.ScrolledText(progress_window, height=18, width=60)
                text_area.pack(fill='both', expand=True, padx=10, pady=10)
                
                def log_progress(message):
                    text_area.insert(tk.END, f"{message}\n")
                    text_area.see(tk.END)
                    progress_window.update()
                
                log_progress("🏭 MES Fix 시작...")
                log_progress("=" * 50)
                
                # 사용 환경 확인
                env_setting = load_data('environment', 'office')
                log_progress(f"현재 사용 환경: {env_setting}")
                
                # IP 설정 결정
                if env_setting == 'office':
                    target_ip = "192.168.0.250,14333"
                    env_name = "사무용"
                else:  # field
                    target_ip = "10.10.10.10,14333"
                    env_name = "현장용"
                
                log_progress(f"설정할 IP: {target_ip} ({env_name})")
                
                # pf_profile.ini 파일 경로
                profile_path = "C:\\geopop\\commlib\\pf_profile.ini"
                
                log_progress(f"\n📁 파일 경로: {profile_path}")
                
                # 파일 존재 확인
                if not os.path.exists(profile_path):
                    log_progress("❌ pf_profile.ini 파일을 찾을 수 없습니다!")
                    log_progress("   파일 경로를 확인해주세요.")
                    
                    # 장애 시 추천 사항
                    log_progress("\n📋 파일이 없을 때 해결방법:")
                    log_progress("1. MES 프로그램이 정상 설치되었는지 확인")
                    log_progress("2. C:\\geopop\\commlib\\ 폴더 존재 여부 확인")
                    log_progress("3. MES 프로그램 재설치 고려")
                    return
                
                log_progress("✅ pf_profile.ini 파일 발견")
                
                # 파일 백업
                backup_path = profile_path + ".backup"
                try:
                    import shutil
                    shutil.copy2(profile_path, backup_path)
                    log_progress(f"✅ 백업 파일 생성: {backup_path}")
                except Exception as e:
                    log_progress(f"⚠️  백업 생성 실패: {e}")
                
                # 파일 읽기 및 수정
                log_progress("\n🔧 IP 설정 수정 중...")
                try:
                    # 파일 인코딩 자동 감지
                    encodings_to_try = ['utf-8', 'cp949', 'euc-kr', 'latin-1']
                    lines = None
                    used_encoding = None
                    
                    for encoding in encodings_to_try:
                        try:
                            with open(profile_path, 'r', encoding=encoding) as f:
                                lines = f.readlines()
                                used_encoding = encoding
                                log_progress(f"✅ 파일 인코딩 감지: {encoding}")
                                break
                        except UnicodeDecodeError:
                            continue
                    
                    if lines is None:
                        log_progress("❌ 파일 인코딩을 감지할 수 없습니다!")
                        return
                    
                    # [SERVER] 섹션 찾기 및 IP 수정
                    in_server_section = False
                    modified = False
                    
                    for i, line in enumerate(lines):
                        line_stripped = line.strip()
                        
                        if line_stripped == '[SERVER]':
                            in_server_section = True
                            log_progress("✅ [SERVER] 섹션 발견")
                            continue
                        
                        if in_server_section:
                            if line_stripped.startswith('[') and line_stripped.endswith(']'):
                                # 다른 섹션 시작
                                in_server_section = False
                                continue
                            
                            if line_stripped.startswith('IP='):
                                old_ip = line_stripped[3:]
                                lines[i] = f"IP={target_ip}\n"
                                log_progress(f"✅ IP 설정 변경: {old_ip} → {target_ip}")
                                modified = True
                                break
                    
                    if not modified:
                        log_progress("❌ IP= 설정을 찾을 수 없습니다!")
                        log_progress("\n📋 IP 설정이 없을 때 해결방법:")
                        log_progress("1. [SERVER] 섹션 존재 여부 확인")
                        log_progress("2. 파일 형식이 올바른지 확인")
                        log_progress("3. MES 설정 파일 복원 고려")
                        return
                    
                    # 파일 저장 (원본 인코딩 유지)
                    with open(profile_path, 'w', encoding=used_encoding) as f:
                        f.writelines(lines)
                    
                    log_progress("✅ 파일 저장 완료")
                    
                except Exception as e:
                    log_progress(f"❌ 파일 수정 실패: {e}")
                    log_progress("\n📋 파일 수정 실패 시 해결방법:")
                    log_progress("1. 관리자 권한으로 프로그램 실행")
                    log_progress("2. 파일이 사용 중인지 확인 후 종료")
                    log_progress("3. 백업 파일에서 복원")
                    return
                
                log_progress("\n" + "=" * 50)
                log_progress("🎉 MES Fix 완료!")
                log_progress(f"ℹ️  MES 서버 IP가 {env_name} 환경에 맞게 설정되었습니다.")
                log_progress("ℹ️  MES 프로그램을 재시작하세요.")
                
                # 완료 버튼 추가
                button_frame = tk.Frame(progress_window)
                button_frame.pack(pady=10)
                
                close_button = tk.Button(button_frame, text="닫기", 
                                       command=on_window_close,
                                       bg='#f39c12', fg='white', font=('Arial', 10, 'bold'))
                close_button.pack()
                
            except Exception as e:
                logger.error(f"MES fix error: {e}")
                messagebox.showerror("오류", f"MES Fix 중 오류가 발생했습니다:\n{str(e)}")
        
        # 별도 스레드에서 실행
        import threading
        threading.Thread(target=run_mes_fix, daemon=True).start()



    def start_auto_action_animations(self):
        """자동조치 서브메뉴 심플 애니메이션 시작"""
        if not hasattr(self, 'canvas') or not self.canvas:
            return
            
        # 페이드인 효과
        self.fade_in_animation()
        
        # 심플한 테두리 펄스 효과
        self.simple_border_pulse()
    
    def fade_in_animation(self, alpha=0.1):
        """페이드인 애니메이션"""
        if not hasattr(self, 'overlay') or not self.overlay:
            return
            
        if alpha < 0.9:
            self.overlay.attributes('-alpha', alpha)
            self.overlay.after(20, lambda: self.fade_in_animation(alpha + 0.1))
        else:
            self.overlay.attributes('-alpha', 0.9)
    
    def pulse_animation(self, scale=1.0, growing=True):
        """버튼 펄스 애니메이션"""
        if not hasattr(self, 'canvas') or not self.canvas:
            return
            
        try:
            # 모든 버튼에 펄스 효과
            for i in range(4):
                button_tag = f'button_{i}_glow'
                items = self.canvas.find_withtag(button_tag)
                if items:
                    for item in items:
                        coords = self.canvas.coords(item)
                        if len(coords) == 4:
                            center_x = (coords[0] + coords[2]) / 2
                            center_y = (coords[1] + coords[3]) / 2
                            size = (coords[2] - coords[0]) / 2
                            
                            new_size = size * scale
                            self.canvas.coords(item,
                                center_x - new_size, center_y - new_size,
                                center_x + new_size, center_y + new_size)
            
            # 다음 프레임 계산
            if growing:
                new_scale = scale + 0.02
                if new_scale > 1.1:
                    new_scale = 1.1
                    growing = False
            else:
                new_scale = scale - 0.02
                if new_scale < 0.9:
                    new_scale = 0.9
                    growing = True
            
            # 계속 애니메이션
            self.overlay.after(50, lambda: self.pulse_animation(new_scale, growing))
            
        except:
            pass
    
    def rotation_animation(self, angle=0):
        """배경 회전 애니메이션"""
        if not hasattr(self, 'canvas') or not self.canvas:
            return
            
        try:
            import math
            center_x, center_y = self.local_x, self.local_y
            
            # 회전하는 장식 선들 업데이트
            line_items = self.canvas.find_withtag('rotating_line')
            for item in line_items:
                self.canvas.delete(item)
            
            # 새로운 각도로 선 그리기
            for i in range(12):
                base_angle = i * 30 + angle
                rad = math.radians(base_angle)
                x1 = center_x + math.cos(rad) * 60
                y1 = center_y + math.sin(rad) * 60
                x2 = center_x + math.cos(rad) * 130
                y2 = center_y + math.sin(rad) * 130
                
                # 색상 변화
                color_val = int(abs(math.sin(rad)) * 100 + 50)
                line_color = f"#{color_val:02x}{color_val:02x}ff"
                
                self.canvas.create_line(
                    x1, y1, x2, y2,
                    fill=line_color, width=2, tags='rotating_line'
                )
            
            # 다음 프레임
            new_angle = (angle + 1) % 360
            self.overlay.after(30, lambda: self.rotation_animation(new_angle))
            
        except:
            pass
    def test_mes_communication(self):
        """MES 통신 테스트"""
        try:
            # 현재 환경 설정에 따른 MES 서버 정보
            env_setting = load_data('environment', 'office')
            
            if env_setting == 'office':
                mes_server = "192.168.0.250"
                mes_port = 14333
            else:  # field
                mes_server = "10.10.10.10"
                mes_port = 14333
            
            # 간단한 TCP 연결 테스트
            import socket
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(5)  # 5초 타임아웃
            
            try:
                result = sock.connect_ex((mes_server, mes_port))
                sock.close()
                return result == 0  # 0이면 연결 성공
            except Exception:
                return False
            
        except Exception as e:
            logger.error(f"MES communication test error: {e}")
            return False

    def auto_temp_cleanup(self):
        """자동 임시파일 삭제"""
        logger.info("Auto temp cleanup initiated")
        self.close_menu()
        messagebox.showinfo("자동 임시파일 삭제", "임시파일 삭제를 시작합니다.")
    
    def auto_registry_cleanup(self):
        """자동 레지스트리 정리"""
        logger.info("Auto registry cleanup initiated")
        self.close_menu()
        messagebox.showinfo("자동 레지스트리 정리", "레지스트리 정리를 시작합니다.")
    
    def auto_system_optimize(self):
        """자동 시스템 최적화"""
        logger.info("Auto system optimize initiated")
        self.close_menu()
        messagebox.showinfo("자동 시스템 최적화", "시스템 최적화를 시작합니다.")
    
    def auto_virus_scan(self):
        """자동 바이러스 검사"""
        logger.info("Auto virus scan initiated")
        self.close_menu()
        messagebox.showinfo("자동 바이러스 검사", "바이러스 검사를 시작합니다.")


if __name__ == "__main__":
    main()