AdvancedCircuitController<TResult>
using Polly.Utilities;
using System;
namespace Polly.CircuitBreaker
{
    internal class AdvancedCircuitController<TResult> : CircuitStateController<TResult>
    {
        private const short NumberOfWindows = 10;
        internal static readonly long ResolutionOfCircuitTimer = TimeSpan.FromMilliseconds(20).Ticks;
        private readonly IHealthMetrics _metrics;
        private readonly double _failureThreshold;
        private readonly int _minimumThroughput;
        public AdvancedCircuitController(double failureThreshold, TimeSpan samplingDuration, int minimumThroughput, TimeSpan durationOfBreak, Action<DelegateResult<TResult>, CircuitState, TimeSpan, Context> onBreak, Action<Context> onReset, Action onHalfOpen)
            : base(durationOfBreak, onBreak, onReset, onHalfOpen)
        {
            object metrics;
            if (samplingDuration.Ticks >= ResolutionOfCircuitTimer * 10) {
                IHealthMetrics healthMetrics = new RollingHealthMetrics(samplingDuration, 10);
                metrics = healthMetrics;
            } else {
                IHealthMetrics healthMetrics = new SingleHealthMetrics(samplingDuration);
                metrics = healthMetrics;
            }
            _metrics = (IHealthMetrics)metrics;
            _failureThreshold = failureThreshold;
            _minimumThroughput = minimumThroughput;
        }
        public override void OnCircuitReset(Context context)
        {
            using (TimedLock.Lock(Lock)) {
                _metrics?.Reset_NeedsLock();
                ResetInternal_NeedsLock(context);
            }
        }
        public override void OnActionSuccess(Context context)
        {
            using (TimedLock.Lock(Lock)) {
                CircuitState internalCircuitState = InternalCircuitState;
                switch ((int)internalCircuitState) {
                case 2:
                    OnCircuitReset(context);
                    break;
                default:
                    throw new InvalidOperationException("Unhandled CircuitState.");
                case 0:
                case 1:
                case 3:
                    break;
                }
                _metrics.IncrementSuccess_NeedsLock();
            }
        }
        public override void OnActionFailure(DelegateResult<TResult> outcome, Context context)
        {
            using (TimedLock.Lock(Lock)) {
                LastOutcome = outcome;
                CircuitState internalCircuitState = InternalCircuitState;
                switch ((int)internalCircuitState) {
                case 2:
                    Break_NeedsLock(context);
                    break;
                case 0: {
                    _metrics.IncrementFailure_NeedsLock();
                    HealthCount healthCount_NeedsLock = _metrics.GetHealthCount_NeedsLock();
                    int total = healthCount_NeedsLock.Total;
                    if (total >= _minimumThroughput && (double)healthCount_NeedsLock.Failures / (double)total >= _failureThreshold)
                        Break_NeedsLock(context);
                    break;
                }
                case 1:
                case 3:
                    _metrics.IncrementFailure_NeedsLock();
                    break;
                default:
                    throw new InvalidOperationException("Unhandled CircuitState.");
                }
            }
        }
    }
}