/// <summary>
 /// Returns a new instance of ReadPreference with some values changed.
 /// </summary>
 /// <param name="mode">The read preference mode.</param>
 /// <param name="tagSets">The tag sets.</param>
 /// <returns>A new instance of ReadPreference.</returns>
 public ReadPreference With(
     Optional <ReadPreferenceMode> mode       = default(Optional <ReadPreferenceMode>),
     Optional <IEnumerable <TagSet> > tagSets = default(Optional <IEnumerable <TagSet> >))
 {
     return(new ReadPreference(
                mode.WithDefault(_mode),
                Optional.Create(tagSets.WithDefault(_tagSets))));
 }
        private ConnectionSettings ConfigureConnection(ConnectionSettings settings, ClusterKey clusterKey)
        {
            var authenticators = clusterKey.Credentials.Select(c => c.ToAuthenticator());

            return(settings.With(
                       authenticators: Optional.Create(authenticators),
                       maxIdleTime: clusterKey.MaxConnectionIdleTime,
                       maxLifeTime: clusterKey.MaxConnectionLifeTime));
        }
        private ClusterSettings ConfigureCluster(ClusterSettings settings, ClusterKey clusterKey)
        {
            var endPoints = clusterKey.Servers.Select(s => (EndPoint) new DnsEndPoint(s.Host, s.Port));

            return(settings.With(
                       connectionMode: clusterKey.ConnectionMode.ToCore(),
                       endPoints: Optional.Create(endPoints),
                       replicaSetName: clusterKey.ReplicaSetName,
                       postServerSelector: new LatencyLimitingServerSelector(clusterKey.LocalThreshold)));
        }
        // internal methods
        internal SslStreamSettings ToSslStreamSettings()
        {
            var clientCertificates = _clientCertificateCollection != null ? ((IEnumerable)_clientCertificateCollection).Cast <X509Certificate>() : Enumerable.Empty <X509Certificate>();

            return(new SslStreamSettings(
                       checkCertificateRevocation: _checkCertificateRevocation,
                       clientCertificates: Optional.Create(clientCertificates),
                       clientCertificateSelectionCallback: _clientCertificateSelectionCallback,
                       enabledProtocols: _enabledSslProtocols,
                       serverCertificateValidationCallback: _serverCertificateValidationCallback));
        }
        private ClusterSettings ConfigureCluster(ClusterSettings settings, ClusterKey clusterKey)
        {
            var endPoints = clusterKey.Servers.Select(s => EndPointHelper.Parse(s.ToString()));

            return(settings.With(
                       connectionMode: clusterKey.ConnectionMode.ToCore(),
                       endPoints: Optional.Enumerable(endPoints),
                       kmsProviders: Optional.Create(clusterKey.KmsProviders),
                       replicaSetName: clusterKey.ReplicaSetName,
                       maxServerSelectionWaitQueueSize: clusterKey.WaitQueueSize,
                       serverSelectionTimeout: clusterKey.ServerSelectionTimeout,
                       postServerSelector: new LatencyLimitingServerSelector(clusterKey.LocalThreshold),
                       schemaMap: Optional.Create(clusterKey.SchemaMap),
                       scheme: clusterKey.Scheme));
        }
        private SslStreamSettings ConfigureSsl(SslStreamSettings settings, ClusterKey clusterKey)
        {
            if (clusterKey.UseSsl)
            {
                var sslSettings = clusterKey.SslSettings ?? new SslSettings();

                var validationCallback = sslSettings.ServerCertificateValidationCallback;
                if (validationCallback == null && !clusterKey.VerifySslCertificate)
                {
                    validationCallback = AcceptAnySslCertificate;
                }

                return(settings.With(
                           clientCertificates: Optional.Create(sslSettings.ClientCertificates ?? Enumerable.Empty <X509Certificate>()),
                           checkCertificateRevocation: sslSettings.CheckCertificateRevocation,
                           clientCertificateSelectionCallback: sslSettings.ClientCertificateSelectionCallback,
                           enabledProtocols: sslSettings.EnabledSslProtocols,
                           serverCertificateValidationCallback: validationCallback));
            }

            return(settings);
        }
        private ClusterSettings ConfigureCluster(ClusterSettings settings, ClusterKey clusterKey)
        {
#pragma warning disable CS0618 // Type or member is obsolete
            var endPoints            = clusterKey.Servers.Select(s => EndPointHelper.Parse(s.ToString()));
            var connectionModeSwitch = clusterKey.ConnectionModeSwitch;
            Optional <ClusterConnectionMode> connectionMode = connectionModeSwitch == ConnectionModeSwitch.UseConnectionMode ? clusterKey.ConnectionMode.ToCore() : default;
            Optional <bool?> directConnection = connectionModeSwitch == ConnectionModeSwitch.UseDirectConnection ? clusterKey.DirectConnection : default;
            return(settings.With(
                       connectionMode: connectionMode,
                       connectionModeSwitch: connectionModeSwitch,
                       directConnection: directConnection,
                       endPoints: Optional.Enumerable(endPoints),
                       kmsProviders: Optional.Create(clusterKey.KmsProviders),
                       localThreshold: clusterKey.LocalThreshold,
                       replicaSetName: clusterKey.ReplicaSetName,
                       maxServerSelectionWaitQueueSize: clusterKey.WaitQueueSize,
                       serverSelectionTimeout: clusterKey.ServerSelectionTimeout,
                       schemaMap: Optional.Create(clusterKey.SchemaMap),
                       scheme: clusterKey.Scheme));

#pragma warning restore CS0618 // Type or member is obsolete
        }
        /// <summary>
        /// Parses a URL and sets all settings to match the URL.
        /// </summary>
        /// <param name="url">The URL.</param>
        public void Parse(string url)
        {
            var connectionString = new ConnectionString(url);

            _authenticationMechanism           = connectionString.AuthMechanism;
            _authenticationMechanismProperties = connectionString.AuthMechanismProperties.ToDictionary(x => x.Key, x => x.Value, StringComparer.InvariantCultureIgnoreCase);
            _authenticationSource = connectionString.AuthSource;
            switch (connectionString.Connect)
            {
            case ClusterConnectionMode.Direct:
                _connectionMode = Driver.ConnectionMode.Direct;
                break;

            case ClusterConnectionMode.ReplicaSet:
                _connectionMode = Driver.ConnectionMode.ReplicaSet;
                break;

            case ClusterConnectionMode.Sharded:
                _connectionMode = Driver.ConnectionMode.ShardRouter;
                break;

            case ClusterConnectionMode.Standalone:
                _connectionMode = Driver.ConnectionMode.Standalone;
                break;

            default:
                _connectionMode = Driver.ConnectionMode.Automatic;
                break;
            }
            _connectTimeout     = connectionString.ConnectTimeout.GetValueOrDefault(MongoDefaults.ConnectTimeout);
            _databaseName       = connectionString.DatabaseName;
            _fsync              = connectionString.FSync;
            _guidRepresentation = connectionString.UuidRepresentation.GetValueOrDefault(MongoDefaults.GuidRepresentation);
            _ipv6    = connectionString.Ipv6.GetValueOrDefault(false);
            _journal = connectionString.Journal;
            _maxConnectionIdleTime = connectionString.MaxIdleTime.GetValueOrDefault(MongoDefaults.MaxConnectionIdleTime);
            _maxConnectionLifeTime = connectionString.MaxLifeTime.GetValueOrDefault(MongoDefaults.MaxConnectionLifeTime);
            _maxConnectionPoolSize = connectionString.MaxPoolSize.GetValueOrDefault(MongoDefaults.MaxConnectionPoolSize);
            _minConnectionPoolSize = connectionString.MinPoolSize.GetValueOrDefault(MongoDefaults.MinConnectionPoolSize);
            _password = connectionString.Password;
            if (connectionString.ReadPreference != null)
            {
                _readPreference = new ReadPreference(connectionString.ReadPreference.Value);
            }
            if (connectionString.ReadPreferenceTags != null)
            {
                if (_readPreference == null)
                {
                    throw new MongoConfigurationException("ReadPreferenceMode is required when using tag sets.");
                }
                _readPreference = _readPreference.With(tagSets: Optional.Create <IEnumerable <TagSet> >(connectionString.ReadPreferenceTags));
            }

            _replicaSetName = connectionString.ReplicaSet;
            _localThreshold = connectionString.LocalThreshold.GetValueOrDefault(MongoDefaults.LocalThreshold);
            _servers        = connectionString.Hosts.Select(endPoint =>
            {
                DnsEndPoint dnsEndPoint;
                IPEndPoint ipEndPoint;
                if ((dnsEndPoint = endPoint as DnsEndPoint) != null)
                {
                    return(new MongoServerAddress(dnsEndPoint.Host, dnsEndPoint.Port));
                }
                else if ((ipEndPoint = endPoint as IPEndPoint) != null)
                {
                    return(new MongoServerAddress(ipEndPoint.Address.ToString(), ipEndPoint.Port));
                }
                else
                {
                    throw new NotSupportedException("Only DnsEndPoint and IPEndPoints are supported in the connection string.");
                }
            });
            _socketTimeout        = connectionString.SocketTimeout.GetValueOrDefault(MongoDefaults.SocketTimeout);
            _username             = connectionString.Username;
            _useSsl               = connectionString.Ssl.GetValueOrDefault(false);
            _verifySslCertificate = connectionString.SslVerifyCertificate.GetValueOrDefault(true);
            _w = connectionString.W;
            if (connectionString.WaitQueueSize != null)
            {
                _waitQueueSize     = connectionString.WaitQueueSize.Value;
                _waitQueueMultiple = 0.0;
            }
            else if (connectionString.WaitQueueMultiple != null)
            {
                _waitQueueMultiple = connectionString.WaitQueueMultiple.Value;
                _waitQueueSize     = 0;
            }
            _waitQueueTimeout = connectionString.WaitQueueTimeout.GetValueOrDefault(MongoDefaults.WaitQueueTimeout);
            _wTimeout         = connectionString.WTimeout;
        }