WingMan – Rev 5

Subversion Repositories:
Rev:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Windows.Forms;
using Gma.System.MouseKeyHook;
using WingMan.Communication;
using WingMan.MouseKey;
using WingMan.Properties;

namespace WingMan
{
    public partial class WingManForm : Form
    {
        public WingManForm()
        {
            InitializeComponent();

            MQTTCommunication = new MQTTCommunication();

            MouseKeyBindings = new MouseKeyBindings(new List<MouseKeyBinding>());

            HelmBindingSource = new BindingSource
            {
                DataSource = MouseKeyBindings.Bindings
            };
            HelmBindingsListBox.DisplayMember = "DisplayName";
            HelmBindingsListBox.ValueMember = "Keys";
            HelmBindingsListBox.DataSource = HelmBindingSource;

            MouseKeyBindingsExchange = new MouseKeyBindingsExchange();
            WingBindingSource = new BindingSource
            {
                DataSource = MouseKeyBindingsExchange.ExchangeBindings
            };
            WingBindingsComboBox.DisplayMember = "Nick";
            WingBindingsComboBox.ValueMember = "Names";
            WingBindingsComboBox.DataSource = WingBindingSource;

            // Start lobby message synchronizer.
            LobbyMessageSynchronizer = new LobbyMessageSynchronizer(MQTTCommunication);
            LobbyMessageSynchronizer.OnLobbyMessageReceived += OnLobbyMessageReceived;

            // Start mouse key bindings synchronizer.
            MouseKeyBindingsSynchronizer = new MouseKeyBindingsSynchronizer(MouseKeyBindings, MQTTCommunication);
            MouseKeyBindingsSynchronizer.OnMouseKeyBindingsSynchronized += OnMouseKeyBindingsSynchronized;
        }

        private void OnMouseKeyBindingsSynchronized(object sender, MouseKeyBindingsSynchronizedEventArgs e)
        {
            this.Invoke((MethodInvoker) delegate
            {
                foreach (var binding in e.ExchangeBindings)
                {
                    ActivityTextBox.AppendText(
                        $"{Strings.Synchronized_bindings_with_client} : {binding.Nick} : {binding.Names.Count}{Environment.NewLine}");


                    var exchangeBindings = MouseKeyBindingsExchange.ExchangeBindings.FirstOrDefault(exchangeBinding =>
                        string.Equals(exchangeBinding.Nick, binding.Nick, StringComparison.Ordinal));

                    // If the nick has not been registered add it.
                    if (exchangeBindings == null)
                    {
                        MouseKeyBindingsExchange.ExchangeBindings.Add(binding);
                        continue;
                    }

                    // If the nick has been added, then update the binding names.
                    exchangeBindings.Names = binding.Names;

                    // Update wing list box.
                    var selectedExchangeBinding = (MouseKeyBindingExchange)WingBindingsComboBox.SelectedItem;
                    if (selectedExchangeBinding == null || !string.Equals(selectedExchangeBinding.Nick, binding.Nick))
                        continue;

                    WingBindingsListBox.Items.Clear();
                    WingBindingsListBox.DisplayMember = "Name";
                    WingBindingsListBox.ValueMember = "Name";
                    WingBindingsListBox.Items.AddRange(exchangeBindings.Names.Select(name => (object)name).ToArray());

                }

                WingBindingSource.ResetBindings(false);

            });
        }

        private static IKeyboardMouseEvents MouseKeyApplicationHook { get; set; }

        private List<string> MouseKeyCombo { get; set; }

        private MouseKeyBindings MouseKeyBindings { get; }

        private BindingSource HelmBindingSource { get; }

        private BindingSource WingBindingSource { get; set; }

        private MouseKeyBindingsExchange MouseKeyBindingsExchange { get; set; }

        public MQTTCommunication MQTTCommunication { get; set; }

        public LobbyMessageSynchronizer LobbyMessageSynchronizer { get; set; }

        public MouseKeyBindingsSynchronizer MouseKeyBindingsSynchronizer { get; set; }

