private void ConnectionTimer_Tick(object sender, EventArgs e)
 {
     if (mConnectionHeartbeats.Count > 0)
     {
         TimeSpan span = DateTime.Now - mConnectionHeartbeats.Last();
         if (span.TotalSeconds < 15)
         {
             if (!mReceivedInitialHandshake)
             {
                 SimConnectionStateChanged(this, new ClientEventArgs <bool>(false));
                 EnableConnectButton?.Invoke(this, new ClientEventArgs <bool>(false));
                 SendMessage(new XplaneConnect
                 {
                     Type      = XplaneConnect.MessageType.PluginVersion,
                     Timestamp = DateTime.Now
                 }.ToJSON());
                 SendMessage(new XplaneConnect
                 {
                     Type      = XplaneConnect.MessageType.PluginHash,
                     Timestamp = DateTime.Now
                 }.ToJSON());
             }
             else
             {
                 mXplaneConnected = true;
                 SimConnectionStateChanged(this, new ClientEventArgs <bool>(true));
                 if (mValidCsl && !mInvalidPluginVersionShown)
                 {
                     EnableConnectButton?.Invoke(this, new ClientEventArgs <bool>(true));
                 }
             }
             mXplaneConnected = true;
             mConnectionHeartbeats.RemoveAt(0);
         }
         else
         {
             mXplaneConnected          = false;
             mReceivedInitialHandshake = false;
             SimConnectionStateChanged(this, new ClientEventArgs <bool>(false));
             EnableConnectButton?.Invoke(this, new ClientEventArgs <bool>(false));
         }
     }
     else
     {
         mXplaneConnected          = false;
         mReceivedInitialHandshake = false;
         SimConnectionStateChanged(this, new ClientEventArgs <bool>(false));
         EnableConnectButton?.Invoke(this, new ClientEventArgs <bool>(false));
     }
 }
        private void DealerSocket_ReceiveReady(object sender, NetMQSocketEventArgs e)
        {
            string command = e.Socket.ReceiveFrameString();

            if (!string.IsNullOrEmpty(command))
            {
                try
                {
                    var     json = JsonConvert.DeserializeObject <XplaneConnect>(command);
                    dynamic data = json.Data;
                    switch (json.Type)
                    {
                    case XplaneConnect.MessageType.PluginHash:
                        string hash = data.Hash;
                        if (!string.IsNullOrEmpty(hash))
                        {
                            mFsdManager.ClientProperties.PluginHash = hash;
                        }
                        break;

                    case XplaneConnect.MessageType.RequestAtis:
                        string callsign = data.Callsign;
                        if (!string.IsNullOrEmpty(callsign))
                        {
                            RequestControllerAtisSent?.Invoke(this, new RequestControllerAtisEventArgs(callsign));
                        }
                        break;

                    case XplaneConnect.MessageType.PluginVersion:
                        mReceivedInitialHandshake = true;
                        int pluginVersion = (int)data.Version;
                        if (pluginVersion != MIN_PLUGIN_VERSION)
                        {
                            EnableConnectButton?.Invoke(this, new ClientEventArgs <bool>(false));
                            if (!mInvalidPluginVersionShown)
                            {
                                NotificationPosted?.Invoke(this, new NotificationPostedEventArgs(NotificationType.Error, "Error: Incorrect xPilot Plugin Version. You are using an out of date xPilot plugin. Please close X-Plane and reinstall xPilot."));
                                PlaySoundRequested?.Invoke(this, new PlaySoundEventArgs(SoundEvent.Error));
                                mInvalidPluginVersionShown = true;
                            }
                        }
                        break;

                    case XplaneConnect.MessageType.SocketMessage:
                    {
                        string msg = data.Message;
                        if (!string.IsNullOrEmpty(msg))
                        {
                            RaiseSocketMessageReceived?.Invoke(this, new ClientEventArgs <string>(msg));
                        }
                    }
                    break;

                    case XplaneConnect.MessageType.PrivateMessageSent:
                    {
                        string msg = data.Message;
                        string to  = data.To;
                        if (mFsdManager.IsConnected)
                        {
                            PrivateMessageSent?.Invoke(this, new PrivateMessageSentEventArgs(mFsdManager.OurCallsign, to, msg));
                        }
                    }
                    break;

                    case XplaneConnect.MessageType.ValidateCslPaths:
                        mValidCsl = (bool)data.Result;
                        if (data.Result == false)
                        {
                            EnableConnectButton?.Invoke(this, new ClientEventArgs <bool>(false));
                            NotificationPosted?.Invoke(this, new NotificationPostedEventArgs(NotificationType.Error, "Error: No valid CSL paths are configured or enabled, or you have no CSL models installed. Please verify the CSL configuration in X-Plane (Plugins > xPilot > Preferences). If you need assistance configuring your CSL paths, see the \"CSL Model Configuration\" section in the xPilot Documentation (http://docs.xpilot-project.org). Restart X-Plane and xPilot after you have properly configured your CSL models."));
                            PlaySoundRequested?.Invoke(this, new PlaySoundEventArgs(SoundEvent.Error));
                        }
                        break;

                    case XplaneConnect.MessageType.ForceDisconnect:
                        string reason = data.Reason;
                        NotificationPosted?.Invoke(this, new NotificationPostedEventArgs(NotificationType.Error, reason));
                        PlaySoundRequested?.Invoke(this, new PlaySoundEventArgs(SoundEvent.Error));
                        mFsdManager.Disconnect(new DisconnectInfo
                        {
                            Type = DisconnectType.Intentional
                        });
                        break;
                    }
                }
                catch (JsonException ex)
                {
                    NotificationPosted?.Invoke(this, new NotificationPostedEventArgs(NotificationType.Error, "Error deserializing JSON object: " + ex.Message));
                }
            }
        }