ChainValidationHelper(MonoTlsProvider provider, MonoTlsSettings settings, bool cloneSettings, MonoTlsStream stream, ServerCertValidationCallbackWrapper callbackWrapper)
        {
            if (settings == null)
            {
                settings = MonoTlsSettings.CopyDefaultSettings();
            }
            if (cloneSettings)
            {
                settings = settings.CloneWithValidator(this);
            }
            if (provider == null)
            {
                provider = MonoTlsProviderFactory.GetProvider();
            }

            this.provider        = provider;
            this.settings        = settings;
            this.tlsStream       = stream;
            this.callbackWrapper = callbackWrapper;

            var fallbackToSPM = false;

            if (settings != null)
            {
                if (settings.RemoteCertificateValidationCallback != null)
                {
                    var callback = Private.CallbackHelpers.MonoToPublic(settings.RemoteCertificateValidationCallback);
                    certValidationCallback = new ServerCertValidationCallback(callback);
                }
                certSelectionCallback = Private.CallbackHelpers.MonoToInternal(settings.ClientCertificateSelectionCallback);
                fallbackToSPM         = settings.UseServicePointManagerCallback ?? stream != null;
            }

            if (stream != null)
            {
                this.request = stream.Request;
                this.sender  = request;

                if (certValidationCallback == null)
                {
                    certValidationCallback = request.ServerCertValidationCallback;
                }
                if (certSelectionCallback == null)
                {
                    certSelectionCallback = new LocalCertSelectionCallback(DefaultSelectionCallback);
                }

                if (settings == null)
                {
                    fallbackToSPM = true;
                }
            }

            if (fallbackToSPM && certValidationCallback == null)
            {
                certValidationCallback = ServicePointManager.ServerCertValidationCallback;
            }
        }
        ChainValidationHelper(ChainValidationHelper other, MonoTlsSettings settings, ServerCertValidationCallbackWrapper callbackWrapper = null)
        {
            sender = other.sender;
            certValidationCallback = other.certValidationCallback;
            certSelectionCallback  = other.certSelectionCallback;
            tlsStream = other.tlsStream;
            request   = other.request;

            this.settings        = settings = settings.CloneWithValidator(this);
            this.callbackWrapper = callbackWrapper;
        }
        /*
         * This is a hack which is used in SslStream - see ReferenceSources/SslStream.cs for details.
         */
        internal static ChainValidationHelper CloneWithCallbackWrapper(MonoTlsProvider provider, ref MonoTlsSettings settings, ServerCertValidationCallbackWrapper wrapper)
        {
            var helper = (ChainValidationHelper)settings.CertificateValidator;

            if (helper == null)
            {
                helper = new ChainValidationHelper(provider, settings, true, null, wrapper);
            }
            else
            {
                helper = new ChainValidationHelper(helper, provider, settings, wrapper);
            }
            settings = helper.settings;
            return(helper);
        }
		ChainValidationHelper (MonoTlsProvider provider, MonoTlsSettings settings, bool cloneSettings, MonoTlsStream stream, ServerCertValidationCallbackWrapper callbackWrapper)
		{
			if (settings == null)
				settings = MonoTlsSettings.CopyDefaultSettings ();
			if (cloneSettings)
				settings = settings.CloneWithValidator (this);
			if (provider == null)
				provider = MonoTlsProviderFactory.GetProvider ();

			this.provider = provider;
			this.settings = settings;
			this.tlsStream = stream;
			this.callbackWrapper = callbackWrapper;

			var fallbackToSPM = false;

			if (settings != null) {
				if (settings.RemoteCertificateValidationCallback != null) {
					var callback = Private.CallbackHelpers.MonoToPublic (settings.RemoteCertificateValidationCallback);
					certValidationCallback = new ServerCertValidationCallback (callback);
				}
				certSelectionCallback = Private.CallbackHelpers.MonoToInternal (settings.ClientCertificateSelectionCallback);
				fallbackToSPM = settings.UseServicePointManagerCallback ?? stream != null;
			}

			if (stream != null) {
				this.request = stream.Request;
				this.sender = request;

				if (certValidationCallback == null)
					certValidationCallback = request.ServerCertValidationCallback;
				if (certSelectionCallback == null)
					certSelectionCallback = new LocalCertSelectionCallback (DefaultSelectionCallback);

				if (settings == null)
					fallbackToSPM = true;
			}

			if (fallbackToSPM && certValidationCallback == null)
				certValidationCallback = ServicePointManager.ServerCertValidationCallback;
		}
		ChainValidationHelper (ChainValidationHelper other, MonoTlsProvider provider, MonoTlsSettings settings, ServerCertValidationCallbackWrapper callbackWrapper = null)
		{
			sender = other.sender;
			certValidationCallback = other.certValidationCallback;
			certSelectionCallback = other.certSelectionCallback;
			tlsStream = other.tlsStream;
			request = other.request;

			if (settings == null)
				settings = MonoTlsSettings.DefaultSettings;

			this.provider = provider;
			this.settings = settings.CloneWithValidator (this);
			this.callbackWrapper = callbackWrapper;
		}
		/*
		 * This is a hack which is used in SslStream - see ReferenceSources/SslStream.cs for details.
		 */
		internal static ChainValidationHelper CloneWithCallbackWrapper (MonoTlsProvider provider, ref MonoTlsSettings settings, ServerCertValidationCallbackWrapper wrapper)
		{
			var helper = (ChainValidationHelper)settings.CertificateValidator;
			if (helper == null)
				helper = new ChainValidationHelper (provider, settings, true, null, wrapper);
			else
				helper = new ChainValidationHelper (helper, provider, settings, wrapper);
			settings = helper.settings;
			return helper;
		}
		internal ChainValidationHelper (HttpWebRequest request)
		{
			this.callbackWrapper = callbackWrapper;

			this.request = request;
			this.sender = request;

			if (certValidationCallback == null)
				certValidationCallback = request.ServerCertValidationCallback;
			if (certSelectionCallback == null)
				certSelectionCallback = new LocalCertSelectionCallback (DefaultSelectionCallback);

			if (certValidationCallback == null)
				certValidationCallback = ServicePointManager.ServerCertValidationCallback;
		}