        private void OnLobbyMessageReceived(object sender, LobbyMessageReceivedEventArgs e)
        {
            LobbyTextBox.Invoke((MethodInvoker) delegate
            {
                LobbyTextBox.AppendText($"{e.Nick} : {e.Message}{Environment.NewLine}");
            });
        }

        private void AddressTextBoxClick(object sender, EventArgs e)
        {
            Address.BackColor = Color.Empty;
        }

        private void PortTextBoxClick(object sender, EventArgs e)
        {
            Port.BackColor = Color.Empty;
        }

        private async void HostButtonClickAsync(object sender, EventArgs e)
        {
            // Stop the MQTT server if it is running.
            if (MQTTCommunication.Running)
            {
                await MQTTCommunication.Stop().ConfigureAwait(false);
                toolStripStatusLabel.Text = Strings.Server_stopped;
                HostButton.BackColor = Color.Empty;

                // Enable controls.
                ConnectButton.Enabled = true;
                Address.Enabled = true;
                Port.Enabled = true;
                Nick.Enabled = true;

                return;
            }

            if (!ValidateAddressPort(out var ipAddress, out var port, out var nick))
                return;

            // Start the MQTT server.
            await MQTTCommunication.Start(MQTTCommunicationType.Server, ipAddress, port, nick).ConfigureAwait(false);
            toolStripStatusLabel.Text = Strings.Server_started;
            HostButton.BackColor = Color.Aquamarine;

            // Disable controls
            ConnectButton.Enabled = false;
            Address.Enabled = false;
            Port.Enabled = false;
            Nick.Enabled = false;
        }

        private bool ValidateAddressPort(out IPAddress address, out int port, out string nick)
        {
            address = IPAddress.Any;
            port = 0;
            nick = string.Empty;

            if (string.IsNullOrEmpty(Address.Text) &&
                string.IsNullOrEmpty(Port.Text) &&
                string.IsNullOrEmpty(Nick.Text))
            {
                Address.BackColor = Color.LightPink;
                Port.BackColor = Color.LightPink;
                Nick.BackColor = Color.LightPink;
                return false;
            }

            if (!IPAddress.TryParse(Address.Text, out address))
            {
                Address.BackColor = Color.LightPink;
                return false;
            }

            if (!uint.TryParse(Port.Text, out var uPort))
            {
                Port.BackColor = Color.LightPink;
                return false;
            }

            port = (int) uPort;

            if (string.IsNullOrEmpty(Nick.Text))
            {
                Nick.BackColor = Color.LightPink;
                return false;
            }

            nick = Nick.Text;

            Address.BackColor = Color.Empty;
            Port.BackColor = Color.Empty;
            Nick.BackColor = Color.Empty;

            return true;
        }

        private async void ConnectButtonClickAsync(object sender, EventArgs e)
        {
            if (MQTTCommunication.Running)
            {
                await MQTTCommunication.Stop().ConfigureAwait(false);
                ConnectButton.Text = Strings.Connect;
                ConnectButton.BackColor = Color.Empty;

                Address.Enabled = true;
                Port.Enabled = true;
                Nick.Enabled = true;
                HostButton.Enabled = true;
                return;
            }

            if (!ValidateAddressPort(out var ipAddress, out var port, out var nick))
                return;

            await MQTTCommunication.Start(MQTTCommunicationType.Client, ipAddress, port, nick).ConfigureAwait(false);

            toolStripStatusLabel.Text = Strings.Client_started;
            ConnectButton.Text = Strings.Disconnect;
            ConnectButton.BackColor = Color.Aquamarine;

            HostButton.Enabled = false;
            Address.Enabled = false;
            Port.Enabled = false;
            Nick.Enabled = false;
        }

        private async void LobbySayTextBoxKeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode != Keys.Enter)
                return;

            await LobbyMessageSynchronizer.Broadcast(LobbySayTextBox.Text).ConfigureAwait(false);

