namespace PainoBar_Helper { public partial class Main : Form { private readonly ProfileManager _profileManager; private readonly PianobarManager _pianobarManager; private OutputManager? _outputManager; private System.Windows.Forms.Timer? _statusTimer; private bool _statusToggle = false; // Connection status enum private enum ConnectionStatus { Disconnected, // Red ConnectedIdle, // Green ConnectedActive // Blue } private ConnectionStatus _currentStatus = ConnectionStatus.Disconnected; public Main() { InitializeComponent(); _profileManager = new ProfileManager(); _pianobarManager = new PianobarManager(); InitializeMenus(); InitializeStatusBar(); InitializeEvents(); UpdateProfilesMenu(); UpdateConnectionStatus(ConnectionStatus.Disconnected); // Set initial status if (statusLabelRight != null) { var activeProfile = _profileManager.GetActiveProfile(); if (activeProfile != null) { statusLabelRight.Text = $"Ready - Profile: {activeProfile.Name}"; } else if (_profileManager.Profiles.Any()) { // If no active profile but profiles exist, set the first one as active _profileManager.SetActiveProfile(_profileManager.Profiles.First().Name); statusLabelRight.Text = $"Ready - Profile: {_profileManager.ActiveProfileName}"; } else { statusLabelRight.Text = "Ready - No profile configured"; } } } #region Initialization private void InitializeMenus() { // File menu is assumed to be created in the Designer // This method sets up dynamic profile menu items } private void InitializeStatusBar() { // Status bar zones are assumed to be created in the Designer: // - statusLabelLeft: Connection indicator // - statusLabelCenter: Alternating status (Profile/Station) // - statusLabelRight: Event feed _statusTimer = new System.Windows.Forms.Timer(); _statusTimer.Interval = 10000; // 10 seconds _statusTimer.Tick += StatusTimer_Tick; _statusTimer.Start(); UpdateCenterStatus(); } private void InitializeEvents() { // Pianobar events _pianobarManager.Connected += PianobarManager_Connected; _pianobarManager.Disconnected += PianobarManager_Disconnected; _pianobarManager.SongChanged += PianobarManager_SongChanged; _pianobarManager.StationChanged += PianobarManager_StationChanged; _pianobarManager.EventOccurred += PianobarManager_EventOccurred; // Profile events _profileManager.ProfilesChanged += ProfileManager_ProfilesChanged; _profileManager.ActiveProfileChanged += ProfileManager_ActiveProfileChanged; } #endregion #region Button Event Handlers // This method should be wired to btnConnect.Click in the Designer public void btnConnect_Click(object? sender, EventArgs e) { if (_pianobarManager.IsConnected) { MessageBox.Show("Already connected to Pianobar.", "Already Connected", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } // Get pianobar.exe path from active profile or use default var activeProfile = _profileManager.GetActiveProfile(); if (activeProfile == null) { var result = MessageBox.Show( "No profile selected. Would you like to create one now?\n\n" + "Click Yes to open Settings, or No to cancel.", "No Profile", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (result == DialogResult.Yes) { menuSettings_Click(sender, e); } return; } string pianobarPath = activeProfile.Settings.PianobarPath; string? configPath = _profileManager.GetActiveConfigPath(); string? eventFilePath = _profileManager.GetEventOutputPath(); // Debug information string debugInfo = $"Profile: {activeProfile.Name}\n" + $"Pianobar Path: {pianobarPath}\n" + $"Config Path: {configPath ?? "(none)"}\n" + $"Event File: {eventFilePath ?? "(none)"}\n" + $"File Exists: {File.Exists(pianobarPath)}"; try { // Update status to show we're attempting connection if (statusLabelRight != null) statusLabelRight.Text = $"Starting Pianobar..."; _pianobarManager.Connect(pianobarPath, configPath, eventFilePath); // Success message will be shown by the Connected event handler } catch (Exception ex) { // Update status to show connection failed if (statusLabelRight != null) statusLabelRight.Text = "Failed to start Pianobar"; MessageBox.Show( $"Failed to start Pianobar:\n\n{ex.Message}\n\n" + $"Debug Information:\n{debugInfo}", "Connection Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } // This method should be wired to btnDisconnect.Click in the Designer public void btnDisconnect_Click(object? sender, EventArgs e) { if (!_pianobarManager.IsConnected) { MessageBox.Show("Not connected to Pianobar.", "Not Connected", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } if (statusLabelRight != null) statusLabelRight.Text = "Disconnecting..."; // Check if we should kill the process or just detach var activeProfile = _profileManager.GetActiveProfile(); bool killProcess = activeProfile?.Settings.KillProcessOnDisconnect ?? false; if (killProcess) { _pianobarManager.DisconnectAndKill(); } else { _pianobarManager.Disconnect(); } _outputManager?.Stop(); } // This method should be wired to btnPlayPause.Click in the Designer public void btnPlayPause_Click(object? sender, EventArgs e) { if (!_pianobarManager.IsConnected) { MessageBox.Show("Not connected to Pianobar.", "Not Connected", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } try { _pianobarManager.PlayPause(); UpdatePlayPauseButton(); } catch (Exception ex) { MessageBox.Show($"Failed to toggle play/pause:\n{ex.Message}", "Command Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } // This method should be wired to btnSkip.Click in the Designer public void btnSkip_Click(object? sender, EventArgs e) { if (!_pianobarManager.IsConnected) { MessageBox.Show("Not connected to Pianobar.", "Not Connected", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } try { _pianobarManager.Skip(); } catch (Exception ex) { MessageBox.Show($"Failed to skip track:\n{ex.Message}", "Command Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } // This method should be wired to btnStations.Click in the Designer (or menu item) public void btnStations_Click(object? sender, EventArgs e) { if (!_pianobarManager.IsConnected) { MessageBox.Show("Not connected to Pianobar.", "Not Connected", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } var stationForm = new StationForm(_pianobarManager); stationForm.ShowDialog(this); } #endregion #region Menu Event Handlers // This method should be wired to the Settings menu item click public void menuSettings_Click(object? sender, EventArgs e) { var activeProfile = _profileManager.GetActiveProfile(); var settingsForm = new SettingsForm(_profileManager, activeProfile?.Settings ?? new ProfileSettings()); if (settingsForm.ShowDialog(this) == DialogResult.OK) { // Settings were saved, update the UI UpdateProfilesMenu(); // Update status to show the new active profile var newActiveProfile = _profileManager.GetActiveProfile(); if (newActiveProfile != null && statusLabelRight != null) { statusLabelRight.Text = $"Profile saved: {newActiveProfile.Name}"; } // Restart output manager if connected if (_pianobarManager.IsConnected) { RestartOutputManager(); } } } private void ProfileManager_ProfilesChanged(object? sender, EventArgs e) { UpdateProfilesMenu(); } private void ProfileManager_ActiveProfileChanged(object? sender, EventArgs e) { UpdateProfilesMenu(); UpdateCenterStatus(); } // Call this method to build the Profiles submenu dynamically private void UpdateProfilesMenu() { // Assumes menuProfiles (profilesToolStripMenuItem) is a ToolStripMenuItem in your File menu // Created in the Designer if (profilesToolStripMenuItem == null) return; profilesToolStripMenuItem.DropDownItems.Clear(); foreach (var profile in _profileManager.Profiles) { var menuItem = new ToolStripMenuItem(profile.Name); menuItem.Tag = profile.Name; menuItem.Click += ProfileMenuItem_Click; if (profile.Name == _profileManager.ActiveProfileName) menuItem.Checked = true; profilesToolStripMenuItem.DropDownItems.Add(menuItem); } } private void ProfileMenuItem_Click(object? sender, EventArgs e) { if (sender is ToolStripMenuItem menuItem && menuItem.Tag is string profileName) { _profileManager.SetActiveProfile(profileName); } } #endregion #region Pianobar Event Handlers private void PianobarManager_Connected(object? sender, EventArgs e) { Invoke(() => { var activeProfile = _profileManager.GetActiveProfile(); if (activeProfile != null) { _outputManager = new OutputManager(activeProfile.Settings); _outputManager.ActiveStateChanged += OutputManager_ActiveStateChanged; _outputManager.Start(); } UpdateConnectionStatus( _outputManager?.IsActive == true ? ConnectionStatus.ConnectedActive : ConnectionStatus.ConnectedIdle ); UpdatePlayPauseButton(); }); } private void PianobarManager_Disconnected(object? sender, EventArgs e) { Invoke(() => { _outputManager?.Stop(); _outputManager = null; UpdateConnectionStatus(ConnectionStatus.Disconnected); UpdatePlayPauseButton(); }); } private void PianobarManager_SongChanged(object? sender, SongChangedEventArgs e) { Invoke(() => { _outputManager?.UpdateSongMetadata(e); }); } private void PianobarManager_StationChanged(object? sender, string e) { // Station change is handled via event feed UpdateCenterStatus(); } private void PianobarManager_EventOccurred(object? sender, PianobarEventArgs e) { Invoke(() => { // Update right status zone with event text if (statusLabelRight != null) { statusLabelRight.Text = e.EventText; } }); } private void OutputManager_ActiveStateChanged(object? sender, EventArgs e) { Invoke(() => { if (_pianobarManager.IsConnected) { UpdateConnectionStatus( _outputManager?.IsActive == true ? ConnectionStatus.ConnectedActive : ConnectionStatus.ConnectedIdle ); } }); } #endregion #region UI Update Methods private void UpdateConnectionStatus(ConnectionStatus status) { _currentStatus = status; if (statusLabelLeft == null) return; switch (status) { case ConnectionStatus.Disconnected: statusLabelLeft.Text = "? Disconnected"; statusLabelLeft.ForeColor = Color.Red; break; case ConnectionStatus.ConnectedIdle: statusLabelLeft.Text = "? Connected (Idle)"; statusLabelLeft.ForeColor = Color.Green; break; case ConnectionStatus.ConnectedActive: statusLabelLeft.Text = "? Connected (Active)"; statusLabelLeft.ForeColor = Color.Blue; break; } } private void UpdatePlayPauseButton() { // Uses btnPlayPause from the Designer if (btnPlayPause == null) return; if (!_pianobarManager.IsConnected) { btnPlayPause.Text = "Play"; return; } btnPlayPause.Text = _pianobarManager.IsPlaying ? "Pause" : "Play"; } private void StatusTimer_Tick(object? sender, EventArgs e) { _statusToggle = !_statusToggle; UpdateCenterStatus(); } private void UpdateCenterStatus() { if (statusLabelCenter == null) return; if (_statusToggle) { // Show profile string profileName = _profileManager.ActiveProfileName ?? "None"; statusLabelCenter.Text = $"Profile: {profileName}"; } else { // Show station string station = _pianobarManager.CurrentStation ?? "None"; statusLabelCenter.Text = $"Station: {station}"; } } private void RestartOutputManager() { _outputManager?.Stop(); var activeProfile = _profileManager.GetActiveProfile(); if (activeProfile != null && _pianobarManager.IsConnected) { _outputManager = new OutputManager(activeProfile.Settings); _outputManager.ActiveStateChanged += OutputManager_ActiveStateChanged; _outputManager.Start(); UpdateConnectionStatus( _outputManager.IsActive ? ConnectionStatus.ConnectedActive : ConnectionStatus.ConnectedIdle ); } } #endregion #region Cleanup protected override void OnFormClosing(FormClosingEventArgs e) { _statusTimer?.Stop(); _pianobarManager?.Disconnect(); _outputManager?.Dispose(); base.OnFormClosing(e); } #endregion } }