/**
   * Construct an IEntityGroup from a Grouper WsGroup.
   *
   * @param wsGroup
   * @return the group
   */
  protected IEntityGroup createUportalGroupFromGrouperGroup(WsGroup wsGroup) {
    IEntityGroup iEntityGroup = new EntityGroupImpl(wsGroup.getName(), IPerson.class);

    // need to set the group name and description to the actual
    // display name and description
    iEntityGroup.setName(wsGroup.getDisplayName());
    iEntityGroup.setDescription(wsGroup.getDescription());
    return iEntityGroup;
  }
  /**
   * Test a Grouper {WsGroup} against a query string according to the specified method and determine
   * if it matches the query.
   *
   * @param group WsGroup to be tested
   * @param query Query string
   * @param method int-based method matching one of the standard search methods defined in
   *     {IGroupConstants}
   * @return <code>true</code> if the group matches, <code>false</code> otherwise
   */
  protected boolean groupMatches(WsGroup group, String query, int method) {

    // Ensure that this group has a name defined before performing
    // comparisons.
    if (group == null || group.getName() == null) {
      return false;
    }

    switch (method) {
      case IGroupConstants.IS:
        return group.getName().equals(query);
      case IGroupConstants.STARTS_WITH:
        return group.getName().startsWith(query);
      case IGroupConstants.ENDS_WITH:
        return group.getName().endsWith(query);
      case IGroupConstants.CONTAINS:
        return group.getName().contains(query);
      default:
        return false;
    }
  }
  /* (non-Javadoc)
   * @see org.jasig.portal.groups.IEntityGroupStore#searchForGroups(java.lang.String, int, java.lang.Class)
   */
  public EntityIdentifier[] searchForGroups(
      final String query, final int method, @SuppressWarnings("unchecked") final Class leaftype) {

    // only search for groups
    if (leaftype != IPerson.class) {
      return new EntityIdentifier[] {};
    }

    if (LOGGER.isDebugEnabled()) {
      LOGGER.debug("Searching Grouper for groups matching query: " + query);
    }

    // result groups.
    List<EntityIdentifier> groups = new ArrayList<EntityIdentifier>();

    try {

      // TODO: searches need to be performed against the group display
      // name rather than the group key

      GcFindGroups groupSearch = new GcFindGroups();
      WsQueryFilter filter = new WsQueryFilter();
      // is this an exact search or fuzzy
      if (method == IGroupConstants.IS) {
        filter.setQueryFilterType("FIND_BY_GROUP_NAME_EXACT");
      } else {
        filter.setQueryFilterType("FIND_BY_GROUP_NAME_APPROXIMATE");
      }
      filter.setGroupName(query);
      groupSearch.assignQueryFilter(filter);
      WsFindGroupsResults results = groupSearch.execute();

      if (results != null && results.getGroupResults() != null) {
        for (WsGroup g : results.getGroupResults()) {
          if (validKey(g.getName())) {
            if (LOGGER.isTraceEnabled()) {
              LOGGER.trace("Retrieved group: " + g.getName());
            }
            groups.add(new EntityIdentifier(g.getName(), IEntityGroup.class));
          }
        }
      }

      if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("Returning " + groups.size() + " results for query " + query);
      }

      return groups.toArray(new EntityIdentifier[groups.size()]);

    } catch (Exception e) {
      LOGGER.warn(
          "Exception while attempting to retrieve "
              + "search results for query "
              + query
              + " and entity type "
              + leaftype.getCanonicalName()
              + " : "
              + e.getMessage());
      return new EntityIdentifier[] {};
    }
  }
  /* (non-Javadoc)
   * @see org.jasig.portal.groups.IEntityGroupStore#findParentGroups(org.jasig.portal.groups.IGroupMember)
   */
  @SuppressWarnings("unchecked")
  public Iterator findParentGroups(IGroupMember gm) throws GroupsException {

    final List<IEntityGroup> parents = new LinkedList<IEntityGroup>();

    GcGetGroups getGroups = new GcGetGroups();

    String uportalStem = getStemPrefix();

    // if only searching in a specific stem
    if (!StringUtils.isBlank(uportalStem)) {
      getGroups.assignStemScope(StemScope.ALL_IN_SUBTREE);
      getGroups.assignWsStemLookup(new WsStemLookup(uportalStem, null));
    }

    String key = null;
    String subjectSourceId = null;
    if (gm.isGroup()) {

      key = ((IEntityGroup) gm).getLocalKey();

      if (!validKey(key)) {
        return parents.iterator();
      }
      subjectSourceId = "g:gsa";
    } else {

      // Determine the key to use for this entity. If the entity is a
      // group, we should use the group's local key (excluding the
      // "grouper." portion of the full key. If the entity is not a
      // group type, just use the key.
      key = gm.getKey();
    }
    getGroups.addSubjectLookup(new WsSubjectLookup(null, subjectSourceId, key));

    if (LOGGER.isDebugEnabled()) {
      LOGGER.debug("Searching Grouper for parent groups of the entity with key: " + key);
    }

    try {

      WsGetGroupsResults results = getGroups.execute();

      if (results == null || results.getResults() == null || results.getResults().length != 1) {
        LOGGER.debug("Grouper service returned no matches for key " + key);
        return parents.iterator();
      }
      WsGetGroupsResult wsg = results.getResults()[0];
      if (wsg.getWsGroups() != null) {
        for (WsGroup g : wsg.getWsGroups()) {
          if (LOGGER.isDebugEnabled()) {
            LOGGER.trace("Retrieved group: " + g.getName());
          }
          IEntityGroup parent = createUportalGroupFromGrouperGroup(g);
          parents.add(parent);
        }
      }

      if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("Retrieved " + parents.size() + " parent groups of entity with key " + key);
      }

    } catch (Exception e) {
      LOGGER.warn(
          "Exception while attempting to retrieve "
              + "parents for entity with key "
              + key
              + " from Grouper web services: "
              + e.getMessage());
      return Collections.<IEntityGroup>emptyList().iterator();
    }

    return parents.iterator();
  }