            LobbySayTextBox.Text = string.Empty;
        }

        private void HelmAddButtonClick(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(HelmNameTextBox.Text))
            {
                HelmNameTextBox.BackColor = Color.LightPink;
                return;
            }

            HelmAddButton.Enabled = false;

            MouseKeyCombo = new List<string>();

            MouseKeyApplicationHook = Hook.AppEvents();
            MouseKeyApplicationHook.MouseDown += MouseKeyHookOnMouseDown;
            MouseKeyApplicationHook.KeyUp += MouseKeyHookOnKeyUp;
            MouseKeyApplicationHook.KeyDown += MouseKeyHookOnKeyDown;
            MouseKeyApplicationHook.MouseUp += MouseKeyHookOnMouseUp;
        }

        private void MouseKeyHookOnKeyUp(object sender, KeyEventArgs e)
        {
            MouseKeyBindings.Bindings.Add(new MouseKeyBinding(HelmNameTextBox.Text, MouseKeyCombo));

            HelmBindingSource.ResetBindings(false);

            MouseKeyApplicationHook.KeyDown -= MouseKeyHookOnKeyDown;
            MouseKeyApplicationHook.KeyUp -= MouseKeyHookOnKeyUp;
            MouseKeyApplicationHook.KeyDown -= MouseKeyHookOnKeyDown;
            MouseKeyApplicationHook.KeyUp -= MouseKeyHookOnKeyUp;

            MouseKeyApplicationHook.Dispose();

            HelmNameTextBox.Text = string.Empty;
            HelmAddButton.Enabled = true;
        }

        private void MouseKeyHookOnMouseUp(object sender, MouseEventArgs e)
        {
            MouseKeyBindings.Bindings.Add(new MouseKeyBinding(HelmNameTextBox.Text, MouseKeyCombo));

            HelmBindingSource.ResetBindings(false);

            MouseKeyApplicationHook.KeyDown -= MouseKeyHookOnKeyDown;
            MouseKeyApplicationHook.KeyUp -= MouseKeyHookOnKeyUp;
            MouseKeyApplicationHook.KeyDown -= MouseKeyHookOnKeyDown;
            MouseKeyApplicationHook.KeyUp -= MouseKeyHookOnKeyUp;

            MouseKeyApplicationHook.Dispose();

            HelmNameTextBox.Text = string.Empty;
            HelmAddButton.Enabled = true;
        }


        private void MouseKeyHookOnMouseDown(object sender, MouseEventArgs e)
        {
            MouseKeyCombo.Add(e.Button.ToDisplayName());
        }

        private void MouseKeyHookOnKeyDown(object sender, KeyEventArgs e)
        {
            e.SuppressKeyPress = true;

            MouseKeyCombo.Add(e.KeyCode.ToDisplayName());
        }

        private void HelmNameTextBoxClick(object sender, EventArgs e)
        {
            HelmNameTextBox.BackColor = Color.Empty;
        }

        private void HelmRemoveButtonClick(object sender, EventArgs e)
        {
            var helmBinding = (MouseKeyBinding) HelmBindingsListBox.SelectedItem;
            if (helmBinding == null)
                return;

            MouseKeyBindings.Bindings.Remove(helmBinding);
            HelmBindingSource.ResetBindings(false);
        }

        private async void LobbySayButtonClick(object sender, EventArgs e)
        {
            await LobbyMessageSynchronizer.Broadcast(LobbySayTextBox.Text).ConfigureAwait(false);

            LobbySayTextBox.Text = string.Empty;
        }

        private void WingBindingsComboBoxIndexChanged(object sender, EventArgs e)
        {
            var exchangeBinding = (MouseKeyBindingExchange) WingBindingsComboBox.SelectedItem;
            if (exchangeBinding == null)
                return;

            WingBindingsListBox.Items.Clear();
            WingBindingsListBox.DisplayMember = "Name";
            WingBindingsListBox.ValueMember = "Name";
            WingBindingsListBox.Items.AddRange(exchangeBinding.Names.Select(name => (object)name).ToArray());
        }
    }
}