/****** sgeobj/href/href_list_add() *******************************************
*  NAME
*     href_list_add() -- Add host or hostgroup reference.
*
*  SYNOPSIS
*     bool 
*     href_list_add(lList **this_list, lList **answer_list, 
*                   const char *host_or_group) 
*
*  FUNCTION
*     Add a host or hostgroup given by 'host_or_group' into the list 
*     'this_list'. If the function is successfull then the function
*     returns 'true' otherwise it will add an entry into 'answer_list'
*     and return with 'false'. If 'this_list' does not exist than it
*     will be created.
*
*  INPUTS
*     lList **this_list         - HR_Type list 
*     lList **answer_list       - AN_Type list 
*     const char *host_or_group - host or group name  
*
*  RESULT
*     bool - error state
*        true - Success
*        false - Error
*******************************************************************************/
bool 
href_list_add(lList **this_list, lList **answer_list, const char *host_or_group)
{
   bool ret = true;

   DENTER(HOSTREF_LAYER, "href_list_add");
   if (this_list != NULL && host_or_group != NULL) {
      if (!href_list_has_member(*this_list, host_or_group)) {
         lListElem *h_or_g;   /* HR_Type */

         h_or_g = lAddElemHost(this_list, HR_name, host_or_group, HR_Type);
         if (h_or_g == NULL) {
            answer_list_add(answer_list, MSG_SGETEXT_NOMEM,
                            STATUS_EMALLOC, ANSWER_QUALITY_ERROR);
            ret = false;
         }
      }
   } else {
      SGE_ADD_MSG_ID(sprintf(SGE_EVENT, MSG_INAVLID_PARAMETER_IN_S, SGE_FUNC));
      answer_list_add(answer_list, SGE_EVENT, 
                      STATUS_ERROR1, ANSWER_QUALITY_ERROR);
      ret = false;
   }
   DEXIT;
   return ret;
}
/****** sgeobj/href/href_list_compare() ***************************************
*  NAME
*     href_list_compare() -- Finds additional entries in list 
*
*  SYNOPSIS
*     bool 
*     href_list_compare(const lList *this_list, lList **answer_list, 
*                       const lList *list, lList **add_hosts, 
*                       lList **add_groups, lList **equity_hosts,
*                       lList **equity_groups) 
*
*  FUNCTION
*     This function will find differences between two hostref lists
*     given by 'this_list' and 'list'. Hosts and hostgroups which are
*     only in 'this_list' can be found in 'add_hosts' and 'add_groups'.
*     References which are contained in both lists can be found in 
*     'equity_hosts' and 'equity_groups' after a call to this function.
*
*     If the calling function is not interested in one ore more of the
*     result lists than NULL should be used as parameter. The calling
*     function is responsible to free all result lists. 
*
*     If the callee is also interested in the references which are
*     only part of 'list' than this function can not be used.
*     href_list_find_diff() should be used in this case. 
*
*  INPUTS
*     const lList *this_list - HR_Type list to comapre
*     lList **answer_list    - AN_Type list 
*     const lList *list      - 2nd HR_Type list to be compared
*     lList **add_hosts      - HR_Type list 
*     lList **add_groups     - HR_Type list 
*     lList **equity_hosts   - HR_Type list
*     lList **equity_groups  - HR_Type list
*
*  RESULT
*     bool - error state
*        true  - Success
*        false - Error
*
*  SEE ALSO
*     sgeobj/href/href_list_find_diff()
*******************************************************************************/
bool 
href_list_compare(const lList *this_list, lList **answer_list,
                  const lList *list, lList **add_hosts,
                  lList **add_groups, lList **equity_hosts, 
                  lList **equity_groups) 
{
   bool ret = true;
   lListElem *this_elem;   /* HR_Type */
  
   DENTER(HOSTREF_LAYER, "href_list_compare"); 

   for_each(this_elem, this_list) {
      const char *host_or_group = lGetHost(this_elem, HR_name);

      if (!href_list_has_member(list, host_or_group)) {
         if (is_hgroup_name(host_or_group)) {
            if (add_groups != NULL) {
               ret = href_list_add(add_groups, answer_list, host_or_group);
            }
         } else if (add_hosts != NULL) {
            ret = href_list_add(add_hosts, answer_list, host_or_group);
         }
      } else {
         if (is_hgroup_name(host_or_group)) {
            if (equity_groups != NULL) {
               ret = href_list_add(equity_groups, answer_list, host_or_group);
            }
         } else if (equity_hosts != NULL) {
            ret = href_list_add(equity_hosts, answer_list, host_or_group);
         }
      }
      if (!ret) {
         break;
      }
   }
   DRETURN(ret);
}
static bool
hgroup_mod_hostlist(lListElem *hgroup, lList **answer_list,
                    lListElem *reduced_elem, int sub_command,
                    lList **add_hosts, lList **rem_hosts,
                    lList **occupant_groups)
{
    bool ret = true;

    DENTER(TOP_LAYER, "hgroup_mod_hostlist");
    if (hgroup != NULL && reduced_elem != NULL) {
        int pos = lGetPosViaElem(reduced_elem, HGRP_host_list, SGE_NO_ABORT);

        if (pos >= 0) {
            lList *list = lGetPosList(reduced_elem, pos);
            lList *old_href_list = lCopyList("", lGetList(hgroup, HGRP_host_list));
            lList *master_list = *(hgroup_list_get_master_list());
            lList *href_list = NULL;
            lList *add_groups = NULL;
            lList *rem_groups = NULL;

            if (ret) {
                ret &= href_list_resolve_hostnames(list, answer_list, true);
            }
            if (ret) {
                attr_mod_sub_list(answer_list, hgroup, HGRP_host_list, HR_name,
                                  reduced_elem, sub_command, SGE_ATTR_HOSTLIST,
                                  SGE_OBJ_HGROUP, 0);
                href_list = lGetList(hgroup, HGRP_host_list);
            }
            if (ret) {
                ret &= href_list_find_diff(href_list, answer_list, old_href_list,
                                           add_hosts, rem_hosts, &add_groups,
                                           &rem_groups);
            }
            if (ret && add_groups != NULL) {
                ret &= hgroup_list_exists(master_list, answer_list, add_groups);
            }
            if (ret) {
                ret &= href_list_find_effective_diff(answer_list, add_groups,
                                                     rem_groups, master_list,
                                                     add_hosts, rem_hosts);
            }
            if (ret) {
                ret &= href_list_resolve_hostnames(*add_hosts, answer_list, false);
            }

            /*
             * Try to find cycles in the definition
             */
            if (ret) {
                ret &= hgroup_find_all_referencees(hgroup, answer_list,
                                                   master_list, occupant_groups);
                ret &= href_list_add(occupant_groups, answer_list,
                                     lGetHost(hgroup, HGRP_name));
                if (ret) {
                    if (*occupant_groups != NULL && add_groups != NULL) {
                        lListElem *add_group = NULL;

                        for_each(add_group, add_groups) {
                            const char *name = lGetHost(add_group, HR_name);

                            if (href_list_has_member(*occupant_groups, name)) {
                                break;
                            }
                        }
                        if (add_group == NULL) {
                            /*
                             * No cycle found => success
                             */
                            ;
                        } else {
                            SGE_ADD_MSG_ID(sprintf(SGE_EVENT, MSG_HGROUP_CYCLEINDEF_SS,
                                                   lGetHost(add_group, HR_name),
                                                   lGetHost(hgroup, HGRP_name)));
                            answer_list_add(answer_list, SGE_EVENT, STATUS_ESYNTAX,
                                            ANSWER_QUALITY_ERROR);
                            ret = false;
                        }
                    }
                }
            }