public RulesetOverlayConfigurationChangeMessage(Ruleset ruleset, RulesetOverlayConfiguration newConfiguration, RulesetOverlayConfiguration previousConfiguration)
        {
            Ruleset = ruleset;
            OverlayConfiguration = newConfiguration;

            CalculateSettingChanges(newConfiguration, previousConfiguration);
        }
        private void CalculateSettingChanges(RulesetOverlayConfiguration newConfiguration, RulesetOverlayConfiguration previousConfiguration)
        {
            if (newConfiguration.UseCompactLayout != previousConfiguration?.UseCompactLayout)
            {
                ChangedSettings.Add(RulesetOverlayConfigurationChange.UseCompactLayout);
            }

            if (newConfiguration.StatsDisplayType != previousConfiguration?.StatsDisplayType)
            {
                ChangedSettings.Add(RulesetOverlayConfigurationChange.StatsDisplayType);
            }

            if (newConfiguration.ShowStatusPanelScores != previousConfiguration?.ShowStatusPanelScores)
            {
                ChangedSettings.Add(RulesetOverlayConfigurationChange.ShowStatusPanelScores);
            }
        }
        public async Task SeedDefaultRuleset()
        {
            _logger.LogInformation($"Seeding Default Ruleset...");

            var stopWatchSetup             = new Stopwatch();
            var stopWatchCollections       = new Stopwatch();
            var stopWatchOverlay           = new Stopwatch();
            var stopWatchActionRules       = new Stopwatch();
            var stopWatchItemRules         = new Stopwatch();
            var stopWatchItemCategoryRules = new Stopwatch();
            var stopWatchFacilityRules     = new Stopwatch();
            var stopWatchFinalize          = new Stopwatch();

            var stopWatchTotal = Stopwatch.StartNew();

            stopWatchSetup.Start();


            using var factory = _dbContextHelper.GetFactory();
            var dbContext = factory.GetDbContext();

            var defaultRulesetId = _defaultRulesetId;

            var storeRuleset = await dbContext.Rulesets.FirstOrDefaultAsync(r => r.Id == defaultRulesetId);

            bool rulesetExistsInDb = false;

            RulesetOverlayConfiguration storeOverlayConfiguration = null;

            var storeActionRules       = new List <RulesetActionRule>();
            var storeItemCategoryRules = new List <RulesetItemCategoryRule>();
            var storeItemRules         = new List <RulesetItemRule>();
            var storeFacilityRules     = new List <RulesetFacilityRule>();

            if (storeRuleset != null)
            {
                stopWatchCollections.Start();

                var storeRulesetWithCollections = await _rulesetDataService.GetRulesetFromIdAsync(storeRuleset.Id, CancellationToken.None, true, true);

                storeOverlayConfiguration = storeRulesetWithCollections.RulesetOverlayConfiguration;

                storeActionRules       = storeRulesetWithCollections.RulesetActionRules.ToList();
                storeItemCategoryRules = storeRulesetWithCollections.RulesetItemCategoryRules.ToList();
                storeItemRules         = storeRulesetWithCollections.RulesetItemRules.ToList();
                storeFacilityRules     = storeRulesetWithCollections.RulesetFacilityRules.ToList();

                rulesetExistsInDb = true;

                stopWatchCollections.Stop();
            }
            else
            {
                var utcNow     = DateTime.UtcNow;
                var newRuleset = new Ruleset
                {
                    Name        = "Default",
                    DateCreated = utcNow
                };

                storeRuleset = newRuleset;
            }

            storeRuleset.DefaultMatchTitle = "PS2 Scrims";
            storeRuleset.IsDefault         = true;
            storeRuleset.DefaultEndRoundOnFacilityCapture = false;


            // Get all async collection requests together
            var CollectionsTaskList = new List <Task>();

            var allItemCategoryIdsTask = _itemCategoryService.GetItemCategoryIdsAsync();

            CollectionsTaskList.Add(allItemCategoryIdsTask);

            var allWeaponItemCategoryIdsTask = _itemCategoryService.GetWeaponItemCategoryIdsAsync();

            CollectionsTaskList.Add(allWeaponItemCategoryIdsTask);

            var allWeaponItemsTask = _itemService.GetAllWeaponItemsAsync();

            CollectionsTaskList.Add(allWeaponItemsTask);

            await Task.WhenAll(CollectionsTaskList);

            var allItemCategoryIds       = allItemCategoryIdsTask.Result;
            var allWeaponItemCategoryIds = allWeaponItemCategoryIdsTask.Result;
            var allWeaponItems           = allWeaponItemsTask.Result;

            stopWatchSetup.Stop();

            stopWatchOverlay.Start();

            #region Overlay Configuration

            if (storeOverlayConfiguration == null)
            {
                storeOverlayConfiguration = new RulesetOverlayConfiguration()
                {
                    RulesetId             = _defaultRulesetId,
                    UseCompactLayout      = false,
                    StatsDisplayType      = OverlayStatsDisplayType.InfantryScores,
                    ShowStatusPanelScores = null
                };

                dbContext.RulesetOverlayConfigurations.Add(storeOverlayConfiguration);
            }
            else
            {
                storeOverlayConfiguration.UseCompactLayout      = false;
                storeOverlayConfiguration.StatsDisplayType      = OverlayStatsDisplayType.InfantryScores;
                storeOverlayConfiguration.ShowStatusPanelScores = null;

                dbContext.RulesetOverlayConfigurations.Update(storeOverlayConfiguration);
            }

            #endregion Overlay Configuration

            stopWatchOverlay.Stop();

            stopWatchActionRules.Start();

            #region Action rules
            var defaultActionRules = GetDefaultActionRules();
            var createdActionRules = new List <RulesetActionRule>();
            var allActionRules     = new List <RulesetActionRule>();

            var allActionEnumValues = GetScrimActionTypes().Where(a => a != ScrimActionType.None && a != ScrimActionType.Login && a != ScrimActionType.Logout);

            var allActionValues = new List <ScrimActionType>();
            allActionValues.AddRange(allActionEnumValues);
            allActionValues.AddRange(storeActionRules.Select(ar => ar.ScrimActionType).Where(a => !allActionValues.Contains(a)).ToList());

            foreach (var actionType in allActionValues)
            {
                var storeEntity   = storeActionRules?.FirstOrDefault(r => r.ScrimActionType == actionType);
                var defaultEntity = defaultActionRules.FirstOrDefault(r => r.ScrimActionType == actionType);

                var isValidAction = storeEntity == null || allActionEnumValues.Any(enumValue => enumValue == storeEntity.ScrimActionType);

                if (storeEntity == null)
                {
                    if (defaultEntity != null)
                    {
                        defaultEntity.RulesetId = defaultRulesetId;
                        createdActionRules.Add(defaultEntity);
                        allActionRules.Add(defaultEntity);
                    }
                    else
                    {
                        var newEntity = BuildRulesetActionRule(defaultRulesetId, actionType, 0);
                        createdActionRules.Add(newEntity);
                        allActionRules.Add(newEntity);
                    }
                }
                else if (isValidAction)
                {
                    if (defaultEntity != null)
                    {
                        storeEntity.Points = defaultEntity.Points;
                        storeEntity.DeferToItemCategoryRules = defaultEntity.DeferToItemCategoryRules;
                        storeEntity.ScrimActionTypeDomain    = defaultEntity.ScrimActionTypeDomain;
                    }
                    else
                    {
                        storeEntity.Points = 0;
                        storeEntity.ScrimActionTypeDomain = ScrimAction.GetDomainFromActionType(storeEntity.ScrimActionType);
                    }

                    dbContext.RulesetActionRules.Update(storeEntity);
                    allActionRules.Add(storeEntity);
                }
                else
                {
                    dbContext.RulesetActionRules.Remove(storeEntity);
                }
            }

            if (createdActionRules.Any())
            {
                dbContext.RulesetActionRules.AddRange(createdActionRules);
            }
            #endregion Action rules

            stopWatchActionRules.Stop();

            stopWatchItemCategoryRules.Start();

            #region Item Category Rules
            var defaultItemCategoryRules = GetDefaultItemCategoryRules();
            var createdItemCategoryRules = new List <RulesetItemCategoryRule>();

            var allItemCategoryRules = new List <RulesetItemCategoryRule>();

            foreach (var categoryId in allItemCategoryIds)
            {
                var isWeaponItemCategoryId = (allWeaponItemCategoryIds.Contains(categoryId));

                var storeEntity   = storeItemCategoryRules?.FirstOrDefault(r => r.ItemCategoryId == categoryId);
                var defaultEntity = defaultItemCategoryRules.FirstOrDefault(r => r.ItemCategoryId == categoryId);

                if (storeEntity == null)
                {
                    if (defaultEntity != null)
                    {
                        defaultEntity.RulesetId = defaultRulesetId;

                        createdItemCategoryRules.Add(defaultEntity);
                        allItemCategoryRules.Add(defaultEntity);
                    }
                    else if (isWeaponItemCategoryId)
                    {
                        var newEntity = BuildRulesetItemCategoryRule(defaultRulesetId, categoryId, 0);
                        createdItemCategoryRules.Add(newEntity);
                        allItemCategoryRules.Add(newEntity);
                    }
                }
                else
                {
                    if (isWeaponItemCategoryId)
                    {
                        storeEntity.Points           = defaultEntity != null ? defaultEntity.Points : 0;
                        storeEntity.IsBanned         = defaultEntity != null ? defaultEntity.IsBanned : false;
                        storeEntity.DeferToItemRules = defaultEntity != null ? defaultEntity.DeferToItemRules : false;

                        dbContext.RulesetItemCategoryRules.Update(storeEntity);
                        allItemCategoryRules.Add(storeEntity);
                    }
                    else
                    {
                        dbContext.RulesetItemCategoryRules.Remove(storeEntity);
                    }
                }
            }

            if (createdItemCategoryRules.Any())
            {
                dbContext.RulesetItemCategoryRules.AddRange(createdItemCategoryRules);
            }
            #endregion Item Category Rules

            stopWatchItemCategoryRules.Stop();

            stopWatchItemRules.Start();

            #region Item Rules
            var defaultItemRules = GetDefaultItemRules();
            var createdItemRules = new List <RulesetItemRule>();

            var allItemIds = new List <int>(defaultItemRules.Select(r => r.ItemId));
            if (storeItemRules != null)
            {
                allItemIds.AddRange(storeItemRules.Where(r => !allItemIds.Contains(r.ItemId)).Select(r => r.ItemId));
            }

            if (allWeaponItems != null)
            {
                allItemIds.AddRange(allWeaponItems.Where(r => !allItemIds.Contains(r.Id)).Select(r => r.Id));
            }

            var allItemRules = new List <RulesetItemRule>();

            foreach (var itemId in allItemIds)
            {
                var isWeaponItem = (allWeaponItems.Any(r => r.Id == itemId));

                var storeEntity   = storeItemRules?.FirstOrDefault(r => r.ItemId == itemId);
                var defaultEntity = defaultItemRules.FirstOrDefault(r => r.ItemId == itemId);

                var categoryId = allWeaponItems.Where(i => i.Id == itemId).Select(i => i.ItemCategoryId).FirstOrDefault();

                var categoryDefersToItems = false;

                if (categoryId != null)
                {
                    categoryDefersToItems = allItemCategoryRules.Any(r => r.ItemCategoryId == categoryId && r.DeferToItemRules);
                }

                if (storeEntity == null)
                {
                    if (defaultEntity != null)
                    {
                        defaultEntity.RulesetId = defaultRulesetId;

                        createdItemRules.Add(defaultEntity);
                        allItemRules.Add(defaultEntity);
                    }
                    else if (isWeaponItem && categoryDefersToItems)
                    {
                        var defaultPoints = allItemCategoryRules.Where(r => r.ItemCategoryId == categoryId).Select(r => r.Points).FirstOrDefault();

                        var newEntity = BuildRulesetItemRule(defaultRulesetId, itemId, (int)categoryId, defaultPoints, false);

                        createdItemRules.Add(newEntity);
                        allItemRules.Add(newEntity);
                    }
                }
                else
                {
                    if (defaultEntity != null)
                    {
                        if (categoryId != null && categoryId != defaultEntity.ItemCategoryId)
                        {
                            defaultEntity.ItemCategoryId = (int)categoryId;
                        }

                        defaultEntity.RulesetId = defaultRulesetId;

                        storeEntity = defaultEntity;

                        dbContext.RulesetItemRules.Update(storeEntity);
                        allItemRules.Add(storeEntity);
                    }
                    else if (!isWeaponItem || !categoryDefersToItems)
                    {
                        dbContext.RulesetItemRules.Remove(storeEntity);
                    }
                }
            }

            if (createdItemRules.Any())
            {
                dbContext.RulesetItemRules.AddRange(createdItemRules);
            }
            #endregion Item Rules

            stopWatchItemRules.Stop();

            stopWatchFacilityRules.Start();

            #region Facility Rules
            var defaultFacilityRules = GetDefaultFacilityRules();

            var createdFacilityRules = new List <RulesetFacilityRule>();

            var allFacilityRules = new List <RulesetFacilityRule>(storeFacilityRules);
            allFacilityRules.AddRange(defaultFacilityRules.Where(d => !allFacilityRules.Any(a => a.FacilityId == d.FacilityId)));

            foreach (var facilityRule in allFacilityRules)
            {
                var storeEntity   = storeFacilityRules?.FirstOrDefault(r => r.FacilityId == facilityRule.FacilityId);
                var defaultEntity = defaultFacilityRules.FirstOrDefault(r => r.FacilityId == facilityRule.FacilityId);

                if (storeEntity == null)
                {
                    if (defaultEntity != null)
                    {
                        defaultEntity.RulesetId = defaultRulesetId;

                        createdFacilityRules.Add(defaultEntity);
                    }
                }
                else
                {
                    if (defaultEntity == null)
                    {
                        dbContext.RulesetFacilityRules.Remove(storeEntity);
                        allFacilityRules.Remove(storeEntity);
                    }
                }
            }

            if (createdFacilityRules.Any())
            {
                dbContext.RulesetFacilityRules.AddRange(createdFacilityRules);
            }
            #endregion Facility Rules

            stopWatchFacilityRules.Stop();

            stopWatchFinalize.Start();

            storeRuleset.RulesetOverlayConfiguration = storeOverlayConfiguration;

            storeRuleset.RulesetActionRules       = allActionRules;
            storeRuleset.RulesetItemCategoryRules = allItemCategoryRules;
            storeRuleset.RulesetItemRules         = allItemRules;
            storeRuleset.RulesetFacilityRules     = allFacilityRules;

            if (rulesetExistsInDb)
            {
                dbContext.Rulesets.Update(storeRuleset);
            }
            else
            {
                dbContext.Rulesets.Add(storeRuleset);
            }

            await dbContext.SaveChangesAsync();

            stopWatchFinalize.Stop();

            stopWatchTotal.Stop();
            var elapsedMs = stopWatchTotal.ElapsedMilliseconds;

            var totalTime       = $"Finished seeding Default Ruleset (elapsed: {elapsedMs / 1000.0}s)";
            var setupTime       = $"\n\t\t   Setup: {stopWatchSetup.ElapsedMilliseconds / 1000.0}s";
            var collectionsTime = $"\n\t\t\t   Get Collections: {stopWatchCollections.ElapsedMilliseconds / 1000.0}s";
            var overlayTime     = $"\n\t\t\t   Overlay Configuration: {stopWatchOverlay.ElapsedMilliseconds / 1000.0}s";
            var actionsTime     = $"\n\t\t   Action Rules: {stopWatchActionRules.ElapsedMilliseconds / 1000.0}s";
            var itemCatsTime    = $"\n\t\t   Item Category Rules: {stopWatchItemCategoryRules.ElapsedMilliseconds / 1000.0}s";
            var itemsTime       = $"\n\t\t   Item Rules: {stopWatchItemRules.ElapsedMilliseconds / 1000.0}s";
            var facilitiesTime  = $"\n\t\t   Facility Rules: {stopWatchFacilityRules.ElapsedMilliseconds / 1000.0}s";
            var finalizeTime    = $"\n\t\t   Finalize: {stopWatchFinalize.ElapsedMilliseconds / 1000.0}s";

            _logger.LogInformation($"{totalTime}{setupTime}{collectionsTime}{overlayTime}{actionsTime}{itemCatsTime}{itemsTime}{facilitiesTime}{finalizeTime}");
        }