

/*
 *  GRAPH.C
 */

#define GRAPH	struct _GRAPH
#define GNODE	struct _GNODE
#define GCTRL	struct _GCTRL

/*
 *  Flags field:    The upper 4 bits are copied to the lower 4 bits after
 *		    the flags are processed, allowing for 'temporary'
 *		    conditions.
 *
 *  FL_SKIP	    Propogate a skip condition.  As soon as the next node
 *		    is ready to begin processing, cause it not to run
 *		    its function and propogate the FL_SKIP to all of its
 *		    children, and all of their children, etc...
 *
 *  FL_SRC	    Infinite source, this arc is always ready with the
 *		    given value.
 */

GLINK {
    MINNODE FNode;	/*  link from, list based at node	*/
    MINNODE TNode;	/*  link to, list based at node 	*/
    GNODE   *FGNode;	/*  from this node			*/
    GNODE   *TGNode;	/*  to this node			*/
    long    FromId;	/*  Identify value slot for source	*/
    long    ToId;	/*  Identify value slot for destination */
    long    Value;	/*  value to pass to 'to' node          */
    ubyte   Ready;	/*  value pending, else no value pending*/
    ubyte   Flags;	/*  FL_SKIP,FL_NULL,FL_SRC		*/
    ubyte   XFlags;	/*  XL_READ				*/
    ubyte   filler;
};

GNODE {
    MINNODE GNode;	/*  master list node			*/
    GRAPH   *Graph;	/*  owning graph			*/
    APTR    Func;	/*  Function				*/
    long    Arg;	/*  Argument				*/
    short   WaitCnt;	/*  # parents who are not ready 	*/
    MINLIST ChildList;	/*  list of children			*/
    MINLIST ParentList; /*  list of parents			*/
    MINLIST WakeUpList; /*  WakeUp tasks waiting for an ARC to clear	*/
};

GRAPH {
    MINLIST GNodes;	/*  list of all graphs in node	*/
    long    A45[2];	/*  global base registers	*/
    long    UsrLen;
};

GRAPH *
AllocGraph(usrdatalen)
{
    GRAPH *graph = AllocMem(sizeof(GRAPH), MEMF_PUBLIC|MEMF_CLEAR);
    NewList(&graph->GNodes);
    graph->a45[0] = A4;
    graph->a45[1] = A5;
    graph->UsrLen = usrdatalen;
}

GNODE *
AllocGraphNode(graph, func, arg, usrdata/NULL)
GRAPH *graph;
long arg;
{
    GNODE *gnode = AllocMem(sizeof(GNODE), MEMF_PUBLIC|MEMF_CLEAR);
    AddTail(&graph->GNodes, &gnode->GNode);
    gnode->Graph = graph;
    gnode->Func  = func;
    gnode->Arg	 = arg;
    NewList(&gnode->ChildList);
    NewList(&gnode->ParentList);
    NewList(&gnode->WakeUpList);
}

/*
 *  Remove all arcs and free a graph node
 */

FreeGraphNode(gnode)
GNODE *gnode;
{
    Forbid();
    Remove(gnode);
    while (glink = GetHead(&gnode->ChildList))
	RemGraphArc(gnode, glink->FGTNode);
    while (glink = GetHeadOff(&gnode->ParentList, 8))
	RemGraphArc(glink->FGFNode, gnode);
    Permit();
    FreeMem(gnode, sizeof(GNODE));
};

FreeGraph(graph)
GRAPH *graph;
{
    Forbid();
    while (gnode = GetHead(&graph->GNodes))
	FreeGraphNode(gnode);
    Permit();
    FreeMem(graph, sizeof(GRAPH));
}

/*
 *  Set the user data for a given node.  The data is copied into an
 *  equivalent buffer for the node.
 */

SetUserData(gnode, usrdata/NULL)
GNODE *gnode;
{
}

/*
 *  Add a directed arc to the graph.  Set the arc to 'not ready' and
 *  increment the child node's WaitCnt
 */

AddGraphArc(from, to)
GNODE *from, *to;
{
    GLINK *glink = AllocMem(sizeof(GLINK), MEMF_PUBLIC);

    Forbid();
    AddTail(&from->ChildList, &glink->FNode);
    AddTail(&to->ParentList, &glink->TNode);
    glink->FGNode = from;
    glink->FTNode = to;
    ++to->WaitCnt;
    Permit();
}

chklink(glink, gnode)
GLINK *glink;
GNODE *gnode;
{
    if (glink->TGNode == gnode)
	return(glink);
    return(NULL);
}

RemGraphArc(from, to)
GNODE *from, *to;
{
    GLINK *glink;

    Forbid();
    if (glink = SearchFwdNode(GetHead(&from->ChildList), chklink, 0, to)) {
	Remove(&glink->FNode);
	Remove(&glink->TNode);
	if (!glink->Ready) {
	    if (--to->WaitCnt == 0 && GetHeadOff(&to->ParentList, 8))
		GHandler(to);
	}
    }
    Permit();
}

SetGNodeFunc(gnode, func)
GNODE *gnode;
APTR func;
{
    gnode->Func = func;
}

SetGNodeArg(gnode, arg)
GNODE *gnode;
{
    gnode->Arg = arg;
}

APTR
GetGNodeFunc(gnode)
GNODE *gnode;
{
    return(gnode->Func);
}

long
GetGNodeArg(gnode)
GNODE *gnode;
{
    return(gnode->Arg);
}

/*
 *  This function may ONLY be called by a node function, and retrieves
 *  the value from one of the parent arcs (arcs comming in).  When the
 *  node function returns, any remaining unread parent arc's values will
 *  be discarded.
 */

long
GetArcValue(ToId)
{

}

/*
 *  This function may ONLY be called by a node function, and sets the
 *  result value to one of its child arcs (arcs going out).  When the
 *  node function returns, any remaining unset child arc's values will
 *  be SKIPd.
 *
 *  NOTE!  This function will block on child nodes which have yet to
 *  read the previous value with GetArcValue() or are still running.
 */

SetArcValue(gnode, FromId, flags)
GNODE *gnode;
{
}

/*
 *  This function may be called by anybody, and forces a value into an
 *  arc.  This function is usually used to 'prime' a graph.
 */

PrimeArc(from, to, value)
GNODE *from, *to;
{
}

/*
 *  GetGraph()
 *
 *  Load the two buffers with entries corrosponding to the graph.  arcen
 *  and nodeen initially contain the number of ARC and NODE structure
 *  entries that have been allocated.  These variables will hold the
 *  actual number of ARC and NODE entries in the graph regardless of
 *  whether the operation succeeds.
 *
 *  0 is returned if the operation does not succeed, 1 if it does.
 *  The size of the node structure depends on the size of attached
 *  user information.
 *
 *  ARC structure:  two words / entry, representing an arc (from, to),
 *		    where each word is an index (by entry #) into nodebuf.
 *		    i.e. 0, 1, 2 ... even if usrdatalen is 0.
 *
 *  NODE structure: any user data that has been applied to the node, as
 *		    specified by AllocGraphNode().
 */

GetArcs(graph, arcbuf, &arcen, nodebuf, &nodeen)
GRAPH *graph;
{


}

