using FCOMMON; using System; using System.Drawing; using System.Windows.Forms; namespace Project.Dialog { /// /// User info for recipient selection /// public class ChatUserInfo { public string EmployeeId { get; set; } public string NickName { get; set; } public string UserGroup { get; set; } public override string ToString() { return $"{NickName} ({EmployeeId})"; } } public partial class fChat : fBase { private ChatClientService chatService; private string targetEmployeeId; private string targetNickName; /// /// Constructor for new chat or specific recipient /// public fChat(ChatClientService service, string targetEmployeeId = null, string targetNickName = null) { InitializeComponent(); this.chatService = service; this.targetEmployeeId = targetEmployeeId; this.targetNickName = targetNickName; this.KeyDown += (s, e) => { if (e.KeyCode == Keys.Escape) this.Close(); }; } private void fChat_Load(object sender, EventArgs e) { // Subscribe to message received event if (chatService != null) { chatService.MessageReceived += OnMessageReceived; } // Load user list for recipient selection LoadUserList(); // If target is specified, set it if (!string.IsNullOrEmpty(targetEmployeeId)) { SetRecipient(targetEmployeeId, targetNickName); } // Load recent messages (if any) RefreshConnectionStatus(); // Request user list from server if (chatService != null && chatService.IsConnected) { System.Diagnostics.Debug.WriteLine("[DEBUG] Requesting user list from server..."); chatService.RequestUserList(); } else { System.Diagnostics.Debug.WriteLine($"[DEBUG] Cannot request user list - Service: {chatService != null}, Connected: {chatService?.IsConnected}"); } } /// /// Load user list into combobox /// private void LoadUserList() { cboRecipient.Items.Clear(); // Add placeholder cboRecipient.Items.Add(new ChatUserInfo { EmployeeId = "", NickName = "Select recipient...", UserGroup = "" }); // In a real implementation, this would load from server // For now, user will need to type employee ID manually // The server's UserListResponse should populate this cboRecipient.SelectedIndex = 0; } /// /// Set specific recipient /// private void SetRecipient(string employeeId, string nickName) { targetEmployeeId = employeeId; targetNickName = nickName; // Try to find in combobox bool found = false; for (int i = 0; i < cboRecipient.Items.Count; i++) { var user = cboRecipient.Items[i] as ChatUserInfo; if (user != null && user.EmployeeId == employeeId) { cboRecipient.SelectedIndex = i; found = true; break; } } // If not found, add it if (!found && !string.IsNullOrEmpty(employeeId)) { var user = new ChatUserInfo { EmployeeId = employeeId, NickName = nickName ?? employeeId, UserGroup = "" }; cboRecipient.Items.Add(user); cboRecipient.SelectedItem = user; } // Update form title this.Text = $"Chat - {nickName ?? employeeId}"; } private void fChat_FormClosing(object sender, FormClosingEventArgs e) { // Unsubscribe events if (chatService != null) { chatService.MessageReceived -= OnMessageReceived; } } /// /// Message received event handler /// private void OnMessageReceived(object sender, ChatMessage message) { if (InvokeRequired) { BeginInvoke(new Action(() => OnMessageReceived(sender, message))); return; } // Get current recipient from combobox var selectedUser = cboRecipient.SelectedItem as ChatUserInfo; string currentTargetId = selectedUser?.EmployeeId ?? targetEmployeeId; // Filter messages - only show messages between current user and target string myEmployeeId = chatService.EmployeeId; // Show message if: // 1. It's from target to me // 2. It's from me to target (echo from server) // 3. It's a notice (broadcast) bool shouldDisplay = false; if (message.Type == MessageType.Notice) { shouldDisplay = true; // If it's a join/leave notice, refresh user list if (message.Content.Contains("has joined") || message.Content.Contains("has left")) { System.Diagnostics.Debug.WriteLine("[DEBUG] User joined/left, refreshing user list..."); if (chatService != null && chatService.IsConnected) { chatService.RequestUserList(); } } } else if (message.Type == MessageType.UserListResponse) { // Handle user list response HandleUserListResponse(message); return; } else if (!string.IsNullOrEmpty(currentTargetId)) { // From target to me if (message.EmployeeId == currentTargetId && message.TargetEmployeeId == myEmployeeId) { shouldDisplay = true; } // From me to target (echo) else if (message.EmployeeId == myEmployeeId && message.TargetEmployeeId == currentTargetId) { shouldDisplay = true; } } if (shouldDisplay) { AppendMessage(message); } } /// /// Handle user list response from server /// private void HandleUserListResponse(ChatMessage message) { try { System.Diagnostics.Debug.WriteLine($"[DEBUG] UserListResponse received: {message.Content}"); // Parse user list from Content (format: "employeeId1:nickName1:userGroup1,employeeId2:nickName2:userGroup2,...") if (string.IsNullOrEmpty(message.Content)) { System.Diagnostics.Debug.WriteLine("[DEBUG] UserListResponse content is empty"); return; } cboRecipient.Items.Clear(); // Add placeholder cboRecipient.Items.Add(new ChatUserInfo { EmployeeId = "", NickName = "Select recipient...", UserGroup = "" }); string[] users = message.Content.Split(','); System.Diagnostics.Debug.WriteLine($"[DEBUG] Parsing {users.Length} users"); foreach (var userStr in users) { if (string.IsNullOrWhiteSpace(userStr)) continue; string[] parts = userStr.Split(':'); System.Diagnostics.Debug.WriteLine($"[DEBUG] User parts: {string.Join(", ", parts)}"); if (parts.Length >= 2) { string empId = parts[0].Trim(); string nick = parts[1].Trim(); System.Diagnostics.Debug.WriteLine($"[DEBUG] Processing user: {empId} - {nick}, My ID: {chatService.EmployeeId}"); // Don't add myself if (empId != chatService.EmployeeId) { var user = new ChatUserInfo { EmployeeId = empId, NickName = nick, UserGroup = parts.Length > 2 ? parts[2].Trim() : "" }; cboRecipient.Items.Add(user); System.Diagnostics.Debug.WriteLine($"[DEBUG] Added user: {user}"); } else { System.Diagnostics.Debug.WriteLine($"[DEBUG] Skipped myself: {empId}"); } } } System.Diagnostics.Debug.WriteLine($"[DEBUG] Total items in combo: {cboRecipient.Items.Count}"); // Restore previous selection if exists if (!string.IsNullOrEmpty(targetEmployeeId)) { SetRecipient(targetEmployeeId, targetNickName); } else { cboRecipient.SelectedIndex = 0; } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"[ERROR] HandleUserListResponse: {ex.Message}"); MessageBox.Show($"Error loading user list: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } /// /// Append message to chat display /// private void AppendMessage(ChatMessage message) { string timeStr = message.Timestamp.ToString("HH:mm:ss"); string displayMsg = ""; switch (message.Type) { case MessageType.Chat: displayMsg = $"[{timeStr}] {message.NickName}: {message.Content}"; break; case MessageType.Notice: displayMsg = $"[{timeStr}] [NOTICE] {message.Content}"; break; case MessageType.Whisper: displayMsg = $"[{timeStr}] [WHISPER from {message.NickName}] {message.Content}"; break; default: return; } txtChatDisplay.AppendText(displayMsg + Environment.NewLine); txtChatDisplay.ScrollToCaret(); } /// /// Send button click /// private void btnSend_Click(object sender, EventArgs e) { SendMessage(); } /// /// Input text key down (Enter to send) /// private void txtInput_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) { e.SuppressKeyPress = true; SendMessage(); } } /// /// Send chat message /// private void SendMessage() { string content = txtInput.Text.Trim(); if (string.IsNullOrEmpty(content)) return; if (chatService == null || !chatService.IsConnected) { MessageBox.Show("Not connected to chat server.", "Chat", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } // Get target from combobox var selectedUser = cboRecipient.SelectedItem as ChatUserInfo; string currentTargetId = selectedUser?.EmployeeId ?? targetEmployeeId; if (string.IsNullOrEmpty(currentTargetId)) { MessageBox.Show("Please select a recipient.", "Chat", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } // Create message with target var message = new ChatMessage { Type = MessageType.Chat, Content = content, TargetEmployeeId = currentTargetId }; bool sent = chatService.SendMessage(message); if (sent) { // Note: Server will echo the message back, so we don't display it here // This prevents duplicate messages // Clear input txtInput.Text = ""; txtInput.Focus(); } else { MessageBox.Show("Failed to send message.", "Chat", MessageBoxButtons.OK, MessageBoxIcon.Error); } } /// /// Refresh connection status display /// private void RefreshConnectionStatus() { if (chatService != null && chatService.IsConnected) { lblStatus.Text = $"Connected - {chatService.NickName} ({chatService.UserGroup})"; lblStatus.ForeColor = Color.Green; } else { lblStatus.Text = "Disconnected"; lblStatus.ForeColor = Color.Red; } } /// /// Timer to update status periodically /// private void timerStatus_Tick(object sender, EventArgs e) { RefreshConnectionStatus(); } } }