/* (non-Javadoc)
   * @see org.bedework.calfacade.svc.AdminGroups#addMember(org.bedework.calfacade.BwGroup, org.bedework.calfacade.BwPrincipal)
   */
  @Override
  public void addMember(final BwGroup group, final BwPrincipal val) throws CalFacadeException {
    BwGroup ag = findGroup(group.getAccount());

    if (ag == null) {
      throw new CalFacadeException("Group " + group + " does not exist");
    }

    /* val must not already be present on any paths to the root.
     * We'll assume the possibility of more than one parent.
     */

    if (!checkPathForSelf(group, val)) {
      throw new CalFacadeException(CalFacadeException.alreadyOnGroupPath);
    }

    /*
    ag.addGroupMember(val);

    BwAdminGroupEntry ent = new BwAdminGroupEntry();

    ent.setGrp(ag);
    ent.setMember(val);

    getSess().save(ent);
    */
    throw new CalFacadeUnimplementedException();
  }
  /* (non-Javadoc)
   * @see org.bedework.calfacade.svc.AdminGroups#removeMember(org.bedework.calfacade.BwGroup, org.bedework.calfacade.BwPrincipal)
   */
  @Override
  public void removeMember(final BwGroup group, final BwPrincipal val) throws CalFacadeException {
    BwGroup ag = findGroup(group.getAccount());

    if (ag == null) {
      throw new CalFacadeException("Group " + group + " does not exist");
    }

    /*
    ag.removeGroupMember(val);

    sess.namedQuery("findAdminGroupEntry");
    sess.setEntity("grp", group);
    sess.setInt("mbrId", val.getId());

    /* This is what I want to do but it inserts 'true' or 'false'
    sess.setBool("isgroup", (val instanceof BwGroup));
    * /
    if (val instanceof BwGroup) {
      sess.setString("isgroup", "T");
    } else {
      sess.setString("isgroup", "F");
    }

    BwAdminGroupEntry ent = (BwAdminGroupEntry)sess.getUnique();

    if (ent == null) {
      return;
    }

    getSess().delete(ent);
    */
    throw new CalFacadeUnimplementedException();
  }
 @Override
 public void addGroup(final BwGroup group) throws CalFacadeException {
   if (findGroup(group.getAccount()) != null) {
     throw new CalFacadeException(CalFacadeException.duplicateAdminGroup);
   }
   throw new CalFacadeUnimplementedException();
 }
  /* Return all groups for principal == null or all groups for which principal
   * is a member
   *
   */
  private Collection<BwGroup> getGroups(
      final DirConfigProperties dirProps, final BwPrincipal principal) throws CalFacadeException {
    LdapConfigProperties props = (LdapConfigProperties) dirProps;
    InitialLdapContext ctx = null;
    String member = null;

    if (principal != null) {
      if (principal.getKind() == WhoDefs.whoTypeUser) {
        member = getUserEntryValue(props, principal);
      } else if (principal.getKind() == WhoDefs.whoTypeGroup) {
        member = getGroupEntryValue(props, principal);
      }
    }

    try {
      ctx = createLdapInitContext(props);

      BasicAttributes matchAttrs = new BasicAttributes(true);

      if (member != null) {
        matchAttrs.put(props.getGroupMemberAttr(), member);
      }

      String[] idAttr = {props.getGroupIdAttr()};

      ArrayList<BwGroup> groups = new ArrayList<BwGroup>();
      NamingEnumeration response = ctx.search(props.getGroupContextDn(), matchAttrs, idAttr);
      while (response.hasMore()) {
        SearchResult sr = (SearchResult) response.next();
        Attributes attrs = sr.getAttributes();

        Attribute nmAttr = attrs.get(props.getGroupIdAttr());
        if (nmAttr.size() != 1) {
          throw new CalFacadeException("org.bedework.ldap.groups.multiple.result");
        }

        BwGroup group = new BwGroup();
        group.setAccount(nmAttr.get(0).toString());
        group.setPrincipalRef(makePrincipalUri(group.getAccount(), WhoDefs.whoTypeGroup));

        groups.add(group);
      }

      return groups;
    } catch (Throwable t) {
      if (debug) {
        error(t);
      }
      throw new CalFacadeException(t);
    } finally {
      // Close the context to release the connection
      if (ctx != null) {
        closeContext(ctx);
      }
    }
  }
  /* Find members for given group
   *
   */
  private void getGroupMembers(final DirConfigProperties dirProps, final BwGroup group)
      throws CalFacadeException {
    LdapConfigProperties props = (LdapConfigProperties) dirProps;
    InitialLdapContext ctx = null;

    try {
      ctx = createLdapInitContext(props);

      BasicAttributes matchAttrs = new BasicAttributes(true);

      matchAttrs.put(props.getGroupIdAttr(), group.getAccount());

      String[] memberAttr = {props.getGroupMemberAttr()};

      ArrayList<String> mbrs = null;

      boolean beenHere = false;

      NamingEnumeration response = ctx.search(props.getGroupContextDn(), matchAttrs, memberAttr);
      while (response.hasMore()) {
        SearchResult sr = (SearchResult) response.next();
        Attributes attrs = sr.getAttributes();

        if (beenHere) {
          throw new CalFacadeException("org.bedework.ldap.groups.multiple.result");
        }

        beenHere = true;

        Attribute membersAttr = attrs.get(props.getGroupMemberAttr());
        mbrs = new ArrayList<String>();

        for (int m = 0; m < membersAttr.size(); m++) {
          mbrs.add(membersAttr.get(m).toString());
        }
      }
      // LDAP We need a way to search recursively for groups.

      /* Search for each user in the group */
      String memberContext = props.getGroupMemberContextDn();
      String memberSearchAttr = props.getGroupMemberSearchAttr();
      String[] idAttr = {
        props.getGroupMemberUserIdAttr(), props.getGroupMemberGroupIdAttr(), "objectclass"
      };

      for (String mbr : mbrs) {
        if (memberContext != null) {
          matchAttrs = new BasicAttributes(true);

          matchAttrs.put(memberSearchAttr, mbr);

          response = ctx.search(memberContext, matchAttrs, idAttr);
        } else {
          response = ctx.search(memberContext, null, idAttr);
        }

        if (response.hasMore()) {
          SearchResult sr = (SearchResult) response.next();
          Attributes attrs = sr.getAttributes();

          Attribute ocsAttr = attrs.get("objectclass");
          String userOc = props.getUserObjectClass();
          String groupOc = props.getGroupObjectClass();
          boolean isGroup = false;

          for (int oci = 0; oci < ocsAttr.size(); oci++) {
            String oc = ocsAttr.get(oci).toString();
            if (userOc.equals(oc)) {
              break;
            }

            if (groupOc.equals(oc)) {
              isGroup = true;
              break;
            }
          }

          BwPrincipal p = null;
          Attribute attr;

          if (isGroup) {
            p = BwPrincipal.makeGroupPrincipal();

            attr = attrs.get(props.getGroupMemberGroupIdAttr());
          } else {
            p = BwPrincipal.makeUserPrincipal();

            attr = attrs.get(props.getGroupMemberUserIdAttr());
          }

          if (attr.size() != 1) {
            throw new CalFacadeException("org.bedework.ldap.groups.multiple.result");
          }

          p.setAccount(attr.get(0).toString());
          p.setPrincipalRef(makePrincipalUri(p.getAccount(), p.getKind()));
          group.addGroupMember(p);
        }
      }
    } catch (Throwable t) {
      if (debug) {
        error(t);
      }
      throw new CalFacadeException(t);
    } finally {
      // Close the context to release the connection
      if (ctx != null) {
        closeContext(ctx);
      }
    }

    /* Recursively fetch members of groups that are members. */

    for (BwGroup g : group.getGroups()) {
      getGroupMembers(props, g);
    }
  }