﻿import time
from abc import ABC, abstractmethod

# Klasa abstrakcyjna Analizator definiująca wzorzec projektowy "Metoda Szablonowa" (Template Method).
class Analizator(ABC):
    
    # Główka metoda sterująca procesem (szablon działania).
    # Nie jest abstrakcyjna - dziedziczące klasy korzystają z tej implementacji.
    # Chroni przed błędem w kolejności kroków lub pominięciem jakiegoś etapu.
    def proces_analizy(self, sciezka):
        print(f"=== Rozpoczynanie procesu analizy dla pliku: {sciezka} ===")
        start_time = time.time()
        
        try:
            self.otworz_plik(sciezka)
            dane = self.wyodrebnij_dane()
            self.formatuj_wynik(dane)
        except Exception as e:
            print(f"[BŁĄD] Wystąpił problem podczas przetwarzania: {e}")
        finally:
            # Gwarancja zamknięcia zasobów, realizowana w centralnym miejscu
            self.zamknij_plik()
            
        czas_trwania = time.time() - start_time
        print(f"=== Analiza zakończona. Czas przetwarzania: {czas_trwania:.4f}s ===\n")

    # Wymagane metody szczegółowe, które muszą dostarczyć wtyczki do różnych formatów.
    @abstractmethod
    def otworz_plik(self, sciezka):
        pass

    @abstractmethod
    def wyodrebnij_dane(self):
        pass

    @abstractmethod
    def formatuj_wynik(self, dane):
        pass

    # Metoda wspólna (nie-abstrakcyjna), opcjonalnie dająca się nadpisać (haczyk), 
    # ale mająca sensowną domyślną implementację.
    def zamknij_plik(self):
        print("[System] Zamykanie deskryptora pliku (wspólna logika infrastrukturalna).")


# Konkretny analizator dla plików PDF
class AnalizatorPDF(Analizator):
    
    def otworz_plik(self, sciezka):
        print(f"AnalizatorPDF: Inicjalizacja biblioteki PDF i wczytanie {sciezka}")
        
    def wyodrebnij_dane(self):
        print("AnalizatorPDF: Wyciąganie bloków tekstowych ze struktury PDF...")
        return "Przykładowa treść wyjęta z dokumentu."
        
    def formatuj_wynik(self, dane):
        print(f"AnalizatorPDF: Wynik końcowy -> {dane.upper()}")


# Konkretny analizator dla arkuszy kalkulacyjnych Excel
class AnalizatorExcel(Analizator):
    
    def otworz_plik(self, sciezka):
        print(f"AnalizatorExcel: Otwieranie arkusza {sciezka} za pomocą biblioteki pandas")
        
    def wyodrebnij_dane(self):
        print("AnalizatorExcel: Ekstrakcja wierszy z pierwszej zakładki...")
        return ["Wiersz 1", "Wiersz 2", "Wiersz 3"]
        
    def formatuj_wynik(self, dane):
        print(f"AnalizatorExcel: Znaleziono łącznie {len(dane)} wierszy. Oto one:")
        for w in dane:
            print(f" - {w}")


if __name__ == "__main__":
    # Inicjalizacja wtyczek dla poszczególnych rozszerzeń
    pdf_analyzer = AnalizatorPDF()
    excel_analyzer = AnalizatorExcel()
    
    # Wywołanie głównej metody szablonowej. Zauważ, że workflow (szkielet)
    # pozostaje ten sam niezależnie od analizatora.
    pdf_analyzer.proces_analizy("raport_finansowy.pdf")
    time.sleep(0.5) # Drobne opóźnienie dla pokazania logowania czasu
    excel_analyzer.proces_analizy("dane_z_bazy.xlsx")
