public function getPolicy(Role $role, string $action)
    {
        $rules = $this->getRules();
        $pref_policy = $this->getACL()->getPreferredPolicy();

        $inherit = true;
        $ancestor_distance = null;
        $ancestor_policy = null;
        foreach ($rules as $rule)
        {
            // NOINHERIT-rules disable rule inheritance and do nothing else
            if ($rule->policy === Rule::NOINHERIT)
            {
                $inherit = false;
                continue;
            }

            // Always ignore INHERIT rules
            if ($rule->policy === Rule::INHERIT)
                continue;

            // If the action doesn't match, don't consider the rule
            // TODO: What about container actions?
            if ($rule->action !== $action)
                continue;

            // If the Rule applies to the specified Role, its answer is definitive
            if ($rule->role->is($role))
                return $rule->policy;

            // Find the closest matching parent
            if (($distance = $rule->role->isAncestorOf($role)) > 0)
            {
                // Always select the closest parent that has a defined rule.
                // When there are several conflicting rules, applying to the
                // same level of ancestry, select the preferred policy.
                if (
                    $ancestor_distance === null || 
                    $distance < $ancestor_distance || 
                    ($distance === $ancestor_distance && $rule->policy === $pref_policy)
                )
                {
                    $ancestor_policy = $rule;
                    $ancestor_distance = $distance;
                }
            }
        }

        if ($ancestor_policy !== null)
            return $ancestor_policy->policy;

        // This Entity doesn't have a defined policy for this action.
        // If inheritance is disabled, or the Entity does not have a parent (root),
        // return the default policy.
        if (!$inherit || empty($this->parents))
        {
            // Return default policy
            return Rule::UNDEFINED;
        }

        // Inherit from the parents
        $parents = $this->getParents();
        $policy = Rule::UNDEFINED;
        foreach ($parents as $parent)
        {
            $policy = $parent->getPolicy($role, $action);
            // If an Entity has multiple parents, just one of them needs to
            // allow the action to allow it on this Entity.
            if ($policy === $pref_policy)
                return $pref_policy;
        }

        // None of the parents have a preferred policy, so return the alternative
        return $policy;
    }