/// <summary>
        /// Renvoie la liste du trigramme des utilisateurs autorisé pour un utilisateur, une action et une entitée donnés.
        /// </summary>
        /// <param name="request">La requête à fournir au moteur prolog : User, Action, Entity doivent être non nulls</param>
        /// <param name="request.User>">Non Null</param>
        /// <param name="request.Target>">Ignoré</param>
        /// <param name="request.Action>">Non Null</param>
        /// <param name="request.Entity>">Non Null</param>
        /// <returns>Un tableau des utilisateurs authorisés</returns>
        public virtual IEnumerable <string> GetAuthorizedTargets(PermissionRequest request)
        {
            SecurityProvider.Trace($"Call to {nameof(GetAuthorizedTargets)}");

            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            try
            {
                AssertIsNotNull(request.User, nameof(request.User));
                AssertIsNotNull(request.Action, nameof(request.Action));
                AssertIsNotNull(request.Entity, nameof(request.Entity));

                var solutions = Solve(DefaultRuleName,
                                      request.MaxSolutionCount ?? int.MaxValue,
                                      request.User.AsPrologConstant(),
                                      TermTarget,
                                      request.Entity.AsPrologConstant(),
                                      request.Action.AsPrologConstant());

                return(solutions
                       .Select(solution => solution.GetTermValue(TermTarget)?.Trim('\'', '"'))
                       .ToList()
                       .OrderBy(e => e)
                       .Distinct());
            }
            catch (Exception ex)
            {
                SecurityProvider.Trace($"   Error: {ex.GetFullMessage()}");
                throw;
            }
        }
        public virtual IEnumerable <string> GetEntityTargetPermissions(PermissionRequest request)
        {
            var solutions = Solve(DefaultRuleName,
                                  request.MaxSolutionCount ?? int.MaxValue,
                                  request.User,
                                  request.Target,
                                  request.Entity,
                                  TermAction);

            return(solutions
                   .Select(s => s.GetTermValue(TermAction)?.Trim('\'', '"'))
                   .Distinct()
                   .Where(action => Actions.Contains(action))
                   .OrderBy(e => e));
        }
        //public virtual void AddFact(string fact)
        //{
        //	SecurityProvider.Trace($"Call to {nameof(AddFact)}");
        //	SecurityProvider.Trace($"   Adding fact: {fact}");

        //	AddFacts(new List<string> { fact });
        //}

        //public virtual void AddFacts(IEnumerable<string> facts)
        //{
        //	SecurityProvider.Trace($"Call to {nameof(AddFacts)}");

        //	if (facts == null)
        //		return;

        //	var addedFacts = facts as string[] ?? facts.ToArray();
        //	SecurityProvider.Trace($"   Adding facts: {String.Join("; ", addedFacts)}");

        //	AddPredicates(addedFacts, _factsFileFullName);
        //}

        //public virtual void RemoveFact(string fact)
        //{
        //	SecurityProvider.Trace($"Call to {nameof(RemoveFact)}");
        //	SecurityProvider.Trace($"   Removing fact: {fact}");

        //	RemoveFacts(new List<string> { fact });
        //}

        //public virtual void RemoveFacts(IEnumerable<string> facts)
        //{
        //	SecurityProvider.Trace($"Call to {nameof(RemoveFacts)}");

        //	var removedFacts = facts as string[] ?? facts.ToArray();
        //	SecurityProvider.Trace($"   Removing facts: {String.Join("; ", removedFacts)}");

        //	RemovePredicates(removedFacts, _factsFileFullName);
        //}

        //public virtual void AddRule(string rule)
        //{
        //	SecurityProvider.Trace($"Call to {nameof(AddRule)}");
        //	SecurityProvider.Trace($"   Adding rule: {rule}");

        //	AddRules(new List<string> { rule });
        //}

        //public virtual void AddRules(IEnumerable<string> rules)
        //{
        //	SecurityProvider.Trace($"Call to {nameof(AddRules)}");

        //	var addedRules = rules as string[] ?? rules.ToArray();
        //	SecurityProvider.Trace($"   Adding rules: {String.Join("; ", addedRules)}");

        //	AddPredicates(addedRules, _rulesFileFullName);
        //}

        //public virtual void RemoveRule(string rule)
        //{
        //	SecurityProvider.Trace($"Call to {nameof(RemoveRule)}");
        //	SecurityProvider.Trace($"   Removing rule: {rule}");

        //	RemoveRules(new List<string> { rule });
        //}

        //public virtual void RemoveRules(IEnumerable<string> rules)
        //{
        //	SecurityProvider.Trace($"Call to {nameof(RemoveRules)}");

        //	var removedRules = rules as string[] ?? rules.ToArray();
        //	SecurityProvider.Trace($"   Removing rules: {String.Join("; ", removedRules)}");

        //	RemovePredicates(removedRules, _rulesFileFullName);
        //}

        public virtual bool IsAuthorized(PermissionRequest request)
        {
            SecurityProvider.Trace($"Call to {nameof(IsAuthorized)}");

            try
            {
                return(Eval(DefaultRuleName,
                            request.User == null ? request.User : request.User.AsPrologConstant(),
                            request.Target == null ? request.Target : request.Target.AsPrologConstant(),
                            request.Entity == null ? request.Entity : request.Entity.AsPrologConstant(),
                            request.Action == null ? request.Action : request.Action.AsPrologConstant()));
            }
            catch (Exception ex)
            {
                SecurityProvider.Trace($"   Error: {ex.GetFullMessage()}");
                throw;
            }
        }
        /// <summary>
        /// Renvoie un objet Permission contenant les actions autorisées pour un utilisateur, sur une target et une entitée donnée.
        /// </summary>
        /// <param name="request">La requête à fournir au moteur prolog : User, Target, Entity doivent être non nulls</param>
        /// <param name="request.User>">Non Null</param>
        /// <param name="request.Target>">Non Null</param>
        /// <param name="request.Action>">Ignoré</param>
        /// <param name="request.Entity>">Non Null</param>
        /// <returns>Une Permission contenant les actions autorisées</returns>
        public virtual Permission GetTargetPermissions(PermissionRequest request)
        {
            SecurityProvider.Trace($"Call to {nameof(GetTargetPermissions)}");

            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            try
            {
                AssertIsNotNull(request.User, nameof(request.User));
                AssertIsNotNull(request.Entity, nameof(request.Entity));

                var permission = new Permission
                {
                    Target = request.Target,
                    Entity = request.Entity,
                };

                var solutions = Solve(DefaultRuleName,
                                      request.MaxSolutionCount ?? int.MaxValue,
                                      request.User.AsPrologConstant(),
                                      request.Target == null ? request.Target : request.Target.AsPrologConstant(),
                                      request.Entity.AsPrologConstant(),
                                      TermAction);

                var access = solutions
                             .Aggregate(AccessType.Values.None,
                                        (accessType, solution) => accessType | ActionToAccessType(solution.GetTermValue(TermAction)?.Trim('\'', '"')));

                // Aucune Permission
                permission.AccessTypes = access;

                return(permission);
            }
            catch (Exception ex)
            {
                SecurityProvider.Trace($"   Error: {ex.GetFullMessage()}");
                throw;
            }
        }
        /// <summary>
        /// Methode qui permet de récupérer toute les authorisations pour un utilisateur donné
        /// Authorisation(rma, G, E, A) permet par exemple de récupérer tous les couples (G, E, A) de solutions pour laquelle Authorisation(rma, G, E, A) est vraie
        /// </summary>
        /// <param name="request"> Action, Entite et Target sont ignoré, User doit être non null</param>
        /// <returns>  </returns>
        public virtual IEnumerable <Permission> GetUserPermissions(PermissionRequest request)
        {
            SecurityProvider.Trace($"Call to {nameof(GetUserPermissions)}");

            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            try
            {
                AssertIsNotNull(request.User, nameof(request.User));

                var solutions = Solve(DefaultRuleName,
                                      request.MaxSolutionCount ?? int.MaxValue,
                                      request.User.AsPrologConstant(),
                                      TermTarget,
                                      TermEntity,
                                      TermAction);

                return(solutions
                       .GroupBy(solution => new { Target = solution.GetTermValue(TermTarget)?.Trim('\'', '"'), Entity = solution.GetTermValue(TermEntity)?.Trim('\'', '"') })
                       .Select(accessGroup => new Permission
                {
                    Target = accessGroup.Key.Target,
                    Entity = accessGroup.Key.Entity,
                    AccessTypes = accessGroup
                                  .Select(solution => solution.GetTermValue(TermAction)?.Trim('\'', '"'))
                                  .Aggregate(AccessType.Values.None, (accessType, action) => accessType | ActionToAccessType(action))
                }));
            }
            catch (Exception ex)
            {
                SecurityProvider.Trace($"   Error: {ex.GetFullMessage()}");
                throw;
            }
        }