/*
 * BryLib - a mishmash of useful library routines
 * Copyright (C) 1992 Bryan Ford
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * Reminder list handling
 * $Id$
 *
 * $Log$
 *
 */
#ifndef BRY_REMIND_H
#define BRY_REMIND_H

#ifndef BRY_CLIST_H
#include "bry/clist.h"
#endif


/* One of these structures "remembers" a function to be called later. */
struct RemindNode
  {
    struct CNode node;                  /* Circular-list node */
    long (*callfunc)(long globaldata,long localdata); /* What to call */
    long localdata;
    short sequence;                     /* Lower-sequence nodes get called first */
    char inlist;                        /* Nonzero if this node is linked into a CallList */
    char reserved;
  };


/* Handy macro to declare preinitialized instances of RemindNodes */
#define remind_decl(name,func,seq) struct RemindNode name = {{0},func,seq}


/* We don't need any fancy structures here--just a normal circular list. */
#define RemindList        CList


/* Initializing a CallList is also very simple. */
#define remind_initlist(calllistptr) clist_init(calllistptr)


/* Add a RemindNode to a RemindList.  Only adds if node->inlist is zero
   (i.e. if the node is not already on the list).  Sets node->inlist to
   nonzero.  This function keeps the list in order of sequence, so
   when the list is traversed by one of the functions below the nodes
   will be called in order from lowest sequence number to highest.
   Nodes with the same sequence numbers are called in first-in, first-out
   (i.e. first-added, first called) order.  */
void remind_add(struct RemindList *list,struct RemindNode *node);


/* Remove a RemindNode from a RemindList.  Only removes if node->inlist
   is nonzero (i.e. if the node is on a list).  Sets node->inlist to zero.  */
void remind_rem(struct RemindNode *node);
#define remind_remove(node) remind_rem(node)


/* Call all the nodes on a RemindList non-destructively (leaving the nodes
   in place as it goes along).  Note that though this function does not
   remove any nodes, the functions it calls through the RemindNodes may
   remove their own nodes.  callfuncs must return 0 to keep going through
   list; nonzero causes remind_call to stop and return that value
   immediately.  Returns -1 if the list was empty; 0 if all nodes processed
   successfully.

   While callfuncs may remove their own nodes (the nodes that were used
   to call them), they may not remove any other nodes on the list being
   traversed.  They may add new nodes to the list being traversed, but
   whether or not that node will get called on this particular run is
   unspecified.  */
long remind_call(struct RemindList *l,long globaldata);


/* Extension to remind_call: afterfunc is called after each callfunc is
   called.  It is passed the return code of the callfunc that was just
   called, and its return code is used in place of the callfunc's return
   code to determine whether to keep going in the list or stop.  */
long remind_callext(struct RemindList *l,long globaldata,
  long (*afterfunc)(struct RemindNode *node,long retcode,long globaldata));


/* Call the nodes on a RemindList destructively, removing each node as it
   progresses.  Returncode conventions work the same way as remind_call. Each
   node is removed before its callfunc is called, so callfuncs may add their
   own nodes back onto the list; the node will be called again later during
   this same traversal, according to sequence.  (Be careful not to create
   infinite loops.)  For that matter, callfuncs can safely add or delete any
   nodes (their own or others) from the list while inside a remind_callrem.  */
long remind_callrem(struct RemindList *l,long globaldata);


/* Variation of remind_callrem with the afterfunc feature; differences are
   the same as with remind_callext.  */
long remind_callremext(struct RemindList *l,long globaldata,
  long (*afterfunc)(struct RemindNode *node,long retcode,long globaldata));


#endif