# FlightMonitor/controller/cleanup_manager.py """ Manages the orderly shutdown and cleanup of application resources, including closing database connections, stopping background threads, and destroying secondary GUI windows upon application exit or specific events. """ from typing import Any, Optional, TYPE_CHECKING from ..utils.logger import get_logger # Type checking imports to avoid circular dependencies at runtime if TYPE_CHECKING: from flightmonitor.controller.app_controller import AppController from flightmonitor.data.storage import DataStorage from flightmonitor.data.aircraft_database_manager import AircraftDatabaseManager from flightmonitor.gui.main_window import MainWindow from flightmonitor.gui.dialogs.full_flight_details_window import ( FullFlightDetailsWindow, ) from flightmonitor.map.map_canvas_manager import MapCanvasManager module_logger = get_logger(__name__) class CleanupManager: """ Handles all application shutdown and resource cleanup operations. It orchestrates the closing of various modules and components. """ def __init__(self, app_controller: "AppController"): """ Initializes the CleanupManager. Args: app_controller: The main AppController instance, providing access to all application components that need cleanup. """ self.app_controller = app_controller module_logger.debug("CleanupManager initialized.") def on_application_exit(self): """ Performs a coordinated shutdown of all application resources. This method is called when the main application window is closing. """ module_logger.info( "CleanupManager: Application exit requested. Cleaning up resources." ) # --- Close active Full Flight Details window (if any) --- if ( self.app_controller.active_detail_window_ref and self.app_controller.active_detail_window_ref.winfo_exists() ): try: module_logger.info( f"CleanupManager: Closing active detail window for {self.app_controller.active_detail_window_icao} on app exit." ) self.app_controller.active_detail_window_ref.destroy() except Exception as e_close_detail: module_logger.error( f"CleanupManager: Error closing detail window on app exit: {e_close_detail}" ) finally: self.app_controller.active_detail_window_ref = None self.app_controller.active_detail_window_icao = None # --- Shutdown MapCanvasManager worker (if active) --- main_window = self.app_controller.main_window if ( main_window and hasattr(main_window, "map_manager_instance") and main_window.map_manager_instance is not None ): map_manager: "MapCanvasManager" = main_window.map_manager_instance if hasattr(map_manager, "shutdown_worker") and callable( map_manager.shutdown_worker ): try: map_manager.shutdown_worker() module_logger.info( "CleanupManager: Main MapCanvasManager worker shutdown requested." ) except Exception as e_map_shutdown: module_logger.error( f"CleanupManager: Error during Main MapCanvasManager worker shutdown: {e_map_shutdown}", exc_info=True, ) # --- Stop live monitoring (adapter thread and data processor) --- is_adapter_considered_running = ( self.app_controller.live_adapter_thread and self.app_controller.live_adapter_thread.is_alive() ) or self.app_controller.is_live_monitoring_active if is_adapter_considered_running: module_logger.info( "CleanupManager: Live monitoring is active, requesting AppController to stop it." ) self.app_controller.stop_live_monitoring(from_error=False) # --- Close DataStorage connection pool --- if self.app_controller.data_storage: try: self.app_controller.data_storage.close_all_connections() module_logger.info("CleanupManager: DataStorage connection pool closed.") except Exception as e_db_close: module_logger.error( f"CleanupManager: Error closing DataStorage pool: {e_db_close}", exc_info=True, ) finally: self.app_controller.data_storage = None # --- Close AircraftDatabaseManager connection --- if self.app_controller.aircraft_db_manager: try: self.app_controller.aircraft_db_manager.close_connection() module_logger.info( "CleanupManager: AircraftDatabaseManager connection closed." ) except Exception as e_ac_db_close: module_logger.error( f"CleanupManager: Error closing AircraftDatabaseManager: {e_ac_db_close}", exc_info=True, ) finally: self.app_controller.aircraft_db_manager = None module_logger.info("CleanupManager: Cleanup on application exit finished.") def details_window_closed(self, closed_icao24: str): """ Handles the event when a full flight details window is closed. Clears the AppController's references to the closed window if it was the active one. Args: closed_icao24: The ICAO24 of the flight whose details window was closed. """ normalized_closed_icao24 = closed_icao24.lower().strip() if self.app_controller.active_detail_window_icao == normalized_closed_icao24: module_logger.info( f"CleanupManager: Detail window for {normalized_closed_icao24} reported closed. Clearing references in AppController." ) self.app_controller.active_detail_window_ref = None self.app_controller.active_detail_window_icao = None main_window = self.app_controller.main_window if ( main_window and hasattr(main_window, "full_flight_details_window") and main_window.full_flight_details_window and not main_window.full_flight_details_window.winfo_exists() ): main_window.full_flight_details_window = None else: module_logger.debug( f"CleanupManager: A detail window for {normalized_closed_icao24} closed, but it was not the currently tracked active one ({self.app_controller.active_detail_window_icao}). No action on active_detail references." )