/**
   * Overrides the implies method to handle checking for the existence of one attribute - the "match
   * one" scenario rather than the "match all" behavior of the overridden classes. Specifically,
   * this permission will imply another permission if that permission matches at least one of our
   * permission attributes.
   *
   * @param p the permission to check for behavior/functionality comparison.
   * @return {@code true} if this current instance <em>implies</em> the specified {@code Permission}
   *     argument, {@code false} otherwise.
   */
  @Override
  public boolean implies(Permission p) {
    if (permissionList.isEmpty()) {
      SecurityLogger.logDebug(
          PERMISSION_START_MSG
              + toString()
              + PERMISSION_NOT_IMPLIES_MSG
              + p.toString()
              + PERMISSION_END_MSG);
      return false;
    }

    if (p instanceof CollectionPermission) {
      for (Permission perm : ((CollectionPermission) p).getPermissionList()) {
        boolean result = false;
        for (Permission ourPerm : permissionList) {
          // we only care about the key value permission here, because that one can have
          // multiple values
          // mapped to a single key. In the case of "match one" we only need one of those
          // values to satisfy
          // the permission.
          if (ourPerm instanceof KeyValuePermission) {
            for (String value : ((KeyValuePermission) ourPerm).getValues()) {
              // Since this is "match one" we know that only one of these values needs
              // to match in order
              // for the entire permission at that key to be implied
              // So here we loop through all of the values assigned to that key and
              // create new
              // single valued key value permissions
              KeyValuePermission kvp =
                  new KeyValuePermission(((KeyValuePermission) ourPerm).getKey());
              kvp.addValue(value);
              if (perm.implies(kvp)) {
                result = true;
                break;
              }
            }
            // Currently we use key value permissions for everything. However, we still need
            // to be able to handle
            // permissions other than KV, so this else block will serve as the catch all for
            // everything else.
          } else {
            // Shiro permissions are always a "match all" condition so we need to flip
            // the implies to make it match one
            if (perm.implies(ourPerm)) {
              result = true;
              break;
            }
          }
        }
        if (!result) {
          SecurityLogger.logDebug(
              PERMISSION_START_MSG
                  + toString()
                  + PERMISSION_NOT_IMPLIES_MSG
                  + p.toString()
                  + PERMISSION_END_MSG);
          return false;
        }
      }
      SecurityLogger.logDebug(
          PERMISSION_START_MSG
              + toString()
              + PERMISSION_IMPLIES_MSG
              + p.toString()
              + PERMISSION_END_MSG);
      return true;
    }

    // default catch all permission check
    for (Permission permission : permissionList) {
      // Shiro permissions are always a "match all" condition so we need to flip the implies
      // to make it match one
      if (p.implies(permission)) {
        SecurityLogger.logDebug(
            PERMISSION_START_MSG
                + toString()
                + PERMISSION_IMPLIES_MSG
                + p.toString()
                + PERMISSION_END_MSG);
        return true;
      }
    }
    SecurityLogger.logDebug(
        PERMISSION_START_MSG
            + toString()
            + PERMISSION_NOT_IMPLIES_MSG
            + p.toString()
            + PERMISSION_END_MSG);
    return false;
  }