Enhance the UI design/layout massively.
use eframe::egui::{self, CollapsingHeader, Layout, RichText, ScrollArea, SidePanel, TextStyle, TopBottomPanel};
use eframe::{egui::Align};
use object::{Object, ObjectSection};
use std::fs::File;
use std::io::Read;

fn main() {
    let app = BinaryAnalyzerApp::default();
    let native_options = eframe::NativeOptions::default();
    eframe::run_native(
        "Rust Binary Analyzer",
        native_options,
        Box::new(|_cc| Ok(Box::new(app))),
    )
    .expect("Failed to start eframe");
}

struct BinaryAnalyzerApp {
    binary_path: String,
    analysis_result: AnalysisResult,
    error_message: Option<String>,
    selected_section: Option<SectionInfo>,
}

impl Default for BinaryAnalyzerApp {
    fn default() -> Self {
        Self {
            binary_path: String::new(),
            analysis_result: AnalysisResult::default(),
            error_message: None,
            selected_section: None,
        }
    }
}

impl eframe::App for BinaryAnalyzerApp {
    fn update(&mut self, ctx: &egui::Context, _: &mut eframe::Frame) {
        // Top Panel for Title
        TopBottomPanel::top("top_panel").show(ctx, |ui| {
            ui.vertical_centered(|ui| {
                ui.add_space(10.0);
                ui.heading(RichText::new("Rust Binary Analyzer").heading());
                ui.add_space(10.0);
            });
        });

        // Side Panel for File Input
        SidePanel::left("side_panel")
            .min_width(200.0)
            .show(ctx, |ui| {
                ui.heading("Open Binary File");
                ui.separator();
                ui.label("Binary Path:");
                if ui.text_edit_singleline(&mut self.binary_path).lost_focus()
                    && ui.input(|i| i.key_pressed(egui::Key::Enter))
                {
                    self.perform_analysis();
                }
                if ui.button("Browse").clicked() {
                    if let Some(path) = tinyfiledialogs::open_file_dialog("Open Binary File", "", None)
                    {
                        self.binary_path = path.clone();
                        self.perform_analysis();
                    }
                }
                if let Some(error) = &self.error_message {
                    ui.colored_label(egui::Color32::RED, error);
                }
            });

        // Central Panel for Analysis Result
        egui::CentralPanel::default().show(ctx, |ui| {
            if self.analysis_result.is_empty() {
                ui.vertical_centered(|ui| {
                    ui.add_space(100.0);
                    ui.label("No file analyzed yet.");
                });
            } else {
                egui::TopBottomPanel::top("info_panel").show_inside(ui, |ui| {
                    ui.horizontal(|ui| {
                        ui.label("Format:");
                        ui.monospace(format!("{:?}", self.analysis_result.format));
                        ui.separator();
                        ui.label("Architecture:");
                        ui.monospace(format!("{:?}", self.analysis_result.architecture));
                        ui.separator();
                        ui.label("Endianness:");
                        ui.monospace(format!("{:?}", self.analysis_result.endianness));
                    });
                });

                ui.add_space(20.0);

                egui::ScrollArea::vertical().show(ui, |ui| {
                    CollapsingHeader::new("Sections")
                        .default_open(true)
                        .show(ui, |ui| {
                            self.display_sections(ui);
                        });
                });
            }
        });
    }
}

impl BinaryAnalyzerApp {
    fn perform_analysis(&mut self) {
        match analyze_binary(&self.binary_path) {
            Ok(result) => {
                self.analysis_result = result;
                self.error_message = None;
            }
            Err(e) => {
                self.analysis_result = AnalysisResult::default();
                self.error_message = Some(e);
            }
        }
    }

    fn display_sections(&mut self, ui: &mut egui::Ui) {
        let text_style = TextStyle::Body;
        let row_height = ui.text_style_height(&text_style);

        egui::Grid::new("sections_grid")
            .striped(true)
            .min_col_width(100.0)
            .show(ui, |ui| {
                ui.heading("Name");
                ui.heading("Address");
                ui.heading("Size");
                ui.end_row();

                for section in &self.analysis_result.sections {
                    ui.label(&section.name);
                    ui.label(format!("0x{:X}", section.address));
                    ui.label(format!("{}", section.size));
                    ui.end_row();
                }
            });
    }
}

struct AnalysisResult {
    format: object::BinaryFormat,
    architecture: object::Architecture,
    endianness: object::Endianness,
    sections: Vec<SectionInfo>,
}

impl Default for AnalysisResult {
    fn default() -> Self {
        Self {
            format: object::BinaryFormat::Pe,
            architecture: object::Architecture::Unknown,
            endianness: object::Endianness::Little,
            sections: Vec::new(),
        }
    }
}

impl AnalysisResult {
    fn is_empty(&self) -> bool {
        self.sections.is_empty()
    }
}

struct SectionInfo {
    name: String,
    address: u64,
    size: u64,
}

fn analyze_binary(path: &str) -> Result<AnalysisResult, String> {
    let mut file = File::open(path).map_err(|e| format!("Failed to open file: {}", e))?;

    let mut buffer = Vec::new();
    file.read_to_end(&mut buffer)
        .map_err(|e| format!("Failed to read file: {}", e))?;

    let obj_file = object::File::parse(&*buffer).map_err(|e| format!("Failed to parse binary: {}", e))?;

    let mut sections = Vec::new();
    for section in obj_file.sections() {
        let section_info = SectionInfo {
            name: section.name().unwrap_or("Unknown").to_string(),
            address: section.address(),
            size: section.size(),
        };
        sections.push(section_info);
    }

    Ok(AnalysisResult {
        format: obj_file.format(),
        architecture: obj_file.architecture(),
        endianness: obj_file.endianness(),
        sections,
    })
}