import tkinter as tk
from tkinter import filedialog, messagebox
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import numpy as np
import os

class ThesisPlotApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Thesis Figure Generator")
        self.root.geometry("450x300")

        # ==========================================
        # 1. THESIS CONFIGURATION
        # ==========================================
        self.RATE_LABELS = ["0.5A", "1A", "2A", "3A", "4A", "3A", "2A", "1A", "0.5A"]
        self.CYCLES_PER_STEP = 5 
        
        # Font settings to match your document
        self.FONT_FAMILY = 'serif' # Options: 'serif' (Times), 'sans-serif' (Arial)
        self.FONT_SIZE = 12
        # ==========================================

        instruction = (
            "Rate testing plots  \n\n"
            "By: Bora @MSE\n"
          
        )
        self.lbl_instruct = tk.Label(root, text=instruction, font=("Arial", 11), pady=15)
        self.lbl_instruct.pack()

        self.btn_select = tk.Button(root, text="Select Files & Generate", command=self.select_files, 
                                    font=("Arial", 11, "bold"), bg="#e1e1e1", height=2)
        self.btn_select.pack(fill='x', padx=40, pady=5)

        self.btn_quit = tk.Button(root, text="Quit", command=root.quit)
        self.btn_quit.pack(pady=10)

    def select_files(self):
        file_paths = filedialog.askopenfilenames(
            title="Select Excel Files",
            filetypes=[("Excel Files", "*.xlsx")]
        )
        if file_paths:
            self.plot_files(file_paths)

    def setup_thesis_style(self):
        """Sets matplotlib params for professional publication quality"""
        plt.rcParams.update({
            'font.family': self.FONT_FAMILY,
            'font.size': self.FONT_SIZE,
            'axes.labelsize': self.FONT_SIZE + 2,
            'axes.titlesize': self.FONT_SIZE + 4,
            'xtick.labelsize': self.FONT_SIZE,
            'ytick.labelsize': self.FONT_SIZE,
            'figure.dpi': 150,   # View DPI
            'savefig.dpi': 300,  # Save DPI (High Res)
            'lines.linewidth': 1.5,
            'axes.grid': True,
            'grid.alpha': 0.3,
        })

    def plot_files(self, file_paths):
        self.setup_thesis_style()
        
        # Thesis standard size: width=6-7 inches matches A4/Letter margins well
        fig, ax = plt.subplots(figsize=(8, 5))
        
        # Distinct markers for B&W readability
        markers = ['o', 's', '^', 'D', 'v', '<', '>'] 
        colors = list(mcolors.TABLEAU_COLORS.values())
        
        files_plotted = 0
        max_y_val = 0

        for i, file_path in enumerate(file_paths):
            try:
                xls = pd.ExcelFile(file_path)
                if 'cycle' not in xls.sheet_names: continue

                df = pd.read_excel(xls, sheet_name='cycle')
                
                if 'Cycle Index' in df.columns and 'DChg. Spec. Cap.(mAh/g)' in df.columns:
                    # Formatting for this specific file
                    label = os.path.splitext(os.path.basename(file_path))[0]
                    color = colors[i % len(colors)]
                    marker = markers[i % len(markers)] # Cycle markers too!

                    df = df.sort_values('Cycle Index')
                    current_max = df['DChg. Spec. Cap.(mAh/g)'].max()
                    if current_max > max_y_val: max_y_val = current_max

                    # --- CHUNKED PLOTTING (Connect dots ONLY within steps) ---
                    has_labeled = False
                    for step_idx in range(len(self.RATE_LABELS)):
                        start = step_idx * self.CYCLES_PER_STEP
                        end = start + self.CYCLES_PER_STEP
                        
                        mask = (df['Cycle Index'] > start) & (df['Cycle Index'] <= end)
                        chunk = df.loc[mask]
                        
                        if not chunk.empty:
                            lbl = label if not has_labeled else ""
                            ax.plot(chunk['Cycle Index'], chunk['DChg. Spec. Cap.(mAh/g)'], 
                                    marker=marker, markersize=5, 
                                    linestyle='-', color=color, label=lbl, alpha=0.9)
                            has_labeled = True
                    
                    files_plotted += 1

            except Exception as e:
                print(f"Error: {e}")

        if files_plotted == 0: return

        # ==========================================
        # 2. THESIS ANNOTATIONS (Clean & Professional)
        # ==========================================
        
        # A. Dividers
        total_cycles = len(self.RATE_LABELS) * self.CYCLES_PER_STEP
        dividers = np.arange(self.CYCLES_PER_STEP + 0.5, total_cycles, self.CYCLES_PER_STEP)
        for div in dividers:
            ax.axvline(x=div, color='black', linestyle='--', linewidth=0.7, alpha=0.4)

        # B. Top Labels & Banding
        label_y = max_y_val * 1.08 # Place labels 8% above max data
        
        for idx, text in enumerate(self.RATE_LABELS):
            # Center of the "band"
            center_x = (idx * self.CYCLES_PER_STEP) + (self.CYCLES_PER_STEP / 2) + 0.5
            
            # Label
            ax.text(center_x, label_y, text, ha='center', va='bottom', fontweight='bold')

            # Alternating Banding (Subtle)
            if idx % 2 == 1:
                start_x = (idx * self.CYCLES_PER_STEP) + 0.5
                end_x = ((idx + 1) * self.CYCLES_PER_STEP) + 0.5
                ax.axvspan(start_x, end_x, facecolor='gray', alpha=0.08) # Very subtle gray

        # C. Axis & Legend
        ax.set_title("Specific Discharge Capacity vs Cycle Index", pad=20)
        ax.set_xlabel('Cycle Index')
        ax.set_ylabel('Discharge Specific Capacity (mAh/g)')
        
        # Set limits with headroom for labels
        ax.set_xlim(0, total_cycles + 1)
        ax.set_ylim(bottom=50, top=label_y * 1.05)

        # LEGEND OPTIMIZATION:
        # 'frameon=False' looks cleaner in many journals, but True is safer.
        # 'ncol=2' spreads it out horizontally to save vertical space.
        ax.legend(loc='lower center', ncol=2, frameon=True, fancybox=False, edgecolor='black', fontsize=10)

        plt.tight_layout()
        plt.show()

if __name__ == '__main__':
    root = tk.Tk()
    app = ThesisPlotApp(root)
    root.mainloop()