/// <summary>
 /// Sets the color of each slot based on its rule. Slots that don't inherit must have a color already.
 /// If this completes without error, then the theme is ready to use. (All slots will have a color.)
 /// setSlot() can be called before this, but this must be called before getThemeAs*().
 /// Does not override colors of rules where isCustomized is true (i.e. doesn't override existing customizations).
 /// </summary>
 /// <param name="slotRules"></param>
 /// <param name="isInverted"></param>
 public static void InsureSlots(IThemeRules slotRules, Boolean isInverted)
 {
     // Get all the "root" rules, the ones which don't inherit. Then "set" them to trigger updating dependent slots.
     foreach (var ruleName in slotRules)
     {
         IThemeSlotRule rule = slotRules[ruleName];
         if (rule.inherits == null && String.IsNullOrEmpty(rule.value))
         {
             if (rule.color == null)
             {
                 throw new InvalidOperationException("A color slot rule that does not inherit must provide its own color.");
             }
             ThemeGenerator.SetSlotInternal(rule, rule.color, isInverted, false, false);
         }
     }
 }
        /// <summary>
        ///
        /// </summary>
        /// <param name="rule"></param>
        /// <param name="color"></param>
        /// <param name="isInverted"></param>
        /// <param name="isCustomization"></param>
        /// <param name="overwriteCustomColor"></param>
        public static void SetSlot(IThemeSlotRule rule, IColor color, Boolean isInverted = false, Boolean isCustomization = false, Boolean overwriteCustomColor = true)
        {
            if (rule.color == null && String.IsNullOrEmpty(rule.value))
            {
                // not a color rule
                return;
            }

            if (overwriteCustomColor)
            {
                IColor colorAsIColor = color;
                if (colorAsIColor == null)
                {
                    throw new ArgumentNullException(nameof(color), "Color is invalid in setSlot(): " + color.ToString());
                }

                ThemeGenerator.SetSlotInternal(rule, colorAsIColor, isInverted, isCustomization, overwriteCustomColor);
            }
            else if (rule.color != null)
            {
                ThemeGenerator.SetSlotInternal(rule, rule.color, isInverted, isCustomization, overwriteCustomColor);
            }
        }
        /// <summary>
        /// Sets the given slot's color to the appropriate color, shading it if necessary.
        /// Then, iterates through all other rules(that are this rule's dependents) to update them accordingly.
        /// isCustomization= true means it's a user provided color, set it to that raw color
        /// isCustomization= false means the rule it's inheriting from changed, so updated using asShade
        /// </summary>
        /// <param name="rule"></param>
        /// <param name="color"></param>
        /// <param name="isInverted"></param>
        /// <param name="isCustomization"></param>
        /// <param name="overwriteCustomColor"></param>
        private static void SetSlotInternal(IThemeSlotRule rule, IColor color, Boolean isInverted, Boolean isCustomization, Boolean overwriteCustomColor = true)
        {
            //if (rule.color == null && String.IsNullOrEmpty(rule.value))
            //{
            //    // not a color rule
            //    return;
            //}

            if (overwriteCustomColor || rule.color == null || !rule.isCustomized || rule.inherits == null)
            {
                // set the rule's color under these conditions
                if ((overwriteCustomColor || !rule.isCustomized) && !isCustomization && rule.inherits != null && Shades.IsValidShade(rule.asShade))
                {
                    // it's inheriting by shade
                    if (rule.isBackgroundShade)
                    {
                        rule.color = Shades.GetBackgroundShade(color, rule.asShade, isInverted);
                    }
                    else
                    {
                        rule.color = Shades.GetShade(color, rule.asShade, isInverted);
                    }
                    rule.isCustomized = false;
                }
                else
                {
                    rule.color        = color;
                    rule.isCustomized = true;
                }

                // then update dependent colors
                foreach (var ruleToUpdate in rule.dependentRules)
                {
                    ThemeGenerator.SetSlotInternal(ruleToUpdate, rule.color, isInverted, false, overwriteCustomColor);
                }
            }
        }