private ConnectionStatusChangeResult Disable(string connectionKey, bool updateState)
        {
            var changeResult = new ConnectionStatusChangeResult();

            lock (lockObject)
            {
                if (connections.ContainsKey(connectionKey))
                {
                    Tuple <ConnectionStatus, CancellationTokenSource> previousConnectionValue = connections[connectionKey];
                    connections[connectionKey]             = new Tuple <ConnectionStatus, CancellationTokenSource>(ConnectionStatus.Disabled, null);
                    changeResult.IsConnectionStatusChanged = true;

                    if (updateState)
                    {
                        Tuple <ConnectionStatus, ConnectionStatus> beforeAndAfterState = UpdateDeviceClientState();
                        changeResult.IsClientStatusChanged = beforeAndAfterState.Item1 != beforeAndAfterState.Item2;
                        changeResult.ClientStatus          = beforeAndAfterState.Item2;
                    }

                    if (previousConnectionValue.Item2 != null)
                    {
                        previousConnectionValue.Item2.Cancel();
                    }
                }
            }

            return(changeResult);
        }
        public ConnectionStatusChangeResult ChangeTo(string connectionKey, ConnectionStatus toState, ConnectionStatus?fromState = null, CancellationTokenSource cancellationTokenSource = null)
        {
            if (toState == ConnectionStatus.Disabled)
            {
                return(Disable(connectionKey, true));
            }

            Tuple <ConnectionStatus, CancellationTokenSource> connectionValue;

            if (toState == ConnectionStatus.Disconnected_Retrying)
            {
                if (cancellationTokenSource == null)
                {
                    throw new ArgumentNullException($"{nameof(cancellationTokenSource)} should be provided for retrying state.");
                }
                connectionValue = Tuple.Create(toState, cancellationTokenSource);
            }
            else
            {
                connectionValue = new Tuple <ConnectionStatus, CancellationTokenSource>(toState, null);
            }

            var changeResult = new ConnectionStatusChangeResult
            {
                ClientStatus = this.status
            };

            lock (lockObject)
            {
                if (connections.ContainsKey(connectionKey))
                {
                    ConnectionStatus existingConnectionState = connections[connectionKey].Item1;
                    if (((existingConnectionState != ConnectionStatus.Disconnected && existingConnectionState != ConnectionStatus.Disabled) || toState == ConnectionStatus.Connected) &&
                        (!fromState.HasValue || fromState.Value == existingConnectionState))
                    {
                        connections[connectionKey]             = connectionValue;
                        changeResult.IsConnectionStatusChanged = true;
                    }
                }
                else
                {
                    if (toState == ConnectionStatus.Connected && (!fromState.HasValue || fromState.Value == ConnectionStatus.Disconnected))
                    {
                        connections.Add(connectionKey, connectionValue);
                        changeResult.IsConnectionStatusChanged = true;
                    }
                }

                if (changeResult.IsConnectionStatusChanged)
                {
                    Tuple <ConnectionStatus, ConnectionStatus> beforeAndAfterState = UpdateDeviceClientState();
                    changeResult.IsClientStatusChanged = beforeAndAfterState.Item1 != beforeAndAfterState.Item2;
                    changeResult.ClientStatus          = beforeAndAfterState.Item2;
                }
            }

            return(changeResult);
        }
        public ConnectionStatusChangeResult ChangeTo(ConnectionType connectionType, ConnectionStatus toState, ConnectionStatus?fromState = null)
        {
            if (toState == ConnectionStatus.Disabled)
            {
                return(Disable(connectionType, true));
            }

            var changeResult = new ConnectionStatusChangeResult
            {
                ClientStatus = this.status
            };

            lock (lockObject)
            {
                if (connections.ContainsKey(connectionType))
                {
                    ConnectionStatus        existingConnectionState         = connections[connectionType].Item1;
                    CancellationTokenSource existingCancellationTokenSource = connections[connectionType].Item2;
                    if (((existingConnectionState != ConnectionStatus.Disconnected && existingConnectionState != ConnectionStatus.Disabled) || toState == ConnectionStatus.Connected) &&
                        (!fromState.HasValue || fromState.Value == existingConnectionState))
                    {
                        CancellationTokenSource changeStatusCancellationTokenSource = null;
                        if (toState == ConnectionStatus.Disconnected_Retrying)
                        {
                            changeStatusCancellationTokenSource = new CancellationTokenSource();
                        }
                        connections[connectionType] = new Tuple <ConnectionStatus, CancellationTokenSource>(toState, changeStatusCancellationTokenSource);
                        changeResult.StatusChangeCancellationTokenSource = changeStatusCancellationTokenSource;
                        changeResult.IsConnectionStatusChanged           = true;

                        // When status is changed from Disconnected_Retrying, dispose cancellation token as it is no longer valid.
                        if (existingConnectionState == ConnectionStatus.Disconnected_Retrying && existingCancellationTokenSource != null)
                        {
                            existingCancellationTokenSource.Dispose();
                        }
                    }
                }
                else
                {
                    if (toState == ConnectionStatus.Connected && (!fromState.HasValue || fromState.Value == ConnectionStatus.Disconnected))
                    {
                        connections.Add(connectionType, new Tuple <ConnectionStatus, CancellationTokenSource>(toState, null));
                        changeResult.IsConnectionStatusChanged = true;
                    }
                }

                if (changeResult.IsConnectionStatusChanged)
                {
                    Tuple <ConnectionStatus, ConnectionStatus> beforeAndAfterState = UpdateDeviceClientState();
                    changeResult.IsClientStatusChanged = beforeAndAfterState.Item1 != beforeAndAfterState.Item2;
                    changeResult.ClientStatus          = beforeAndAfterState.Item2;
                }
            }

            return(changeResult);
        }