|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections;
using System.Diagnostics;
namespace System.Configuration
{
internal sealed class SectionUpdates
{
private readonly Hashtable _groups;
private readonly string _name;
private readonly Hashtable _sections;
private int _cMoved;
private int _cUnretrieved;
private Update _sectionGroupUpdate;
internal SectionUpdates(string name)
{
_name = name;
_groups = new Hashtable();
_sections = new Hashtable();
}
internal bool IsNew { get; set; }
internal bool IsEmpty => (_groups.Count == 0) && (_sections.Count == 0);
// Find the SectionUpdates for a configKey, and create it if it does not exist.
private SectionUpdates FindSectionUpdates(string configKey, bool isGroup)
{
string group;
if (isGroup) group = configKey;
else BaseConfigurationRecord.SplitConfigKey(configKey, out group, out _);
Debug.Assert(string.IsNullOrEmpty(_name), "FindSectionUpdates assumes search is from root record");
SectionUpdates sectionUpdates = this;
if (group.Length != 0)
{
// find the SectionUpdates for the group
string[] groups = group.Split(BaseConfigurationRecord.s_configPathSeparatorParams);
foreach (string groupPart in groups)
{
SectionUpdates sectionUpdatesChild = (SectionUpdates)sectionUpdates._groups[groupPart];
if (sectionUpdatesChild == null)
{
sectionUpdatesChild = new SectionUpdates(groupPart);
sectionUpdates._groups[groupPart] = sectionUpdatesChild;
}
sectionUpdates = sectionUpdatesChild;
}
}
return sectionUpdates;
}
// Recursively check whether this group has all new updates.
// An update is new if all sections are new and all subgroups are new.
internal void CompleteUpdates()
{
bool allSubgroupsAreNew = true;
// call CompleteUpdates() for all children
foreach (SectionUpdates sectionUpdates in _groups.Values)
{
sectionUpdates.CompleteUpdates();
if (!sectionUpdates.IsNew) allSubgroupsAreNew = false;
}
IsNew = allSubgroupsAreNew && (_cMoved == _sections.Count);
}
internal void AddSection(Update update)
{
SectionUpdates sectionUpdates = FindSectionUpdates(update.ConfigKey, false);
sectionUpdates._sections.Add(update.ConfigKey, update);
// Maintain counts.
sectionUpdates._cUnretrieved++;
if (update.Moved) sectionUpdates._cMoved++;
}
internal void AddSectionGroup(Update update)
{
SectionUpdates sectionUpdates = FindSectionUpdates(update.ConfigKey, true);
sectionUpdates._sectionGroupUpdate = update;
}
private Update GetUpdate(string configKey)
{
Update update = (Update)_sections[configKey];
if (update != null)
{
if (update.Retrieved) update = null;
else
{
update.Retrieved = true;
_cUnretrieved--;
if (update.Moved) _cMoved--;
}
}
return update;
}
internal DeclarationUpdate GetSectionGroupUpdate()
{
if ((_sectionGroupUpdate != null) && !_sectionGroupUpdate.Retrieved)
{
_sectionGroupUpdate.Retrieved = true;
return (DeclarationUpdate)_sectionGroupUpdate;
}
return null;
}
internal DefinitionUpdate GetDefinitionUpdate(string configKey)
{
return (DefinitionUpdate)GetUpdate(configKey);
}
internal DeclarationUpdate GetDeclarationUpdate(string configKey)
{
return (DeclarationUpdate)GetUpdate(configKey);
}
internal SectionUpdates GetSectionUpdatesForGroup(string group)
{
return (SectionUpdates)_groups[group];
}
// Return true if this section group or any of its children have unretrieved sections.
internal bool HasUnretrievedSections()
{
if ((_cUnretrieved > 0) || ((_sectionGroupUpdate != null) && !_sectionGroupUpdate.Retrieved)) return true;
foreach (SectionUpdates sectionUpdates in _groups.Values)
if (sectionUpdates.HasUnretrievedSections()) return true;
return false;
}
internal void MarkAsRetrieved()
{
_cUnretrieved = 0;
foreach (SectionUpdates sectionUpdates in _groups.Values) sectionUpdates.MarkAsRetrieved();
if (_sectionGroupUpdate != null) _sectionGroupUpdate.Retrieved = true;
}
internal void MarkGroupAsRetrieved(string groupName)
{
SectionUpdates sectionUpdates = _groups[groupName] as SectionUpdates;
sectionUpdates?.MarkAsRetrieved();
}
internal bool HasNewSectionGroups()
{
foreach (SectionUpdates sectionUpdates in _groups.Values)
if (sectionUpdates.IsNew)
return true;
return false;
}
// Return a sorted list of the names of unretrieved sections in this group.
internal string[] GetUnretrievedSectionNames()
{
if (_cUnretrieved == 0)
return null;
string[] sectionNames = new string[_cUnretrieved];
int i = 0;
foreach (Update update in _sections.Values)
if (!update.Retrieved)
{
sectionNames[i] = update.ConfigKey;
i++;
}
Array.Sort(sectionNames);
return sectionNames;
}
// Return a sorted list of the names of moved and unretrieved sections in this group.
internal string[] GetMovedSectionNames()
{
if (_cMoved == 0)
return null;
string[] sectionNames = new string[_cMoved];
int i = 0;
foreach (Update update in _sections.Values)
if (update.Moved && !update.Retrieved)
{
sectionNames[i] = update.ConfigKey;
i++;
}
Array.Sort(sectionNames);
return sectionNames;
}
// Return a sorted list of the names of groups with unretrieved sections.
internal string[] GetUnretrievedGroupNames()
{
ArrayList unretrievedGroups = new ArrayList();
foreach (DictionaryEntry de in _groups)
{
string group = (string)de.Key;
SectionUpdates sectionUpdates = (SectionUpdates)de.Value;
if (sectionUpdates.HasUnretrievedSections()) unretrievedGroups.Add(group);
}
if (unretrievedGroups.Count == 0)
return null;
string[] groupNames = new string[unretrievedGroups.Count];
unretrievedGroups.CopyTo(groupNames);
Array.Sort(groupNames);
return groupNames;
}
// Return a sorted list of the names of new section groups with unretrieved sections.
internal string[] GetNewGroupNames()
{
ArrayList newsGroups = new ArrayList();
foreach (DictionaryEntry de in _groups)
{
string group = (string)de.Key;
SectionUpdates sectionUpdates = (SectionUpdates)de.Value;
if (sectionUpdates.IsNew && sectionUpdates.HasUnretrievedSections()) newsGroups.Add(group);
}
if (newsGroups.Count == 0)
return null;
string[] groupNames = new string[newsGroups.Count];
newsGroups.CopyTo(groupNames);
Array.Sort(groupNames);
return groupNames;
}
}
}
|