async Task IShellDescriptorManagerEventHandler.Changed(ShellDescriptor descriptor, string tenant)
        {
            // deduce and apply state changes involved
            var shellState = await _stateManager.GetShellStateAsync();
            foreach (var feature in descriptor.Features)
            {
                var featureName = feature.Name;
                var featureState = shellState.Features.SingleOrDefault(f => f.Name == featureName);
                if (featureState == null)
                {
                    featureState = new ShellFeatureState
                    {
                        Name = featureName
                    };
                }
                if (!featureState.IsInstalled)
                {
                    _stateManager.UpdateInstalledState(featureState, ShellFeatureState.State.Rising);
                }
                if (!featureState.IsEnabled)
                {
                    _stateManager.UpdateEnabledState(featureState, ShellFeatureState.State.Rising);
                }
            }
            foreach (var featureState in shellState.Features)
            {
                var featureName = featureState.Name;
                if (descriptor.Features.Any(f => f.Name == featureName))
                {
                    continue;
                }
                if (!featureState.IsDisabled)
                {
                    _stateManager.UpdateEnabledState(featureState, ShellFeatureState.State.Falling);
                }
            }

            FireApplyChangesIfNeeded();
        }
        public void UpdateInstalledState(ShellFeatureState featureState, ShellFeatureState.State value)
        {
            if (Logger.IsEnabled(LogLevel.Debug))
            {
                Logger.LogDebug("Feature {0} InstallState changed from {1} to {2}", featureState.Name, featureState.InstallState, value);
            }

            var previousFeatureState = GetOrCreateFeatureState(featureState.Name);
            if (previousFeatureState.InstallState != featureState.InstallState)
            {
                if (Logger.IsEnabled(LogLevel.Warning))
                {
                    Logger.LogWarning("Feature {0} prior InstallState was {1} when {2} was expected",
                               featureState.Name, previousFeatureState.InstallState, featureState.InstallState);
                }
            }

            previousFeatureState.InstallState = value;
            featureState.InstallState = value;

            UpdateShellState();
        }
 static bool IsRising(ShellFeatureState state)
 {
     return state.InstallState == ShellFeatureState.State.Rising ||
            state.EnableState == ShellFeatureState.State.Rising;
 }
 private static bool FeatureShouldBeLoadedForStateChangeNotifications(ShellFeatureState shellFeatureState)
 {
     return FeatureIsChanging(shellFeatureState) || shellFeatureState.EnableState == ShellFeatureState.State.Up;
 }
 private static bool FeatureIsChanging(ShellFeatureState shellFeatureState)
 {
     if (shellFeatureState.EnableState == ShellFeatureState.State.Rising ||
         shellFeatureState.EnableState == ShellFeatureState.State.Falling)
     {
         return true;
     }
     if (shellFeatureState.InstallState == ShellFeatureState.State.Rising ||
         shellFeatureState.InstallState == ShellFeatureState.State.Falling)
     {
         return true;
     }
     return false;
 }
        private ShellFeatureState GetOrCreateFeatureState(string name)
        {
            var featureState = GetShellStateAsync().Result.Features.FirstOrDefault(x => x.Name == name);

            if (featureState == null)
            {
                featureState = new ShellFeatureState() { Name = name };
                _shellState.Features.Add(featureState);
            }

            return featureState;
        }