# import tkinter as tk # from tkinter import ttk, filedialog, messagebox # import pandas as pd # from pathlib import Path # from data_comparator import KSTCoordiComparator # class DataComparisonGUI: # def __init__(self, root): # self.root = root # self.root.title("KST vs Coordi Data Comparison Tool") # self.root.geometry("1200x800") # self.comparator = None # self.comparison_data = None # self.setup_ui() # def setup_ui(self): # # Main container # main_frame = ttk.Frame(self.root, padding="10") # main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) # # Configure grid weights # self.root.columnconfigure(0, weight=1) # self.root.rowconfigure(0, weight=1) # main_frame.columnconfigure(1, weight=1) # main_frame.rowconfigure(2, weight=1) # # Title # title_label = ttk.Label(main_frame, text="KST vs Coordi Data Comparison", # font=("Arial", 16, "bold")) # title_label.grid(row=0, column=0, columnspan=3, pady=(0, 20)) # # File selection frame # file_frame = ttk.LabelFrame(main_frame, text="File Selection", padding="10") # file_frame.grid(row=1, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=(0, 10)) # file_frame.columnconfigure(1, weight=1) # ttk.Label(file_frame, text="Excel File:").grid(row=0, column=0, sticky=tk.W, padx=(0, 10)) # self.file_path_var = tk.StringVar(value="data/sample-data.xlsx") # self.file_entry = ttk.Entry(file_frame, textvariable=self.file_path_var, width=50) # self.file_entry.grid(row=0, column=1, sticky=(tk.W, tk.E), padx=(0, 10)) # browse_btn = ttk.Button(file_frame, text="Browse", command=self.browse_file) # browse_btn.grid(row=0, column=2) # analyze_btn = ttk.Button(file_frame, text="Analyze Data", command=self.analyze_data) # analyze_btn.grid(row=0, column=3, padx=(10, 0)) # # Results notebook (tabs) # self.notebook = ttk.Notebook(main_frame) # self.notebook.grid(row=2, column=0, columnspan=3, sticky=(tk.W, tk.E, tk.N, tk.S)) # # Create tabs # self.create_summary_tab() # self.create_matched_tab() # self.create_kst_only_tab() # self.create_coordi_only_tab() # # Status bar # self.status_var = tk.StringVar(value="Ready - Select an Excel file and click 'Analyze Data'") # status_bar = ttk.Label(main_frame, textvariable=self.status_var, relief=tk.SUNKEN) # status_bar.grid(row=3, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=(10, 0)) # def create_summary_tab(self): # # Summary tab # summary_frame = ttk.Frame(self.notebook) # self.notebook.add(summary_frame, text="Summary") # # Configure grid # summary_frame.columnconfigure(0, weight=1) # summary_frame.rowconfigure(1, weight=1) # # Summary text widget # summary_text_frame = ttk.LabelFrame(summary_frame, text="Comparison Summary", padding="10") # summary_text_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=10, pady=10) # summary_text_frame.columnconfigure(0, weight=1) # summary_text_frame.rowconfigure(0, weight=1) # self.summary_text = tk.Text(summary_text_frame, wrap=tk.WORD, height=15) # summary_scrollbar = ttk.Scrollbar(summary_text_frame, orient=tk.VERTICAL, command=self.summary_text.yview) # self.summary_text.configure(yscrollcommand=summary_scrollbar.set) # self.summary_text.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) # summary_scrollbar.grid(row=0, column=1, sticky=(tk.N, tk.S)) # # Reconciliation info # reconcile_frame = ttk.LabelFrame(summary_frame, text="Reconciliation Results", padding="10") # reconcile_frame.grid(row=1, column=0, sticky=(tk.W, tk.E), padx=10, pady=(0, 10)) # self.reconcile_text = tk.Text(reconcile_frame, wrap=tk.WORD, height=8) # reconcile_scrollbar = ttk.Scrollbar(reconcile_frame, orient=tk.VERTICAL, command=self.reconcile_text.yview) # self.reconcile_text.configure(yscrollcommand=reconcile_scrollbar.set) # self.reconcile_text.grid(row=0, column=0, sticky=(tk.W, tk.E)) # reconcile_scrollbar.grid(row=0, column=1, sticky=(tk.N, tk.S)) # reconcile_frame.columnconfigure(0, weight=1) # def create_matched_tab(self): # matched_frame = ttk.Frame(self.notebook) # self.notebook.add(matched_frame, text="Matched Items") # self.create_data_table(matched_frame, "matched") # def create_kst_only_tab(self): # kst_frame = ttk.Frame(self.notebook) # self.notebook.add(kst_frame, text="KST Only") # self.create_data_table(kst_frame, "kst_only") # def create_coordi_only_tab(self): # coordi_frame = ttk.Frame(self.notebook) # self.notebook.add(coordi_frame, text="Coordi Only") # self.create_data_table(coordi_frame, "coordi_only") # def create_data_table(self, parent, table_type): # # Configure grid # parent.columnconfigure(0, weight=1) # parent.rowconfigure(1, weight=1) # # Info label # info_frame = ttk.Frame(parent) # info_frame.grid(row=0, column=0, sticky=(tk.W, tk.E), padx=10, pady=10) # info_frame.columnconfigure(1, weight=1) # count_label = ttk.Label(info_frame, text="Count:") # count_label.grid(row=0, column=0, padx=(0, 10)) # count_var = tk.StringVar(value="0") # setattr(self, f"{table_type}_count_var", count_var) # count_display = ttk.Label(info_frame, textvariable=count_var, font=("Arial", 10, "bold")) # count_display.grid(row=0, column=1, sticky=tk.W) # # Table frame # table_frame = ttk.Frame(parent) # table_frame.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=10, pady=(0, 10)) # table_frame.columnconfigure(0, weight=1) # table_frame.rowconfigure(0, weight=1) # # Create treeview # columns = ("Title", "Episode", "Sheet", "Row", "Reason") # tree = ttk.Treeview(table_frame, columns=columns, show="headings", height=20) # # Configure columns # tree.heading("Title", text="Title") # tree.heading("Episode", text="Episode") # tree.heading("Sheet", text="Sheet") # tree.heading("Row", text="Row") # tree.heading("Reason", text="Reason") # tree.column("Title", width=300) # tree.column("Episode", width=100) # tree.column("Sheet", width=120) # tree.column("Row", width=80) # tree.column("Reason", width=300) # # Scrollbars # v_scrollbar = ttk.Scrollbar(table_frame, orient=tk.VERTICAL, command=tree.yview) # h_scrollbar = ttk.Scrollbar(table_frame, orient=tk.HORIZONTAL, command=tree.xview) # tree.configure(yscrollcommand=v_scrollbar.set, xscrollcommand=h_scrollbar.set) # tree.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) # v_scrollbar.grid(row=0, column=1, sticky=(tk.N, tk.S)) # h_scrollbar.grid(row=1, column=0, sticky=(tk.W, tk.E)) # # Store tree widget # setattr(self, f"{table_type}_tree", tree) # def browse_file(self): # file_path = filedialog.askopenfilename( # title="Select Excel File", # filetypes=[("Excel files", "*.xlsx *.xls"), ("All files", "*.*")] # ) # if file_path: # self.file_path_var.set(file_path) # def analyze_data(self): # file_path = self.file_path_var.get().strip() # if not file_path: # messagebox.showerror("Error", "Please select an Excel file") # return # if not Path(file_path).exists(): # messagebox.showerror("Error", f"File not found: {file_path}") # return # try: # self.status_var.set("Analyzing data...") # self.root.update() # # Create comparator and analyze # self.comparator = KSTCoordiComparator(file_path) # if not self.comparator.load_data(): # messagebox.showerror("Error", "Failed to load Excel data") # return # # Get comparison results # self.comparison_data = self.comparator.get_comparison_summary() # # Update GUI # self.update_summary() # self.update_data_tables() # self.status_var.set("Analysis complete!") # except Exception as e: # messagebox.showerror("Error", f"Analysis failed: {str(e)}") # self.status_var.set("Analysis failed") # def update_summary(self): # if not self.comparison_data: # return # # Clear previous content # self.summary_text.delete(1.0, tk.END) # self.reconcile_text.delete(1.0, tk.END) # data = self.comparison_data # # Summary text # summary = f"""COMPARISON SUMMARY # {'='*50} # Original Counts: # KST Total: {data['original_counts']['kst_total']:,} # Coordi Total: {data['original_counts']['coordi_total']:,} # Matched Items: {data['matched_items_count']:,} # Mismatches: # KST Only: {data['mismatches']['kst_only_count']:,} # Coordi Only: {data['mismatches']['coordi_only_count']:,} # KST Duplicates: {data['mismatches']['kst_duplicates_count']:,} # Coordi Duplicates: {data['mismatches']['coordi_duplicates_count']:,} # Total Mismatches: {data['mismatches']['kst_only_count'] + data['mismatches']['coordi_only_count'] + data['mismatches']['kst_duplicates_count'] + data['mismatches']['coordi_duplicates_count']:,} # """ # self.summary_text.insert(tk.END, summary) # # Reconciliation text # reconcile = data['reconciliation'] # reconcile_info = f"""RECONCILIATION RESULTS # {'='*40} # After excluding mismatches: # KST Count: {reconcile['reconciled_kst_count']:,} # Coordi Count: {reconcile['reconciled_coordi_count']:,} # Counts Match: {'✅ YES' if reconcile['counts_match_after_reconciliation'] else '❌ NO'} # Items to exclude: # From KST: {reconcile['items_to_exclude_from_kst']:,} # From Coordi: {reconcile['items_to_exclude_from_coordi']:,} # Final Result: Both datasets will have {reconcile['reconciled_kst_count']:,} matching items after reconciliation. # """ # self.reconcile_text.insert(tk.END, reconcile_info) # def update_data_tables(self): # if not self.comparison_data: # return # mismatches = self.comparison_data['mismatch_details'] # # Update matched items (create from intersection) # matched_count = self.comparison_data['matched_items_count'] # self.matched_count_var.set(f"{matched_count:,}") # # Clear matched tree # for item in self.matched_tree.get_children(): # self.matched_tree.delete(item) # # Add matched items (we'll show the first few as examples) # if self.comparator: # categorization = self.comparator.categorize_mismatches() # matched_items = categorization['matched_items'] # for i, item in enumerate(list(matched_items)[:100]): # Show first 100 # self.matched_tree.insert("", tk.END, values=( # item.title, item.episode, item.source_sheet, item.row_index + 1, "Perfect match" # )) # # Update KST only # kst_only = mismatches['kst_only'] # self.kst_only_count_var.set(f"{len(kst_only):,}") # for item in self.kst_only_tree.get_children(): # self.kst_only_tree.delete(item) # for mismatch in kst_only: # self.kst_only_tree.insert("", tk.END, values=( # mismatch['title'], mismatch['episode'], mismatch['sheet'], # mismatch['row_index'] + 1, mismatch['reason'] # )) # # Update Coordi only # coordi_only = mismatches['coordi_only'] # self.coordi_only_count_var.set(f"{len(coordi_only):,}") # for item in self.coordi_only_tree.get_children(): # self.coordi_only_tree.delete(item) # for mismatch in coordi_only: # self.coordi_only_tree.insert("", tk.END, values=( # mismatch['title'], mismatch['episode'], mismatch['sheet'], # mismatch['row_index'] + 1, mismatch['reason'] # )) # def main(): # root = tk.Tk() # app = DataComparisonGUI(root) # root.mainloop() # if __name__ == "__main__": # main()