﻿"""
Zadanie 4: Wzorce projektowe (Singleton Konfiguracyjny)
Gwarantowanie istnienia wyłącznie jednego obiektu danej klasy.
"""

class UstawieniaAplikacji:
    """Klasa realizująca wzorzec projektowy Singleton."""
    _instance = None  # Atrybut klasowy przechowujący jedyną instancję w pamięci

    def __new__(cls, *args, **kwargs):
        """Metoda magiczna kontrolująca alokację pamięci pod nowy obiekt."""
        # Jeśli instancja jeszcze nie istnieje...
        if cls._instance is None:
            print("[Singleton __new__] Tworzenie nowej, unikalnej instancji pamięci...")
            # ...tworzymy ją poprzez odwołanie do konstruktora bazowego (object)
            cls._instance = super(UstawieniaAplikacji, cls).__new__(cls)
        else:
            print("[Singleton __new__] Zwracanie ISTNIEJĄCEJ instancji z pamięci.")
            
        # Zawsze zwracamy ten sam adres (tę samą zmienną klasy)
        return cls._instance

    def __init__(self):
        """Metoda inicjalizacyjna. Uwaga: wywołuje się przy każdym odwołaniu UstawieniaAplikacji()."""
        # Musimy chronić atrybuty przed ponownym nadpisaniem!
        if not hasattr(self, '_initialized'):
            print("[Singleton __init__] Pierwsza inicjalizacja atrybutów początkowych...")
            self.wersja_systemu = "1.0.0"
            self.sciezka_bazy_danych = "data/app.db"
            self.poziom_logowania = "INFO"
            
            # Flaga chroniąca przed powtórnym ustawianiem powyższych pól
            self._initialized = True 
        else:
            print("[Singleton __init__] Obiekt już skonfigurowany, pomijanie nadpisywania.")

if __name__ == "__main__":
    print("--- TESTOWANIE SINGLETONA (ZADANIE 4) ---")
    
    # Próba "utworzenia" dwóch osobnych obiektów konfiguracyjnych
    ustawienia_1 = UstawieniaAplikacji()
    ustawienia_2 = UstawieniaAplikacji()
    
    # Sprawdzamy fizyczną tożsamość pamięci operacyjnej
    print("\n--- ANALIZA REFERENCJI ---")
    print(f"Czy u1 to TEN SAM obiekt co u2? (operator 'is'): {ustawienia_1 is ustawienia_2}")
    print(f"Adres pamięci ustawienia_1 (id): {id(ustawienia_1)}")
    print(f"Adres pamięci ustawienia_2 (id): {id(ustawienia_2)}")
    
    print("\n--- TEST MODYFIKACJI STANU GLOBALNEGO ---")
    print(f"Ścieżka DB przez zmienną 1 (przed): {ustawienia_1.sciezka_bazy_danych}")
    
    # Zmieniamy stan (np. w jednej części aplikacji modyfikujemy ścieżkę)
    ustawienia_1.sciezka_bazy_danych = "C:/production/live_db.sqlite"
    print(">> Zmieniono ścieżkę bazy używając zmiennej 1...")
    
    # Odczytujemy tę właściwość w zmiennej nr 2. Oczekujemy, że zmiana jest widoczna!
    print(f"Ścieżka DB przez zmienną 2 (po zmianie): {ustawienia_2.sciezka_bazy_danych}")
    
    # Wyjaśnienie:
    # UstawieniaAplikacji to mechanizm przechowujący stan globalny w sposób elegancki.
    # Ułatwia to testy/pracę, bo obiekty "same dbają" o to, by nigdy się nie duplikować,
    # ale niesie za sobą "ryzyko zmiennych globalnych" - stan może być nadpisany bez naszej
    # intencji z różnych punktów dużej aplikacji.
