private void TabDynamic_SelectionChanged(object sender, SelectionChangedEventArgs e)
 {
     if (tabControl.SelectedItem is ChatRoomView tab && tab.Name != null)
     {
         if (tab.Name.Equals("+"))
         {
             PopupDialog popup = new PopupDialog();
             popup.ShowDialog();
             string name;
             if (popup.Canceled == true)
             {
                 return;
             }
             else
             {
                 string result = popup.RoomName;
                 name = result;
             }
             if (!(name.Equals("+") || name == string.Empty))
             {
                 ChatRoomView newTab = new ChatRoomView(name);
                 Tabs.Insert(Tabs.Count - 1, newTab);
                 tabControl.ItemsSource  = Tabs;
                 tabControl.SelectedItem = newTab;
                 BinaryWriter writer = new BinaryWriter(_sslStream);
                 writer.Write((int)Opcode.Join);
                 writer.Write(name);
                 writer.Flush();
             }
         }
     }
 }
 /// <summary>
 /// Updates the UI thread whenever the server sends a message or user status update.
 /// </summary>
 /// <param name="sender"></param>
 /// <param name="e"></param>
 private void BgCheck_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
 {
     if (_client.Connected)
     {
         /*listBox.ItemsSource = null;
          * lock (_syncLock)
          * {
          *  listBox.ItemsSource = users;
          * }*/
         // Update UI
         if (e.Result is Tuple <string, string> )
         {
             // if it is not string, it assigns null
             if (e.Result is Tuple <string, string> response)
             {
                 ChatRoomView tab = Tabs.FirstOrDefault(i => i.Name == response.Item1);
                 if (tab != null)
                 {
                     lock (tab._syncLock2)
                     {
                         tab.Messages.Add(new Message(null, tab.Name, null, DateTime.Now, null, response.Item2, Brushes.Blue.ToString()));
                     }
                 }
             }
         }
         else if (e.Result is Message)
         {
             if (e.Result is Message message)
             {
                 Console.Write(message.Chatroom);
                 ChatRoomView tab = Tabs.FirstOrDefault(i => i.Name == message.Chatroom);
                 if (tab != null)
                 {
                     lock (tab._syncLock2)
                     {
                         tab.Messages.Add(message);
                     }
                 }
             }
         }
         // Continue listening on server stream
         _backgroundWorker.RunWorkerAsync();
     }
     else
     {
         // SEND TO ALL TABS
         foreach (ChatRoomView tab in Tabs)
         {
             if (tab != null)
             {
                 lock (tab._syncLock2)
                 {
                     tab.Messages.Add(new Message(null, tab.Name, null, DateTime.Now, null, "You have been disconnected from the server.", Brushes.Red.ToString()));
                 }
             }
         }
         DropClient();
     }
 }
        /// <summary>
        /// Sends encrypted message to each user currently connected to the server.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        ///
        private void TextBox_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (e.Key == Key.Enter && Keyboard.Modifiers != ModifierKeys.Shift)
            {
                e.Handled = true;
                //TabItem ti = (TabItem)tabControl.SelectedItem;
                //var tab = Tabs.FirstOrDefault(i => i.Name == ti.Header.ToString());
                Console.WriteLine("Click: ");
                ChatRoomView tab = tabControl.SelectedItem as ChatRoomView;

                Console.WriteLine("Click: " + tab.Name);
                try
                {
                    if (_client.Connected)
                    {
                        BinaryWriter writer = new BinaryWriter(_sslStream);
                        foreach (User user in tab.Users)
                        {
                            Console.WriteLine("Sending message to: " + user.UserName);
                            Message message = new Message(_currentUser.UserName, tab.Name, user, DateTime.UtcNow, null, tab.Message, ClrPcker_Background.SelectedColor.Value.ToString());
                            message.Encrypt();
                            byte[] encryptedMessage = Serialize(message);
                            int    count            = encryptedMessage.Count();
                            writer.Write((int)Opcode.SendMessage);
                            writer.Write(tab.Name); // add chat room
                            writer.Write(user.UserName);
                            writer.Write(count);
                            writer.Write(encryptedMessage);
                            writer.Flush();
                        }

                        tab.Messages.Add(new Message(_currentUser.UserName, tab.Name, null, DateTime.UtcNow, null, tab.Message, ClrPcker_Background.SelectedColor.Value.ToString()));
                        tab.Message = string.Empty;
                        // textBox.Clear();
                    }
                }
                catch (SocketException ex)
                {
                    Console.WriteLine("SocketException: {0}", ex);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Exception: {0}", ex);
                    tab.Messages.Add(new Message(null, tab.Name, null, DateTime.Now, null, "There was an exception in encrypting and sending the message. Make sure the private key is not corrupt or missing", Brushes.Red.ToString()));
                }
            }
        }
        /// <summary>
        /// Listens for any communication from the server.
        /// Three opcodes are used for communication from the server.
        /// OpCode 1 - Update entire User list
        /// OpCode 2 - Add/Remove single user
        /// OpCode 3 - New Message
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ServerListener(object sender, DoWorkEventArgs e)
        {
            try
            {
                BinaryReader reader = new BinaryReader(_sslStream);
                int          OpCode = reader.ReadInt32();

                Console.WriteLine("reading opcode: " + OpCode);
                if (OpCode == (int)ServerOpcode.GetUsers)
                {
                    Console.WriteLine("OPCODE 2 HAS BEEN ACCEPTED");
                    string userName  = reader.ReadString();
                    string publicKey = reader.ReadString();
                    string chatRoom  = reader.ReadString();
                    User   user      = new User(userName, publicKey);
                    Console.WriteLine("adding user: "******" to : " + chatRoom);
                    ChatRoomView tab = Tabs.FirstOrDefault(i => i.Name == chatRoom);
                    if (tab != null)
                    {
                        lock (tab._syncLock)
                        {
                            tab.Users.Add(user);
                        }
                    }
                    e.Result = null; //no message is passed on to UI
                }
                else if (OpCode == (int)ServerOpcode.UpdateUser)
                {
                    Console.WriteLine("OPCODE 2 HAS BEEN ACCEPTED");
                    string userName  = reader.ReadString();  //username of other client
                    string publicKey = reader.ReadString();
                    bool   status    = reader.ReadBoolean(); //connecting (true) or disconnecting (false)
                    string chatRoom  = reader.ReadString();
                    string message   = null;
                    User   user      = new User(userName, publicKey);
                    if (status)
                    {
                        ChatRoomView tab = Tabs.FirstOrDefault(i => i.Name == chatRoom);
                        if (tab != null)
                        {
                            lock (tab._syncLock)
                            {
                                Console.WriteLine("Adding " + user.UserName + " to " + chatRoom);
                                tab.Users.Add(user);
                            }
                        }
                        message = userName + " has joined the chat.";
                    }
                    else
                    {
                        ChatRoomView tab = Tabs.FirstOrDefault(i => i.Name == chatRoom);
                        if (tab != null)
                        {
                            List <User> usersCopy = new List <User>(tab.Users);
                            foreach (User item in usersCopy)
                            {
                                if (item.UserName == userName)
                                {
                                    lock (tab._syncLock)
                                    {
                                        tab.Users.Remove(item);
                                    }
                                }
                            }
                        }
                        message = userName + " has left the chat.";
                    }
                    e.Result = new Tuple <string, string>(chatRoom, message); //pass on message to UI
                }
                else if (OpCode == (int)ServerOpcode.UserMessage)
                {
                    string  chatRoom         = reader.ReadString();
                    string  username         = reader.ReadString();
                    int     count            = reader.ReadInt32();
                    byte[]  encryptedMessage = reader.ReadBytes(count);
                    Message message          = (Message)Deserialize(encryptedMessage);
                    message.Decrypt();
                    //string decryptedMessage = RSADecrypt(encryptedMessage, privateKey);
                    //string message = username + ": " + decryptedMessage;
                    e.Result = message;                             //pass on message to UI
                }
                else if (OpCode == (int)ServerOpcode.SystemMessage) //System message
                {
                    string chatRoom = reader.ReadString();
                    string message  = reader.ReadString();
                    e.Result = new Tuple <string, string>(chatRoom, message); //pass on message to UI
                }
            }
            catch (IOException ex)
            {
                Console.WriteLine("ServerListener IOException: " + ex);
            }
            catch (Exception ex)
            {
                Console.WriteLine("ServerListener exception: " + ex);
            }
        }
        /// <summary>
        /// Connects to the server and authenticates the user. If the user is authenticated, a background worker thread is created
        /// to listen to any server communication. This is done in a background thread to free up the main UI thread, as to prevent freezing.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ButtonConnect_Click(object sender, RoutedEventArgs e)
        {
            /*
             * TabItem ti = (TabItem)tabControl.SelectedItem;
             * var tab = Tabs.FirstOrDefault(i => i.Name == ti.Header.ToString()); */
            ChatRoomView tab = tabControl.SelectedItem as ChatRoomView;

            try
            {
                tab.Messages.Add(new Message(null, tab.Name, null, DateTime.Now, "Connecting to Server...", "Connecting to Server...", Brushes.Blue.ToString()));
                _serverIP = textBoxIP.Text;
                _port     = Convert.ToInt32(textBoxPort.Text);
                _client   = new TcpClient(); //causes the handle of the previous TcpClient to be lost
                _client.Connect(_serverIP, _port);

                var clientCertificateCollection = new X509CertificateCollection(new X509Certificate[] { new X509Certificate2(_clientCertificateFile, _clientCertificatePassword) });

                //creates an SSL Stream that contains the TCP client socket as the underlying stream.
                _sslStream = new SslStream(_client.GetStream(), false, App_CertificateValidation);
                _sslStream.AuthenticateAsClient(_serverCertificateName, clientCertificateCollection, SslProtocols.Tls12, false);

                tab.Messages.Add(new Message(null, tab.Name, null, DateTime.Now, null, "Authenticating User...", Brushes.Blue.ToString()));

                // Send username and password to sever for authentication
                var writer = new BinaryWriter(_sslStream);
                writer.Write(textBoxUsername.Text);
                writer.Write(passwordBox.Password);
                writer.Write("Global"); // Chat group name sent
                writer.Flush();

                // Receieve response from server about authentication
                var    reader   = new BinaryReader(_sslStream);
                bool   result   = reader.ReadBoolean();
                string response = reader.ReadString();

                if (result == false)
                {
                    tab.Messages.Add(new Message(null, tab.Name, null, DateTime.Now, null, response, Brushes.Red.ToString()));
                    _sslStream.Close();
                    writer.Close();
                    DropClient();
                }
                else
                {
                    _currentUser           = new User(textBoxUsername.Text, null);
                    _currentUser.PublicKey = GetOrGenerateKeyPair(_currentUser.UserName);

                    // send public key
                    writer.Write(_currentUser.PublicKey);
                    writer.Flush();

                    buttonDisconnect.IsEnabled = true;
                    buttonConnect.IsEnabled    = false;
                    tab.Messages.Add(new Message(null, tab.Name, null, DateTime.Now, null, "Connected to Server: " + textBoxIP.Text, Brushes.Blue.ToString()));
                    _backgroundWorker = new BackgroundWorker();
                    Console.WriteLine("Starting background worker listener");
                    _backgroundWorker.DoWork             += ServerListener;
                    _backgroundWorker.RunWorkerCompleted += BgCheck_RunWorkerCompleted;
                    _backgroundWorker.RunWorkerAsync();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                DropClient();
            }
        }