/// <summary>
 /// Creates a new instance of the <see cref="AuthorizationRule"/> class
 /// with the specified permissions, target and exception sets.
 /// </summary>
 ///
 /// <param name="permissions">
 /// The permissions granted.
 /// </param>
 ///
 /// <param name="targetSets">
 /// The set or sets of things to which this rule applies.
 /// </param>
 ///
 /// <param name="exceptionSets">
 /// The set or sets of things to which this rule does not
 /// apply even if contained in a set defined by
 /// <paramref name="targetSets"/>.
 /// </param>
 ///
 /// <exception cref="ArgumentException">
 /// The <paramref name="permissions"/> parameter is
 /// <see cref="ThingPermissions.None"/>.
 /// </exception>
 ///
 public AuthorizationRule(
     ThingPermissions permissions,
     IList <AuthorizationSetDefinition> targetSets    = null,
     IList <AuthorizationSetDefinition> exceptionSets = null)
     : this(null, null, permissions, targetSets, exceptionSets, false, AuthorizationRuleDisplayFlags.None)
 {
 }
        internal void ParseXml(XPathNavigator navigator)
        {
            TypeId = new Guid(navigator.SelectSingleNode(
                                  "thing-type-id").Value);

            XPathNavigator onlinePermissions
                = navigator.SelectSingleNode("online-access-permissions");

            OnlineAccessPermissions = ThingPermissions.None;

            if (onlinePermissions != null)
            {
                XPathNodeIterator nodes
                    = onlinePermissions.Select("permission");
                try
                {
                    foreach (XPathNavigator navPerms in nodes)
                    {
                        OnlineAccessPermissions
                            |= (ThingPermissions)Enum.Parse(
                                   typeof(ThingPermissions),
                                   navPerms.Value);
                    }
                }
                catch (ArgumentException)
                {
                    OnlineAccessPermissions
                        = ThingPermissions.None;
                }
            }

            XPathNavigator offlinePermissions
                = navigator.SelectSingleNode("offline-access-permissions");

            OfflineAccessPermissions = ThingPermissions.None;

            if (offlinePermissions != null)
            {
                XPathNodeIterator nodes
                    = offlinePermissions.Select("permission");
                try
                {
                    foreach (XPathNavigator navPerms in nodes)
                    {
                        OfflineAccessPermissions
                            |= (ThingPermissions)Enum.Parse(
                                   typeof(ThingPermissions),
                                   navPerms.Value);
                    }
                }
                catch (ArgumentException)
                {
                    OfflineAccessPermissions
                        = ThingPermissions.None;
                }
            }
        }
        /// <summary>
        /// Creates a new instance of the <see cref="AuthorizationRule"/> class
        /// with the specified name, reason, permissions, target, exception sets,
        /// optional and display flags.
        /// </summary>
        ///
        /// <param name="name">
        /// The name uniquely identifying this rule in a set
        /// </param>
        ///
        /// <param name="reason">
        /// The reason why an application wants this access
        /// </param>
        ///
        /// <param name="permissions">
        /// The permissions granted.
        /// </param>
        ///
        /// <param name="targetSets">
        /// The set or sets of things to which this rule applies.
        /// </param>
        ///
        /// <param name="exceptionSets">
        /// The set or sets of things to which this rule does not
        /// apply even if contained in a set defined by
        /// <paramref name="targetSets"/>.
        /// </param>
        ///
        /// <param name="isOptional">
        /// Flag indicating whether or not this rule is optional
        /// </param>
        ///
        /// <param name="displayFlags">
        /// Flags controlling how to display this rule
        /// </param>
        ///
        /// <exception cref="ArgumentException">
        /// The <paramref name="permissions"/> parameter is
        /// <see cref="ThingPermissions.None"/>.
        /// </exception>
        ///
        public AuthorizationRule(
            string name,
            string reason,
            ThingPermissions permissions,
            IList <AuthorizationSetDefinition> targetSets,
            IList <AuthorizationSetDefinition> exceptionSets,
            bool isOptional,
            AuthorizationRuleDisplayFlags displayFlags)
        {
            Name         = name;
            IsOptional   = isOptional;
            DisplayFlags = displayFlags;

            if (!string.IsNullOrEmpty(reason))
            {
                CultureSpecificReasons.DefaultValue = reason;
            }

            if (permissions == ThingPermissions.None)
            {
                throw new ArgumentException(Resources.AuthorizationRuleBadPermissions, nameof(permissions));
            }

            Permissions = permissions;

            if (targetSets != null)
            {
                TargetSets =
                    new ReadOnlyCollection <AuthorizationSetDefinition>(
                        targetSets);
            }
            else
            {
                TargetSets =
                    new ReadOnlyCollection <AuthorizationSetDefinition>(
                        new AuthorizationSetDefinition[0]);
            }

            if (exceptionSets != null)
            {
                ExceptionSets =
                    new ReadOnlyCollection <AuthorizationSetDefinition>(
                        exceptionSets);
            }
            else
            {
                ExceptionSets =
                    new ReadOnlyCollection <AuthorizationSetDefinition>(
                        new AuthorizationSetDefinition[0]);
            }
        }
        internal static AuthorizationRule CreateRule(
            XPathNavigator ruleNav,
            bool onlyAllowTypeIdSets)
        {
            bool isOptional = false;

            string isOptionalStr
                = ruleNav.GetAttribute("is-optional", string.Empty);

            if (!string.IsNullOrEmpty(isOptionalStr))
            {
                try
                {
                    isOptional = XmlConvert.ToBoolean(isOptionalStr);
                }
                catch (FormatException)
                {
                }
            }

            string ruleName = ruleNav.GetAttribute("name", string.Empty);

            // <displayflags>
            AuthorizationRuleDisplayFlags displayFlags = AuthorizationRuleDisplayFlags.None;
            XPathNavigator displayFlagsNav             = ruleNav.SelectSingleNode("display-flags");

            if (displayFlagsNav != null)
            {
                try
                {
                    uint flags = XmlConvert.ToUInt32(displayFlagsNav.Value);
                    displayFlags = (AuthorizationRuleDisplayFlags)flags;
                }
                catch (FormatException)
                {
                }
                catch (OverflowException)
                {
                }
            }

            ThingPermissions permissions
                = ThingPermissions.None;
            XPathNodeIterator permissionsIterator =
                ruleNav.Select("permission");

            foreach (XPathNavigator permissionNav in permissionsIterator)
            {
                permissions |=
                    (ThingPermissions)Enum.Parse(
                        typeof(ThingPermissions),
                        permissionNav.Value);
            }

            List <AuthorizationSetDefinition> targetSets =
                GetSets(ruleNav, "target-set");

            List <AuthorizationSetDefinition> exceptionSets =
                GetSets(ruleNav, "exception-set");

            // only do this if only type ID sets are allowed
            //                      AND
            // we have either some target set or exception set data
            // if we enter the if block w/o any target or exception set data to
            // begin with, then we'll incorrectly return <b>null</b> when the XML
            // specified that permissions were allowed on all record data.
            if (onlyAllowTypeIdSets &&
                (targetSets != null || exceptionSets != null))
            {
                if (targetSets != null)
                {
                    for (int i = targetSets.Count - 1; i >= 0; --i)
                    {
                        if (!(targetSets[i] is TypeIdSetDefinition))
                        {
                            targetSets.RemoveAt(i);
                        }
                    }
                }

                if (exceptionSets != null)
                {
                    for (int i = exceptionSets.Count - 1; i >= 0; --i)
                    {
                        if (!(exceptionSets[i] is TypeIdSetDefinition))
                        {
                            exceptionSets.RemoveAt(i);
                        }
                    }
                }

                if ((targetSets == null || targetSets.Count == 0) &&
                    (exceptionSets == null || exceptionSets.Count == 0))
                {
                    return(null);
                }
            }

            AuthorizationRule rule = new AuthorizationRule(
                ruleName,
                null,
                permissions,
                targetSets,
                exceptionSets,
                isOptional,
                displayFlags);

            // <reason>
            // Do this after create the rule so that the CultureSpecificReasons dictionary is available.
            rule.CultureSpecificReasons.PopulateFromXml(ruleNav, "reason");

            return(rule);
        }