using System.Diagnostics; using FrymasterBadgeApp.Services; using Microsoft.Data.SqlClient; using Microsoft.Maui.Storage; namespace FrymasterBadgeApp; public partial class CompanyPage : ContentPage { private readonly SqlService _db; private Dictionary? _selectedCompany; private string _tempLogoPath = ""; private const string LogoPathKey = "LogoBasePath"; /// /// Constructor for CompanyPage. /// of type ContentPage. /// the main page for viewing and editing company information. /// The SQLService object used to access the database. public CompanyPage(SqlService db) { InitializeComponent(); _db = db; Shell.SetBackButtonBehavior( this, new BackButtonBehavior { TextOverride = "Back", Command = new Command(async () => await Shell.Current.GoToAsync("..")), } ); LoadCompanies(); } /// /// Returns the path to the directory used to store company logos. /// /// The path to the directory used to store company logos. private string GetLogoDirectory() => Preferences.Default.Get(LogoPathKey, @"C:\FrymasterData\logos"); /// /// Loads the list of companies from the database. /// the results are ordered by company name (ascending). /// and displays the companies are stored in the CompanyList. /// private void LoadCompanies() { try { var companies = _db.Query("SELECT * FROM Companies ORDER BY Name ASC", null); CompanyList.ItemsSource = companies; } catch (Exception ex) { AppLogger.Error("Failed to load companies", ex); DisplayAlert("Error", "Failed to load companies.", "OK"); } } /// /// Called when the selection in the companies list changes. /// the selection is used to update the company name, address, city, state, zip code, and delete button visibility. /// private void OnCompanySelectionChanged(object sender, SelectionChangedEventArgs e) { var selected = e.CurrentSelection.FirstOrDefault() as Dictionary; if (selected == null) { ClearFields(); return; } _selectedCompany = selected; MainThread.BeginInvokeOnMainThread(async () => { CompName.Text = GetValue(selected, "Name"); CompAddress.Text = GetValue(selected, "Address"); CompCity.Text = GetValue(selected, "City"); CompState.Text = GetValue(selected, "State"); CompZip.Text = GetValue(selected, "Zip"); DeleteBtn.IsVisible = true; LogoPreview.Source = null; _tempLogoPath = ""; // Get stored filename only string storedFileName = GetValue(selected, "logo"); if (!string.IsNullOrWhiteSpace(storedFileName)) { string logoDir = GetLogoDirectory(); string fullPath = Path.Combine(logoDir, storedFileName); if (File.Exists(fullPath)) { _tempLogoPath = fullPath; LogoPreview.Source = ImageSource.FromFile(fullPath); AppLogger.Info($"Logo loaded for company: {fullPath}"); } else { AppLogger.Warning($"Logo file missing: {fullPath}"); } } }); } /// /// Returns the value of the given key from the dictionary, trimmed of whitespace. /// If the key does not exist, an empty string is returned. /// /// The dictionary to search. /// The key to search for. /// The value of the given key, trimmed of whitespace, or an empty string if the key does not exist. private string GetValue(Dictionary dict, string key) { var actualKey = dict.Keys.FirstOrDefault(k => k.Equals(key, StringComparison.OrdinalIgnoreCase) ); return actualKey != null ? dict[actualKey]?.ToString()?.Trim() ?? "" : ""; } /// /// Called when the user selects a logo image from the file picker. /// /// The object that triggered the event /// The event data which contains information about the event private async void OnSelectLogoClicked(object sender, EventArgs e) { try { var result = await FilePicker.Default.PickAsync( new PickOptions { PickerTitle = "Select Company Logo", FileTypes = FilePickerFileType.Images, } ); if (result != null) { _tempLogoPath = result.FullPath; LogoPreview.Source = ImageSource.FromFile(_tempLogoPath); } } catch (Exception ex) { await DisplayAlert("Error", $"Failed to select logo: {ex.Message}", "OK"); } } /// /// Save the selected company to the database. /// /// The object that invoked this method. /// The event data for this method. private async void OnSaveClicked(object sender, EventArgs e) { if (string.IsNullOrWhiteSpace(CompName.Text)) { await DisplayAlert("Error", "Company Name is required", "OK"); return; } string logoDir = GetLogoDirectory(); if (!Directory.Exists(logoDir)) { try { Directory.CreateDirectory(logoDir); } catch { await DisplayAlert("Error", "Cannot create logo directory.", "OK"); return; } } string logoFileNameToSave = ""; // will be stored in DB if (!string.IsNullOrEmpty(_tempLogoPath)) { try { string originalFileName = Path.GetFileName(_tempLogoPath); string extension = Path.GetExtension(originalFileName); string baseName = Path.GetFileNameWithoutExtension(originalFileName); // Avoid overwrites: add timestamp if file already exists string destFileName = originalFileName; string destPath = Path.Combine(logoDir, destFileName); if (File.Exists(destPath)) { destFileName = $"{baseName}_{DateTime.Now:yyyyMMdd_HHmmss}{extension}"; destPath = Path.Combine(logoDir, destFileName); } File.Copy(_tempLogoPath, destPath, true); logoFileNameToSave = destFileName; // only filename saved to DB _tempLogoPath = destPath; // update local temp for preview AppLogger.Info($"Logo saved as: {destPath}"); } catch (Exception ex) { AppLogger.Error("Failed to copy logo", ex); await DisplayAlert("Error", "Failed to save logo file.", "OK"); return; } } try { var parameters = new List { new("@n", CompName.Text ?? ""), new("@a", CompAddress.Text ?? ""), new("@c", CompCity.Text ?? ""), new("@s", CompState.Text ?? ""), new("@z", CompZip.Text ?? ""), new("@l", logoFileNameToSave), // ← only filename }; if (_selectedCompany == null) { _db.Execute( "INSERT INTO Companies (Name, Address, City, State, Zip, logo) VALUES (@n, @a, @c, @s, @z, @l)", parameters.ToArray() ); await DisplayAlert("Success", "Company added.", "OK"); } else { parameters.Add(new("@id", _selectedCompany["ID"])); _db.Execute( "UPDATE Companies SET Name=@n, Address=@a, City=@c, State=@s, Zip=@z, logo=@l WHERE ID=@id", parameters.ToArray() ); await DisplayAlert("Success", "Company updated.", "OK"); } LoadCompanies(); ClearFields(); } catch (Exception ex) { AppLogger.Error("Database save failed", ex); await DisplayAlert("Database Error", ex.Message, "OK"); } } /// /// Resets the UI state after clicking the "Add New" button. /// private void OnAddNewClicked(object sender, EventArgs e) { CompanyList.SelectedItem = null; ClearFields(); } /// /// Resets the UI state after clicking the "Add New" button or deleting a company. /// private void ClearFields() { _selectedCompany = null; _tempLogoPath = ""; CompName.Text = CompAddress.Text = CompCity.Text = CompState.Text = CompZip.Text = ""; LogoPreview.Source = null; DeleteBtn.IsVisible = false; } /// /// Delete a company from the database. /// private async void OnDeleteClicked(object sender, EventArgs e) { if (_selectedCompany == null) return; if (await DisplayAlert("Confirm", $"Delete {CompName.Text}?", "Yes", "No")) { try { _db.Execute( "DELETE FROM Companies WHERE ID=@id", new SqlParameter[] { new("@id", _selectedCompany["ID"]) } ); LoadCompanies(); ClearFields(); } catch (Exception ex) { await DisplayAlert("Error", ex.Message, "OK"); } } } }