text:    /*******************************************************/
     /*      "C" Language Integrated Production System      */
     /*                                                     */
     /*            CLIPS Version 6.40  10/03/19             */
     /*                                                     */
     /*                    AGENDA MODULE                    */
     /*******************************************************/
  
  /*************************************************************/
  /* Purpose:                                                  */
  /*   Provides functionality for examining, manipulating,     */
  /*   adding, and removing activations from the agenda.       */
  /*                                                           */
  /* Principal Programmer(s):                                  */
  /*      Gary D. Riley                                        */
  /*                                                           */
  /* Contributing Programmer(s):                               */
  /*      Brian L. Dantes                                      */
  /*                                                           */
  /* Revision History:                                         */
  /*      6.23: Corrected compilation errors for files         */
  /*            generated by constructs-to-c. DR0861           */
  /*                                                           */
  /*      6.24: Removed CONFLICT_RESOLUTION_STRATEGIES         */
  /*            and DYNAMIC_SALIENCE compilation flags.        */
  /*                                                           */
  /*            Renamed BOOLEAN macro type to intBool.         */
  /*                                                           */
  /*            Added EnvGetActivationBasisPPForm function.    */
  /*                                                           */
  /*      6.30: Added salience groups to improve performance   */
  /*            with large numbers of activations of different */
  /*            saliences.                                     */
  /*                                                           */
  /*            Borland C (IBM_TBC) and Metrowerks CodeWarrior */
  /*            (MAC_MCW, IBM_MCW) are no longer supported.    */
  /*                                                           */
  /*            Support for long long integers.                */
  /*                                                           */
  /*            Added const qualifiers to remove C++           */
  /*            deprecation warnings.                          */
  /*                                                           */
  /*            Converted API macros to function calls.        */
  /*                                                           */
  /*      6.40: Added Env prefix to GetEvaluationError and     */
  /*            SetEvaluationError functions.                  */
  /*                                                           */
  /*            Pragma once and other inclusion changes.       */
  /*                                                           */
  /*            Added support for booleans with <stdbool.h>.   */
  /*                                                           */
  /*            Removed use of void pointers for specific      */
  /*            data structures.                               */
  /*                                                           */
  /*            ALLOW_ENVIRONMENT_GLOBALS no longer supported. */
  /*                                                           */
  /*            UDF redesign.                                  */
  /*                                                           */
  /*************************************************************/
  
  #include <stdio.h>
  #include <string.h>
  
  #include "setup.h"
  
  #if DEFRULE_CONSTRUCT
  
  #include "argacces.h"
  #include "constant.h"
  #include "crstrtgy.h"
  #include "engine.h"
  #include "envrnmnt.h"
  #include "extnfunc.h"
  #include "memalloc.h"
  #include "moduldef.h"
  #include "modulutl.h"
  #include "multifld.h"
  #include "prntutil.h"
  #include "reteutil.h"
  #include "retract.h"
  #include "router.h"
  #include "rulebsc.h"
  #include "ruledef.h"
  #include "strngrtr.h"
  #include "sysdep.h"
  #include "watch.h"
  
  #include "agenda.h"
  
  /***************************************/
  /* LOCAL INTERNAL FUNCTION DEFINITIONS */
  /***************************************/
  
     static void                    PrintActivation(Environment *,const char *,Activation *);
     static void                    AgendaClearFunction(Environment *,void *);
     static const char             *SalienceEvaluationName(SalienceEvaluationType);
     static int                     EvaluateSalience(Environment *,Defrule *);
     static struct salienceGroup   *ReuseOrCreateSalienceGroup(Environment *,struct defruleModule *,int);
     static struct salienceGroup   *FindSalienceGroup(struct defruleModule *,int);
     static void                    RemoveActivationFromGroup(Environment *,Activation *,struct defruleModule *);
  
  /*************************************************/
  /* InitializeAgenda: Initializes the activations */
  /*   watch item and the H/L commands for         */
  /*   manipulating the agenda.                    */
  /*************************************************/
  void InitializeAgenda(
    Environment *theEnv)
    {
     AllocateEnvironmentData(theEnv,AGENDA_DATA,sizeof(struct agendaData),NULL);
  
     AgendaData(theEnv)->SalienceEvaluation = WHEN_DEFINED;
  
     AgendaData(theEnv)->Strategy = DEFAULT_STRATEGY;
  
     AddClearFunction(theEnv,"agenda",AgendaClearFunction,0,NULL);
  #if DEBUGGING_FUNCTIONS
     AddWatchItem(theEnv,"activations",1,&AgendaData(theEnv)->WatchActivations,40,DefruleWatchAccess,DefruleWatchPrint);
  #endif
  #if ! RUN_TIME
     AddUDF(theEnv,"refresh","v",1,1,"y",RefreshCommand,"RefreshCommand",NULL);
     AddUDF(theEnv,"refresh-agenda","v",0,1,"y",RefreshAgendaCommand,"RefreshAgendaCommand",NULL);
     AddUDF(theEnv,"get-salience-evaluation","y",0,0,NULL,GetSalienceEvaluationCommand,"GetSalienceEvaluationCommand",NULL);
     AddUDF(theEnv,"set-salience-evaluation","y",1,1,"y",SetSalienceEvaluationCommand,"SetSalienceEvaluationCommand",NULL);
  
  #if DEBUGGING_FUNCTIONS
     AddUDF(theEnv,"agenda","v",0,1,"y",AgendaCommand,"AgendaCommand",NULL);
  #endif
  #endif
    }
  
  /*****************************************************************/
  /* AddActivation: Creates a rule activation to be added to the   */
  /*   Agenda and links the activation with its associated partial */
  /*   match. The function PlaceActivation is then called to place */
  /*   the activation on the Agenda. Typically called when all     */
  /*   patterns on the LHS of a rule have been satisfied.          */
  /*****************************************************************/
  void AddActivation(
    Environment *theEnv,
    Defrule *theRule,
    PartialMatch *binds)
    {
     Activation *newActivation;
     struct defruleModule *theModuleItem;
     struct salienceGroup *theGroup;
  
     /*=======================================*/
     /* Focus on the module if the activation */
     /* is from an auto-focus rule.           */
     /*=======================================*/
  
     if (theRule->autoFocus)
       { Focus(theRule->header.whichModule->theModule); }
  
     /*=======================================================*/
     /* Create the activation. The activation stores pointers */
     /* to its associated partial match and defrule. The      */
     /* activation is given a time tag, its salience is       */
     /* evaluated, and it is assigned a random number for use */
     /* with the random conflict resolution strategy.         */
     /*=======================================================*/
  
     newActivation = get_struct(theEnv,activation);
     newActivation->theRule = theRule;
     newActivation->basis = binds;
     newActivation->timetag = AgendaData(theEnv)->CurrentTimetag++;
     newActivation->salience = EvaluateSalience(theEnv,theRule);
  
     newActivation->randomID = genrand();
     newActivation->prev = NULL;
     newActivation->next = NULL;
  
     AgendaData(theEnv)->NumberOfActivations++;
  
     /*=======================================================*/
     /* Point the partial match to the activation to complete */
     /* the link between the join network and the agenda.     */
     /*=======================================================*/
  
     binds->marker = newActivation;
  
     /*====================================================*/
     /* If activations are being watch, display a message. */
     /*====================================================*/
  
  #if DEBUGGING_FUNCTIONS
     if (newActivation->theRule->watchActivation &&
         (! ConstructData(theEnv)->ClearReadyInProgress) &&
         (! ConstructData(theEnv)->ClearInProgress))
       {
        WriteString(theEnv,STDOUT,"==> Activation ");
        PrintActivation(theEnv,STDOUT,newActivation);
        WriteString(theEnv,STDOUT,"\n");
       }
  #endif
  
      /*=====================================*/
      /* Place the activation on the agenda. */
      /*=====================================*/
  
      theModuleItem = (struct defruleModule *) theRule->header.whichModule;
  
      theGroup = ReuseOrCreateSalienceGroup(theEnv,theModuleItem,newActivation->salience);
  
      PlaceActivation(theEnv,&(theModuleItem->agenda),newActivation,theGroup);
     }
  
  /*******************************/
  /* ReuseOrCreateSalienceGroup: */
  /*******************************/
  static struct salienceGroup *ReuseOrCreateSalienceGroup(
    Environment *theEnv,
    struct defruleModule *theRuleModule,
    int salience)
    {
     struct salienceGroup *theGroup, *lastGroup, *newGroup;
  
     for (lastGroup = NULL, theGroup = theRuleModule->groupings;
          theGroup != NULL;
          lastGroup = theGroup, theGroup = theGroup->next)
       {
        if (theGroup->salience == salience)
          { return(theGroup); }
  
        if (theGroup->salience < salience)
          { break; }
       }
  
     newGroup = get_struct(theEnv,salienceGroup);
     newGroup->salience = salience;
     newGroup->first = NULL;
     newGroup->last = NULL;
     newGroup->next = theGroup;
     newGroup->prev = lastGroup;
  
     if (newGroup->next != NULL)
       { newGroup->next->prev = newGroup; }
  
     if (newGroup->prev != NULL)
       { newGroup->prev->next = newGroup; }
  
     if (lastGroup == NULL)
       { theRuleModule->groupings = newGroup; }
  
     return newGroup;
    }
  
  /**********************/
  /* FindSalienceGroup: */
  /**********************/
  static struct salienceGroup *FindSalienceGroup(
    struct defruleModule *theRuleModule,
    int salience)
    {
     struct salienceGroup *theGroup;
  
     for (theGroup = theRuleModule->groupings;
          theGroup != NULL;
          theGroup = theGroup->next)
       {
        if (theGroup->salience == salience)
          { return(theGroup); }
  
        if (theGroup->salience < salience)
          { break; }
       }
  
     return NULL;
    }
  
  /***************************************************************/
  /* ClearRuleFromAgenda: Clears the agenda of a specified rule. */
  /***************************************************************/
  void ClearRuleFromAgenda(
    Environment *theEnv,
    Defrule *theRule)
    {
     Defrule *tempRule;
     struct activation *agendaPtr, *agendaNext;
  
     /*============================================*/
     /* Get a pointer to the agenda for the module */
     /* in which the rule is contained.            */
     /*============================================*/
  
     agendaPtr = ((struct defruleModule *) theRule->header.whichModule)->agenda;
  
     /*==============================================*/
     /* Loop through every activation on the agenda. */
     /*==============================================*/
  
     while (agendaPtr != NULL)
       {
        agendaNext = agendaPtr->next;
  
        /*========================================================*/
        /* Check each disjunct of the rule against the activation */
        /* to determine if the activation points to the rule. If  */
        /* it does, then remove the activation from the agenda.   */
        /*========================================================*/
  
        for (tempRule = theRule;
             tempRule != NULL;
             tempRule = tempRule->disjunct)
          {
           if (agendaPtr->theRule == tempRule)
             {
              RemoveActivation(theEnv,agendaPtr,true,true);
              break;
             }
          }
  
        agendaPtr = agendaNext;
       }
    }
  
  /***************************************************************/
  /* GetNextActivation: Returns an activation from the Agenda.   */
  /*   If its argument is NULL, then the first activation on the */
  /*   Agenda is returned. If its argument is not NULL, the next */
  /*   activation after the argument is returned.                */
  /***************************************************************/
  Activation *GetNextActivation(
    Environment *theEnv,
    Activation *actPtr)
    {
     struct defruleModule *theModuleItem;
  
     if (actPtr == NULL)
       {
        theModuleItem = (struct defruleModule *) GetModuleItem(theEnv,NULL,DefruleData(theEnv)->DefruleModuleIndex);
        if (theModuleItem == NULL) return NULL;
        return theModuleItem->agenda;
       }
     else
       { return actPtr->next; }
    }
  
  /*********************************************/
  /* GetActivationBasis: Returns the basis of  */
  /*   the rule associated with an activation. */
  /*********************************************/
  struct partialMatch *GetActivationBasis(
    Environment *theEnv,
    Activation *actPtr)
    {
  #if MAC_XCD
  #pragma unused(theEnv)
  #endif
     return actPtr->basis;
    }
  
  /*********************************************/
  /* ActivationRuleName: Returns the name of   */
  /*   the rule associated with an activation. */
  /*********************************************/
  const char *ActivationRuleName(
    Activation *actPtr)
    {
     return actPtr->theRule->header.name->contents;
    }
  
  /***************************************/
  /* GetActivationRule: Returns the rule */
  /*   associated with an activation.    */
  /***************************************/
  Defrule *GetActivationRule(
    Environment *theEnv,
    Activation *actPtr)
    {
  #if MAC_XCD
  #pragma unused(theEnv)
  #endif
     return actPtr->theRule;
    }
  
  /************************************************/
  /* ActivationGetSalience: Returns the salience  */
  /*   of the rule associated with an activation. */
  /************************************************/
  int ActivationGetSalience(
    Activation *actPtr)
    {
     return actPtr->salience;
    }
  
  /**************************************/
  /* ActivationSetSalience: Sets the    */
  /*   salience value of an activation. */
  /**************************************/
  int ActivationSetSalience(
    Activation *actPtr,
    int value)
    {
     int temp;
  
     if (value > MAX_DEFRULE_SALIENCE)
       { value = MAX_DEFRULE_SALIENCE; }
     else if (value < MIN_DEFRULE_SALIENCE)
       { value = MIN_DEFRULE_SALIENCE; }
      
     temp = actPtr->salience;
     actPtr->salience = value;
     return temp;
    }
  
  /********************************************/
  /* ActivationPPForm: Returns the pretty     */
  /*   print representation of an activation. */
  /********************************************/
  void ActivationPPForm(
    Activation *theActivation,
    StringBuilder *theSB)
    {
     Environment *theEnv = theActivation->theRule->header.env;
     
     OpenStringBuilderDestination(theEnv,"ActPPForm",theSB);
     PrintActivation(theEnv,"ActPPForm",theActivation);
     CloseStringBuilderDestination(theEnv,"ActPPForm");
    }
  
  /****************************************************/
  /* GetActivationBasisPPForm: Returns the pretty     */
  /*   print representation of an activation's basis. */
  /****************************************************/
  void GetActivationBasisPPForm(
    Environment *theEnv,
    char *buffer,
    size_t bufferLength,
    Activation *theActivation)
    {
     OpenStringDestination(theEnv,"ActPPForm",buffer,bufferLength);
     PrintPartialMatch(theEnv,"ActPPForm",theActivation->basis);
     CloseStringDestination(theEnv,"ActPPForm");
    }
  
  /********************************************/
  /* MoveActivationToTop: Moves the specified */
  /*   activation to the top of the agenda.   */
  /********************************************/
  bool MoveActivationToTop(
    Environment *theEnv,
    Activation *theActivation)
    {
     struct activation *prevPtr;
     struct defruleModule *theModuleItem;
  
     /*====================================*/
     /* Determine the module of the agenda */
     /* in which the activation is stored. */
     /*====================================*/
  
     theModuleItem = (struct defruleModule *) theActivation->theRule->header.whichModule;
  
     /*============================================*/
     /* If the activation is already at the top of */
     /* the agenda, then nothing needs to be done. */
     /*============================================*/
  
     if (theActivation == theModuleItem->agenda) return false;
  
     /*=================================================*/
     /* Update the pointers of the activation preceding */
     /* and following the activation being moved.       */
     /*=================================================*/
  
     prevPtr = theActivation->prev;
     prevPtr->next = theActivation->next;
     if (theActivation->next != NULL) theActivation->next->prev = prevPtr;
  
     /*=======================================================*/
     /* Move the activation and then update its pointers, the */
     /* pointers of the activation following it, and the      */
     /* module pointer to the top activation on the agenda.   */
     /*=======================================================*/
  
     theActivation->next = theModuleItem->agenda;
     theModuleItem->agenda->prev = theActivation;
     theActivation->prev = NULL;
     theModuleItem->agenda = theActivation;
  
     /*=============================*/
     /* Mark the agenda as changed. */
     /*=============================*/
  
     AgendaData(theEnv)->AgendaChanged = true;
  
     return true;
    }
  
  /*******************************************/
  /* DeleteActivation: Removes the specified */
  /*   activation from the agenda.           */
  /*******************************************/
  void DeleteActivation(
    Activation *theActivation)
    {
     RemoveActivation(theActivation->theRule->header.env,theActivation,true,true);
    }
  
  /*************************************************/
  /* DeleteAllActivations: Removes all activations */
  /*   from the agenda of the specified module.    */
  /*************************************************/
  void DeleteAllActivations(
    Defmodule *theModule)
    {
     struct activation *tempPtr, *theActivation;
     struct salienceGroup *theGroup, *tempGroup;
     Environment *theEnv = theModule->header.env;
  
     theActivation = GetDefruleModuleItem(theEnv,NULL)->agenda;
     while (theActivation != NULL)
       {
        tempPtr = theActivation->next;
        RemoveActivation(theEnv,theActivation,true,true);
        theActivation = tempPtr;
       }
  
     theGroup = GetDefruleModuleItem(theEnv,NULL)->groupings;
     while (theGroup != NULL)
       {
        tempGroup = theGroup->next;
        rtn_struct(theEnv,salienceGroup,theGroup);
        theGroup = tempGroup;
       }
   }
  
  /*******************************************************/
  /* DetachActivation: Detaches the specified activation */
  /*   from the list of activations on the Agenda.       */
  /*******************************************************/
  bool DetachActivation(
    Environment *theEnv,
    Activation *theActivation)
    {
     struct defruleModule *theModuleItem;
  
     /*============================*/
     /* A NULL pointer is invalid. */
     /*============================*/
  
     if (theActivation == NULL) SystemError(theEnv,"AGENDA",1);
  
     /*====================================*/
     /* Determine the module of the agenda */
     /* in which the activation is stored. */
     /*====================================*/
  
     theModuleItem = (struct defruleModule *) theActivation->theRule->header.whichModule;
  
     RemoveActivationFromGroup(theEnv,theActivation,theModuleItem);
  
     /*========================================================*/
     /* If the activation is the top activation on the agenda, */
     /* then update the module pointer to agenda.              */
     /*========================================================*/
  
     if (theActivation == theModuleItem->agenda)
       { theModuleItem->agenda = theActivation->next; }
  
     /*==================================================*/
     /* Update the pointers in the preceding activation. */
     /*==================================================*/
  
     if (theActivation->prev != NULL)
       { theActivation->prev->next = theActivation->next; }
  
     /*==================================================*/
     /* Update the pointers in the following activation. */
     /*==================================================*/
  
     if (theActivation->next != NULL)
       { theActivation->next->prev = theActivation->prev; }
  
     /*=================================================*/
     /* Update the pointers in the detached activation. */
     /*=================================================*/
  
     theActivation->prev = NULL;
     theActivation->next = NULL;
  
     /*=============================*/
     /* Mark the agenda as changed. */
     /*=============================*/
  
     AgendaData(theEnv)->AgendaChanged = true;
  
     return true;
    }
  
  /****************************************************************************/
  /* PrintActivation: Prints an activation in a "pretty" format. Salience,    */
  /*   rule name, and the partial match which activated the rule are printed. */
  /****************************************************************************/
  static void PrintActivation(
    Environment *theEnv,
    const char *logicalName,
    Activation *theActivation)
    {
     char printSpace[20];
  
     gensprintf(printSpace,"%-6d ",theActivation->salience);
     WriteString(theEnv,logicalName,printSpace);
     WriteString(theEnv,logicalName,theActivation->theRule->header.name->contents);
     WriteString(theEnv,logicalName,": ");
     PrintPartialMatch(theEnv,logicalName,theActivation->basis);
    }
  
  /*****************************/
  /* Agenda: C access routine  */
  /*   for the agenda command. */
  /*****************************/
  void Agenda(
    Environment *theEnv,
    const char *logicalName,
    Defmodule *theModule)
    {
     ListItemsDriver(theEnv,logicalName,theModule,"activation","activations",
                     (GetNextItemFunction *) GetNextActivation,
                     NULL,
                     (PrintItemFunction *) PrintActivation,
                     NULL);
    }
  
  /*******************************************************************/
  /* RemoveActivation: Returns an activation and its associated data */
  /*   structures to the Memory Manager. Links to other activations  */
  /*   and partial matches may also be updated.                      */
  /*******************************************************************/
  void RemoveActivation(
    Environment *theEnv,
    Activation *theActivation,
    bool updateAgenda,
    bool updateLinks)
    {
     struct defruleModule *theModuleItem;
  
     /*====================================*/
     /* Determine the module of the agenda */
     /* in which the activation is stored. */
     /*====================================*/
  
     theModuleItem = (struct defruleModule *) theActivation->theRule->header.whichModule;
  
     /*=================================*/
     /* Update the agenda if necessary. */
     /*=================================*/
  
     if (updateAgenda == true)
       {
        RemoveActivationFromGroup(theEnv,theActivation,theModuleItem);
  
        /*===============================================*/
        /* Update the pointer links between activations. */
        /*===============================================*/
  
        if (theActivation->prev == NULL)
          {
           theModuleItem->agenda = theModuleItem->agenda->next;
           if (theModuleItem->agenda != NULL) theModuleItem->agenda->prev = NULL;
          }
        else
          {
           theActivation->prev->next = theActivation->next;
           if (theActivation->next != NULL)
             { theActivation->next->prev = theActivation->prev; }
          }
  
        /*===================================*/
        /* Indicate removal of activation if */
        /* activations are being watched.    */
        /*===================================*/
  
  #if DEBUGGING_FUNCTIONS
        if (theActivation->theRule->watchActivation &&
            (! ConstructData(theEnv)->ClearReadyInProgress) &&
            (! ConstructData(theEnv)->ClearInProgress))
          {
           WriteString(theEnv,STDOUT,"<== Activation ");
           PrintActivation(theEnv,STDOUT,theActivation);
           WriteString(theEnv,STDOUT,"\n");
          }
  #endif
  
        /*=============================*/
        /* Mark the agenda as changed. */
        /*=============================*/
  
        AgendaData(theEnv)->AgendaChanged = true;
       }
  
     /*============================================*/
     /* Update join and agenda links if necessary. */
     /*============================================*/
  
     if ((updateLinks == true) && (theActivation->basis != NULL))
       { theActivation->basis->marker = NULL; }
  
     /*================================================*/
     /* Return the activation to the free memory pool. */
     /*================================================*/
  
     AgendaData(theEnv)->NumberOfActivations--;
  
     rtn_struct(theEnv,activation,theActivation);
    }
  
  /******************************/
  /* RemoveActivationFromGroup: */
  /******************************/
  static void RemoveActivationFromGroup(
    Environment *theEnv,
    Activation *theActivation,
    struct defruleModule *theRuleModule)
    {
     struct salienceGroup *theGroup;
  
     theGroup = FindSalienceGroup(theRuleModule,theActivation->salience);
     if (theGroup == NULL) return;
  
     if (theActivation == theGroup->first)
       {
        /*====================================================*/
        /* If the activation is the only remaining activation */
        /* in the group, then the group needs to be removed.  */
        /*====================================================*/
  
        if (theActivation == theGroup->last)
          {
           if (theGroup->prev == NULL)
             { theRuleModule->groupings = theGroup->next; }
           else
             { theGroup->prev->next = theGroup->next; }
  
           if (theGroup->next != NULL)
             { theGroup->next->prev = theGroup->prev; }
  
           rtn_struct(theEnv,salienceGroup,theGroup);
          }
  
        /*======================================================*/
        /* Otherwise this is the first activation in the group, */
        /* but there are other activations which follow.        */
        /*======================================================*/
  
        else
          { theGroup->first = theActivation->next; }
       }
     else
       {
        /*====================================================*/
        /* Otherwise if the activation isn't the first in the */
        /* group, then check to see if it's the last.         */
        /*====================================================*/
  
        if (theActivation == theGroup->last)
          { theGroup->last = theActivation->prev; }
  
        /*==================================================*/
        /* Otherwise the activation is in the middle of the */
        /* group and no first/last updates are needed.      */
        /*==================================================*/
  
        else
          { return; }
       }
    }
  
  /**************************************************************/
  /* AgendaClearFunction: Agenda clear routine for use with the */
  /*   clear command. Resets the current time tag to zero.      */
  /**************************************************************/
  static void AgendaClearFunction(
    Environment *theEnv,
    void *context)
    {
     AgendaData(theEnv)->CurrentTimetag = 1;
    }
  
  /*************************************************/
  /* RemoveAllActivations: Removes all activations */
  /*   from the agenda of the current module.      */
  /*************************************************/
  void RemoveAllActivations(
    Environment *theEnv)
    {
     struct activation *tempPtr, *theActivation;
     struct salienceGroup *theGroup, *tempGroup;
  
     theActivation = GetDefruleModuleItem(theEnv,NULL)->agenda;
     while (theActivation != NULL)
       {
        tempPtr = theActivation->next;
        RemoveActivation(theEnv,theActivation,true,true);
        theActivation = tempPtr;
       }
  
     theGroup = GetDefruleModuleItem(theEnv,NULL)->groupings;
     while (theGroup != NULL)
       {
        tempGroup = theGroup->next;
        rtn_struct(theEnv,salienceGroup,theGroup);
        theGroup = tempGroup;
       }
   }
  
  /**********************************************/
  /* GetAgendaChanged: Returns the value of the */
  /*   boolean flag which indicates whether any */
  /*   changes have been made to the agenda.    */
  /**********************************************/
  bool GetAgendaChanged(
    Environment *theEnv)
    {
     return(AgendaData(theEnv)->AgendaChanged);
    }
  
  /*****************************************************************/
  /* SetAgendaChanged: Sets the value of the boolean flag which    */
  /*   indicates whether any changes have been made to the agenda. */
  /*****************************************************************/
  void SetAgendaChanged(
    Environment *theEnv,
    bool value)
    {
     AgendaData(theEnv)->AgendaChanged = value;
    }
  
  /**********************/
  /* ReorderAllAgendas: */
  /**********************/
  void ReorderAllAgendas(
    Environment *theEnv)
    {
     Defmodule *theModule;
     
     for (theModule = GetNextDefmodule(theEnv,NULL);
          theModule != NULL;
          theModule = GetNextDefmodule(theEnv,theModule))
       { ReorderAgenda(theModule); }
    }
  
  /*******************************************************/
  /* ReorderAgenda: Completely reorders the agenda based */
  /*   on the current conflict resolution strategy.      */
  /*******************************************************/
  void ReorderAgenda(
    Defmodule *theModule)
    {
     struct activation *theActivation, *tempPtr;
     struct defruleModule *theModuleItem;
     struct salienceGroup *theGroup, *tempGroup;
     Environment *theEnv;
  
     if (theModule == NULL) return;
     theEnv = theModule->header.env;
       
     /*=================================*/
     /* Get the list of activations and */
     /* remove them from the agenda.    */
     /*=================================*/
  
     theModuleItem = GetDefruleModuleItem(theEnv,theModule);
     theActivation = theModuleItem->agenda;
     theModuleItem->agenda = NULL;
  
     theGroup = theModuleItem->groupings;
     while (theGroup != NULL)
       {
        tempGroup = theGroup->next;
        rtn_struct(theEnv,salienceGroup,theGroup);
        theGroup = tempGroup;
       }
  
     theModuleItem->groupings = NULL;
  
     /*=========================================*/
     /* Reorder the activations by placing them */
     /* back on the agenda one by one.          */
     /*=========================================*/
  
     while (theActivation != NULL)
       {
        tempPtr = theActivation->next;
        theActivation->next = NULL;
        theActivation->prev = NULL;
        theGroup = ReuseOrCreateSalienceGroup(theEnv,theModuleItem,theActivation->salience);
        PlaceActivation(theEnv,&(theModuleItem->agenda),theActivation,theGroup);
        theActivation = tempPtr;
       }
    }
  
  /****************************************************/
  /* GetNumberOfActivations: Returns the value of the */
  /*   total number of activations on all agendas.    */
  /****************************************************/
  unsigned long GetNumberOfActivations(
    Environment *theEnv)
    {
     return(AgendaData(theEnv)->NumberOfActivations);
    }
  
  /******************************************************/
  /* RefreshCommand: H/L Command for refreshing a rule. */
  /*   Syntax: (refresh <defrule-name>)                 */
  /******************************************************/
  void RefreshCommand(
    Environment *theEnv,
    UDFContext *context,
    UDFValue *returnValue)
    {
     const char *ruleName;
     Defrule *rulePtr;
  
     /*===========================*/
     /* Get the name of the rule. */
     /*===========================*/
  
     ruleName = GetConstructName(context,"refresh","rule name");
     if (ruleName == NULL) return;
  
     /*===============================*/
     /* Determine if the rule exists. */
     /*===============================*/
  
     rulePtr = FindDefrule(theEnv,ruleName);
     if (rulePtr == NULL)
       {
        CantFindItemErrorMessage(theEnv,"defrule",ruleName,true);
        return;
       }
  
     /*===================*/
     /* Refresh the rule. */
     /*===================*/
  
     Refresh(rulePtr);
    }
  
  /***********************************************************/
  /* Refresh: Refreshes a defrule. Activations of the rule   */
  /*   that have already been fired are added to the agenda. */
  /***********************************************************/
  void Refresh(
    Defrule *theRule)
    {
     Defrule *rulePtr;
     struct partialMatch *listOfMatches;
     unsigned long b;
     Environment *theEnv = theRule->header.env;
  
     /*====================================*/
     /* Refresh each disjunct of the rule. */
     /*====================================*/
  
     for (rulePtr = theRule;
          rulePtr != NULL;
          rulePtr = rulePtr->disjunct)
       {
        /*================================*/
        /* Check each partial match that  */
        /* satisfies the LHS of the rule. */
        /*================================*/
  
        for (b = 0; b < rulePtr->lastJoin->leftMemory->size; b++)
          {
           for (listOfMatches = rulePtr->lastJoin->leftMemory->beta[b];
                listOfMatches != NULL;
                listOfMatches = listOfMatches->nextInMemory)
             {
              /*=======================================================*/
              /* If the partial match is associated with an activation */
              /* (which it should always be), then place a new         */
              /* activation on the agenda if this partial matchdoesn't */
              /* have an activation associated with it.                */
              /*=======================================================*/
  
              if (((struct joinNode *) listOfMatches->owner)->ruleToActivate != NULL)
                {
                 if (listOfMatches->marker == NULL)
                   { AddActivation(theEnv,rulePtr,listOfMatches); }
                }
             }
          }
       }
    }
  
  /**********************************************/
  /* RefreshAgendaCommand: H/L access routine   */
  /*   for the refresh-agenda command.          */
  /**********************************************/
  void RefreshAgendaCommand(
    Environment *theEnv,
    UDFContext *context,
    UDFValue *returnValue)
    {
     unsigned int numArgs;
     bool error;
     Defmodule *theModule;
  
     /*==============================================*/
     /* This function can have at most one argument. */
     /*==============================================*/
  
     numArgs = UDFArgumentCount(context);
  
     /*===============================================================*/
     /* If a module name is specified, then the agenda of that module */
     /* is refreshed. Otherwise, the agenda of the current module is  */
     /* refreshed.                                                    */
     /*===============================================================*/
  
     if (numArgs == 1)
       {
        theModule = GetModuleName(context,1,&error);
        if (error) return;
       }
     else
       { theModule = GetCurrentModule(theEnv); }
  
     /*===============================================*/
     /* Refresh the agenda of the appropriate module. */
     /*===============================================*/
  
     if (theModule == NULL)
       { RefreshAllAgendas(theEnv); }
     else
       { RefreshAgenda(theModule); }
    }
  
  /**********************/
  /* RefreshAllAgendas: */
  /**********************/
  void RefreshAllAgendas(
    Environment *theEnv)
    {
    Defmodule *theModule;
    
    for (theModule = GetNextDefmodule(theEnv,NULL);
         theModule != NULL;
         theModule = GetNextDefmodule(theEnv,theModule))
       { RefreshAgenda(theModule); }
    }
  
  /*************************************/
  /* RefreshAgenda: C access routine   */
  /*   for the refresh-agenda command. */
  /*************************************/
  void RefreshAgenda(
    Defmodule *theModule)
    {
     Activation *theActivation;
     SalienceEvaluationType oldValue;
     Environment *theEnv;
     
     if (theModule == NULL) return;
     theEnv = theModule->header.env;
     
     /*=====================================*/
     /* If embedded, clear the error flags. */
     /*=====================================*/
     
     if (EvaluationData(theEnv)->CurrentExpression == NULL)
       { ResetErrorFlags(theEnv); }
  
     /*==========================*/
     /* Save the current module. */
     /*==========================*/
  
     SaveCurrentModule(theEnv);
  
     /*=======================================================*/
     /* Remember the current setting for salience evaluation. */
     /* To perform the refresh, the when activated setting is */
     /* used to recompute the salience values.                */
     /*=======================================================*/
  
     oldValue = GetSalienceEvaluation(theEnv);
     SetSalienceEvaluation(theEnv,WHEN_ACTIVATED);
  
     /*============================*/
     /* Change the current module. */
     /*============================*/
  
     SetCurrentModule(theEnv,theModule);
  
     /*================================================================*/
     /* Recompute the salience values for the current module's agenda. */
     /*================================================================*/
  
     for (theActivation = GetNextActivation(theEnv,NULL);
          theActivation != NULL;
          theActivation = GetNextActivation(theEnv,theActivation))
       { theActivation->salience = EvaluateSalience(theEnv,theActivation->theRule); }
  
     /*======================================================*/
     /* Reorder the agenda based on the new salience values. */
     /*======================================================*/
  
     ReorderAgenda(theModule);
  
     /*==========================================*/
     /* Restore the salience evaluation setting. */
     /*==========================================*/
  
     SetSalienceEvaluation(theEnv,oldValue);
  
     /*=============================*/
     /* Restore the current module. */
     /*=============================*/
  
     RestoreCurrentModule(theEnv);
    }
  
  /*********************************************************/
  /* SetSalienceEvaluationCommand: H/L Command for setting */
  /*   the salience evaluation behavior.                   */
  /*   Syntax: (set-salience-evaluation-behavior <symbol>) */
  /*********************************************************/
  void SetSalienceEvaluationCommand(
    Environment *theEnv,
    UDFContext *context,
    UDFValue *returnValue)
    {
     UDFValue value;
     const char *argument;
     const char *oldValue;
  
     /*==================================================*/
     /* Get the current setting for salience evaluation. */
     /*==================================================*/
  
     oldValue = SalienceEvaluationName(GetSalienceEvaluation(theEnv));
  
     /*=========================================*/
     /* This function expects a single argument */
     /* which must be a symbol.                 */
     /*=========================================*/
  
     if (! UDFFirstArgument(context,SYMBOL_BIT,&value))
       { return; }
  
     /*=============================================================*/
     /* The allowed symbols to pass as an argument to this function */
     /* are when-defined, when-activated, and every-cycle.          */
     /*=============================================================*/
  
     argument = value.lexemeValue->contents;
  
     if (strcmp(argument,"when-defined") == 0)
       { SetSalienceEvaluation(theEnv,WHEN_DEFINED); }
     else if (strcmp(argument,"when-activated") == 0)
       { SetSalienceEvaluation(theEnv,WHEN_ACTIVATED); }
     else if (strcmp(argument,"every-cycle") == 0)
       { SetSalienceEvaluation(theEnv,EVERY_CYCLE); }
     else
       {
        UDFInvalidArgumentMessage(context,
           "symbol with value when-defined, when-activated, or every-cycle");
        returnValue->lexemeValue = CreateSymbol(theEnv,oldValue);
        return;
       }
  
     /*=================================================*/
     /* Return the old setting for salience evaluation. */
     /*=================================================*/
  
     returnValue->lexemeValue = CreateSymbol(theEnv,oldValue);
    }
  
  /*********************************************************/
  /* GetSalienceEvaluationCommand: H/L Command for getting */
  /*   the salience evaluation behavior.                   */
  /*   Syntax: (get-salience-evaluation-behavior)          */
  /*********************************************************/
  void GetSalienceEvaluationCommand(
    Environment *theEnv,
    UDFContext *context,
    UDFValue *returnValue)
    {
     returnValue->lexemeValue = CreateSymbol(theEnv,SalienceEvaluationName(GetSalienceEvaluation(theEnv)));
    }
  
  /*****************************************************************/
  /* SalienceEvaluationName: Given the integer value corresponding */
  /*   to a specified salience evaluation behavior, returns a      */
  /*   character string of the behavior's name.                    */
  /*****************************************************************/
  static const char *SalienceEvaluationName(
    SalienceEvaluationType strategy)
    {
     const char *sname;
  
     switch (strategy)
       {
        case WHEN_DEFINED:
          sname = "when-defined";
          break;
        case WHEN_ACTIVATED:
          sname = "when-activated";
          break;
        case EVERY_CYCLE:
          sname = "every-cycle";
          break;
        default:
          sname = "unknown";
          break;
       }
  
     return sname;
    }
  
  /*******************************************************/
  /* GetSalienceEvaluation: Returns the value of current */
  /*  type of salience evaluation (e.g., when defined,   */
  /*  when activated, or every cycle).                   */
  /*******************************************************/
  SalienceEvaluationType GetSalienceEvaluation(
    Environment *theEnv)
    {
     return AgendaData(theEnv)->SalienceEvaluation;
    }
  
  /**********************************************/
  /* SetSalienceEvaluation: Sets the value of   */
  /*   the current type of salience evaluation. */
  /**********************************************/
  SalienceEvaluationType SetSalienceEvaluation(
    Environment *theEnv,
    SalienceEvaluationType value)
    {
     SalienceEvaluationType ov;
  
     ov = AgendaData(theEnv)->SalienceEvaluation;
     AgendaData(theEnv)->SalienceEvaluation = value;
     return ov;
    }
  
  /*****************************************************************/
  /* EvaluateSalience: Returns the salience value of the specified */
  /*   defrule. If salience evaluation is currently set to         */
  /*   when-defined, then the current value of the rule's salience */
  /*   is returned. Otherwise the salience expression associated   */
  /*   with the rule is reevaluated, the value is stored as the    */
  /*   rule's current salience, and it is then returned.           */
  /*****************************************************************/
  static int EvaluateSalience(
    Environment *theEnv,
    Defrule *theDefrule)
    {
     UDFValue salienceValue;
     long long salience;
  
    /*==================================================*/
    /* If saliences are only being evaluated when rules */
    /* are defined, then just return the last salience  */
    /* value evaluated for the rule.                    */
    /*==================================================*/
  
    if (GetSalienceEvaluation(theEnv) == WHEN_DEFINED)
      { return theDefrule->salience; }
  
    /*=================================================================*/
    /* If the rule's salience value was defined as an integer constant */
    /* (i.e., not an expression or global variable which could change  */
    /* on reevaluation), then just return the salience value computed  */
    /* for the rule when it was defined.                               */
    /*=================================================================*/
  
    if (theDefrule->dynamicSalience == NULL) return theDefrule->salience;
  
    /*====================================================*/
    /* Reevaluate the rule's salience. If an error occurs */
    /* during evaluation, print an error message.         */
    /*====================================================*/
  
    SetEvaluationError(theEnv,false);
    if (EvaluateExpression(theEnv,theDefrule->dynamicSalience,&salienceValue))
      {
       SalienceInformationError(theEnv,"defrule",theDefrule->header.name->contents);
       return theDefrule->salience;
      }
  
    /*========================================*/
    /* The salience value must be an integer. */
    /*========================================*/
  
    if (salienceValue.header->type != INTEGER_TYPE)
      {
       SalienceNonIntegerError(theEnv);
       SalienceInformationError(theEnv,"defrule",theDefrule->header.name->contents);
       SetEvaluationError(theEnv,true);
       return theDefrule->salience;
      }
  
    /*==========================================*/
    /* The salience value must fall between the */
    /* minimum and maximum allowed values.      */
    /*==========================================*/
  
    salience = salienceValue.integerValue->contents;
  
    if ((salience > MAX_DEFRULE_SALIENCE) || (salience < MIN_DEFRULE_SALIENCE))
      {
       SalienceRangeError(theEnv,MIN_DEFRULE_SALIENCE,MAX_DEFRULE_SALIENCE);
       SetEvaluationError(theEnv,true);
       SalienceInformationError(theEnv,"defrule",theDefrule->header.name->contents);
       return theDefrule->salience;
      }
  
    /*===================================*/
    /* Store the new salience value with */
    /* the rule and return this value.   */
    /*===================================*/
  
    theDefrule->salience = (int) salience;
    return theDefrule->salience;
   }
  
  #if DEBUGGING_FUNCTIONS
  
  /***********************************************/
  /* AgendaCommand: Prints out the agenda of the */
  /*   rules that are ready to fire.             */
  /*   Syntax: (agenda)                          */
  /***********************************************/
  void AgendaCommand(
    Environment *theEnv,
    UDFContext *context,
    UDFValue *returnValue)
    {
     unsigned int numArgs;
     bool error;
     Defmodule *theModule;
  
     /*===============================================================*/
     /* If a module name is specified, then the agenda of that module */
     /* is displayed. Otherwise, the agenda of the current module is  */
     /* displayed.                                                    */
     /*===============================================================*/
  
     numArgs = UDFArgumentCount(context);
     if (numArgs == 1)
       {
        theModule = GetModuleName(context,1,&error);
        if (error) return;
       }
     else
       { theModule = GetCurrentModule(theEnv); }
  
     /*===============================================*/
     /* Display the agenda of the appropriate module. */
     /*===============================================*/
  
     Agenda(theEnv,STDOUT,theModule);
    }
  
  #endif /* DEBUGGING_FUNCTIONS */
  
  #endif /* DEFRULE_CONSTRUCT */
  
  