<commit_before>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace HobknobClientNet
{
    internal class FeatureToggleCache : IDisposable
    {
        public event EventHandler<CacheUpdatedArgs> CacheUpdated;
        public event EventHandler<CacheUpdateFailedArgs> CacheUpdateFailed;

        private readonly FeatureToggleProvider _featureToggleProvider;
        private readonly TimeSpan _updateInterval;
        private Timer _timer;
        private Dictionary<string, bool> _cache;

        public FeatureToggleCache(FeatureToggleProvider featureToggleProvider, TimeSpan cacheUpdateInterval)
        {
            _featureToggleProvider = featureToggleProvider;
            _updateInterval = cacheUpdateInterval;

            if (_updateInterval < TimeSpan.FromSeconds(1))
            {
                throw new Exception("Cache update interval must be at least 1 second long");
            }
        }

        public void Initialize()
        {
            UpdateCache();
            _timer = new Timer(UpdateCacheTick, null, _updateInterval, _updateInterval);
        }

        public bool? Get(string applicationName, string featureName, string toggleName = null)
        {
            var toggleSuffix = toggleName != null ? "/" + toggleName : string.Empty;
            var featureToggleKey = string.Format("/v1/toggles/{0}/{1}{2}", applicationName, featureName, toggleSuffix);
            bool value;
            return _cache != null && _cache.TryGetValue(featureToggleKey, out value) ? value : (bool?)null;
        }

        private bool UpdateCache()
        {
            Dictionary<string, bool> featureToggles;
            try
            {
                featureToggles = _featureToggleProvider.Get().ToDictionary(x => x.Key, x => x.Value);
            }
            catch (Exception ex)
            {
                if (CacheUpdateFailed != null)
                {
                    CacheUpdateFailed.Invoke(this, new CacheUpdateFailedArgs(ex));
                }                    
                return false;
            }

            var updates = GetUpdates(_cache, featureToggles);
            _cache = featureToggles;
            if (CacheUpdated != null)
            {
                CacheUpdated.Invoke(this, new CacheUpdatedArgs(updates));
            }
            return true;
        }

        private void UpdateCacheTick(object _)
        {
            UpdateCache();
        }

        private static IEnumerable<CacheUpdate> GetUpdates(Dictionary<string, bool> existingToggles, Dictionary<string, bool> newToggles)
        {
            var existingNotNull = existingToggles ?? new Dictionary<string, bool>();

            var updates = new List<CacheUpdate>();
            foreach (var newToggle in newToggles)<commit_msg>kill .invoke for less code and more git commits<commit_after>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace HobknobClientNet
{
    internal class FeatureToggleCache : IDisposable
    {
        public event EventHandler<CacheUpdatedArgs> CacheUpdated;
        public event EventHandler<CacheUpdateFailedArgs> CacheUpdateFailed;

        private readonly FeatureToggleProvider _featureToggleProvider;
        private readonly TimeSpan _updateInterval;
        private Timer _timer;
        private Dictionary<string, bool> _cache;

        public FeatureToggleCache(FeatureToggleProvider featureToggleProvider, TimeSpan cacheUpdateInterval)
        {
            _featureToggleProvider = featureToggleProvider;
            _updateInterval = cacheUpdateInterval;

            if (_updateInterval < TimeSpan.FromSeconds(1))
            {
                throw new Exception("Cache update interval must be at least 1 second long");
            }
        }

        public void Initialize()
        {
            UpdateCache();
            _timer = new Timer(UpdateCacheTick, null, _updateInterval, _updateInterval);
        }

        public bool? Get(string applicationName, string featureName, string toggleName = null)
        {
            var toggleSuffix = toggleName != null ? "/" + toggleName : string.Empty;
            var featureToggleKey = string.Format("/v1/toggles/{0}/{1}{2}", applicationName, featureName, toggleSuffix);
            bool value;
            return _cache != null && _cache.TryGetValue(featureToggleKey, out value) ? value : (bool?)null;
        }

        private bool UpdateCache()
        {
            Dictionary<string, bool> featureToggles;
            try
            {
                featureToggles = _featureToggleProvider.Get().ToDictionary(x => x.Key, x => x.Value);
            }
            catch (Exception ex)
            {
                if (CacheUpdateFailed != null)
                {
                    CacheUpdateFailed(this, new CacheUpdateFailedArgs(ex));
                }                    
                return false;
            }

            var updates = GetUpdates(_cache, featureToggles);
            _cache = featureToggles;
            if (CacheUpdated != null)
            {
                CacheUpdated(this, new CacheUpdatedArgs(updates));
            }
            return true;
        }

        private void UpdateCacheTick(object _)
        {
            UpdateCache();
        }

        private static IEnumerable<CacheUpdate> GetUpdates(Dictionary<string, bool> existingToggles, Dictionary<string, bool> newToggles)
        {
            var existingNotNull = existingToggles ?? new Dictionary<string, bool>();

            var updates = new List<CacheUpdate>();
            foreach (var newToggle in newToggles)
{'fraction_non_alphanumeric': 0.07677373808683374, 'fraction_numerical': 0.002117896223085069, 'mean_word_length': 2.043501611170784, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2962365', 'n_tokens_mistral': 1359, 'n_tokens_neox': 1314, 'n_words': 341}