/* 
 * $RCSfile: upi_defaults.c,v $
 *
 * x-kernel v3.3
 *
 * Copyright (c) 1993,1991,1990,1996  Arizona Board of Regents
 *
 * $Log: upi_defaults.c,v $
 * Revision 1.2  1996/01/29 19:57:51  slm
 * Updated copyright and version.
 *
 * Revision 1.1  1995/07/28  21:41:44  slm
 * Initial revision
 *
 * Revision 1.15.1.3  1994/12/02  17:56:38  hkaram
 * Changed to new mapResolve
 *
 * Revision 1.15.1.2  1994/11/22  20:53:55  hkaram
 * Added casts to MapResolve calls
 *
 * Revision 1.15.1.1  1994/10/27  20:52:20  hkaram
 * New branch
 *
 * Revision 1.15  1994/10/06  02:20:39  davidm
 * (defaultOpenDisableAll, findHlpEnable): simplified by taking advantage
 * 	of v3.2 mapForEach() semantics (i.e., MFE_REMOVE).
 *
 * Revision 1.14  1994/03/13  03:34:42  davidm
 * Pointers are now printed as "%lx" and cast to (u_long).
 *
 * Revision 1.13  1993/12/13  20:27:49  menze
 * Modifications from UMass:
 *
 *   [ 93/11/12          yates ]
 *   Changed casting of Map manager calls so that the header file does it all.
 */

#include "xkernel.h"

extern int traceprotocol;
int        traceprotdef = 0;

#define savePart(pxx, spxx) \
	bcopy((char *)(pxx), (char *)(spxx), sizeof(Part) * partLength(pxx))

#define restorePart(pxx, spxx) \
	bcopy((char *)(spxx), (char *)(pxx), sizeof(Part) * partLength(pxx))

/* Check for a valid participant list */
#define partCheck(pxx, name, retval) {                                 \
    if (!(pxx) || partLength(pxx) < 1) {                               \
	xTrace1(protdef, TR_ERRORS, "xDefault %s -- bad participants", \
		(name));                                               \
	return (retval);                                               \
    }                                                                  \
}

#ifdef __STDC__

static int      findHlpEnable(void *, void *, void *);
static XkReturn llpOpenDisable(Protl, Protl, Protl, Part *, Protl *, int);

#else

static XkReturn llpOpenDisable();

#endif

XkReturn
defaultOpenEnable(map, hlp, hlpType, key)
Map   map;
Protl hlp, hlpType;
void  *key;
{
    Enable *e;
    
    xAssert(map);
    xAssert(key);
    xAssert(xIsProtl(hlp));
    xAssert(xIsProtl(hlpType));
    if (mapResolve(map, (char *)key, (void **)&e) == XK_FAILURE) {
	xTrace0(protdef, TR_MORE_EVENTS,
		"openenable -- creating new enable obj");
	e = X_NEW(Enable);
	e->rcnt = 1;
	e->hlp = hlp;
	e->hlpType = hlpType;
	e->binding =  mapBind(map, key, e);
	if (e->binding == ERR_BIND) {
	    xTrace0(protdef, TR_ERRORS, "openenable -- binding failed!");
	    xFree((char *)e);
	    return XK_FAILURE;
	}
    }
    else {
	xTrace0(protdef, TR_MORE_EVENTS, "openenable -- obj exists");
	if (e->hlp != hlp || e->hlpType != hlpType) {
	    xTrace0(protdef, TR_SOFT_ERRORS, "openenable -- hlp mismatch");
	    xTrace4(protdef, TR_SOFT_ERRORS, 
		   "(existing rcv: %lx  type %lx, paramater rcv: %lx  type %lx",
		    (u_long)e->hlp, (u_long)e->hlpType,
		    (u_long)hlp, (u_long)hlpType);
	    return XK_FAILURE;
	}
	e->rcnt++;
	xTrace1(protdef, TR_MORE_EVENTS,
		"openenable -- increasing enable obj ref count to %d",
		e->rcnt);
    }
    return XK_SUCCESS;
}

XkReturn
defaultOpenDisable(map, hlp, hlpType, key)
Map   map;
Protl hlp, hlpType;
void  *key;
{
    Enable *e;
    
    xAssert(map);
    xAssert(key);
    xAssert(xIsProtl(hlp));
    xAssert(xIsProtl(hlpType));
    if (mapResolve(map, (char *)key, (void **)&e) == XK_FAILURE) {
	xTrace0(protdef, TR_SOFT_ERRORS, "opendisable -- no enable obj found");
	return XK_FAILURE;
    }
    if (e->hlp != hlp || e->hlpType != hlpType) {
	    xTrace0(protdef, TR_SOFT_ERRORS, "opendisable -- hlp mismatch");
	    xTrace4(protdef, TR_SOFT_ERRORS, 
		   "(existing rcv: %lx  type %lx, paramater rcv: %lx  type %lx",
		    (u_long)e->hlp, (u_long)e->hlpType,
		    (u_long)hlp, (u_long)hlpType);
	return XK_FAILURE;
    }
    e->rcnt--;
    xTrace1(protdef, TR_MORE_EVENTS,
	    "opendisable -- reducing enable obj ref count to %d", e->rcnt);
    if (e->rcnt == 0) {
	xTrace0(protdef, TR_MORE_EVENTS,
		"opendisable -- removing enable object");
	mapRemoveBinding(map, e->binding);
	xFree((char *)e);
    }
    return XK_SUCCESS;
}

typedef struct {
    Protl          hlp;
    DisableAllFunc callback;
} FindStuff;

static int
findHlpEnable(key, val, arg)
void *key, *val, *arg;
{
    FindStuff *fs = (FindStuff *)arg;
    Enable    *e = (Enable *)val;

    if (e->hlp == fs->hlp) {
	xTrace2(protdef, TR_ALWAYS,
		"defaultOpenDisableAll removes binding (rcv %s, type %s)",
		e->hlp->fullName, e->hlpType->fullName);
	if (fs->callback)
	    (*fs->callback)(key, e);
	xFree((char *)e);
	return MFE_REMOVE | MFE_CONTINUE;
    }
    else
	return MFE_CONTINUE;
}

XkReturn
defaultOpenDisableAll(map, hlp, f)
Map            map;
Protl          hlp;
DisableAllFunc f;
{
    FindStuff fs;

    xTrace0(protdef, TR_FUNCTIONAL_TRACE, "openDisableAll");
    fs.hlp   = hlp;
    fs.callback = f;
    mapForEach(map, findHlpEnable, &fs);
    return XK_SUCCESS;
}

XkReturn
defaultVirtualOpenEnable(self, map, hlp, hlpType, llp, participants)
Map   map;
Protl self, hlp, hlpType, *llp;
Part  *participants;
{
    Part     *sp;
    int      i;
    XkReturn xkr;
    
    xAssert(map);
    xAssert(xIsProtl(self));
    xAssert(xIsProtl(hlp));
    xAssert(xIsProtl(hlpType));
    xTrace0(protdef, TR_MAJOR_EVENTS, "default virtual open enable");
    partCheck(participants, "openEnable", XK_FAILURE);
    if (defaultOpenEnable(map, hlp, hlpType, (void *)&hlpType) ==
	    XK_FAILURE) {
	return XK_FAILURE;
    }
    xkr = XK_SUCCESS;
    sp = (Part *)xMalloc(sizeof(Part) * partLength(participants));
    savePart(participants, sp);
    for (i = 0; llp[i]; i++) {
	restorePart(participants, sp);
	if (!xIsProtl(llp[i]) ||
	    xOpenEnable(self, hlpType, llp[i], participants) == XK_FAILURE) {
	    xTrace1(protdef, TR_SOFT_ERRORS,
		    "could not openEnable llp %s", llp[i]->name);
	    llpOpenDisable(self, hlp, hlpType, sp, llp, i);
	    xkr = XK_FAILURE;
	    break;
	}
    }
    xFree((char *)sp);
    return xkr;
}

static XkReturn
llpOpenDisable(self, hlp, hlpType, participants, llp, i)
Protl self, hlp, hlpType, *llp;
Part  *participants;
int   i;
{
    Part     *sp;
    XkReturn rv = XK_SUCCESS;

    sp = (Part *)xMalloc(sizeof(Part) * partLength(participants));
    savePart(participants, sp);
    for (i--; i >= 0; i--) {
	restorePart(participants, sp);
	if (!xIsProtl(llp[i]) ||
	    xOpenDisable(hlp, hlpType, llp[i], participants) == XK_FAILURE) {
	    xTrace1(protdef, TR_SOFT_ERRORS,
		    "llpOpenDisable could not openDisable llp %s",
		    llp[i]->name);
	    rv = XK_FAILURE;
	}
    }
    xFree((char *)sp);
    return rv;
}

XkReturn
defaultVirtualOpenDisable(self, map, hlp, hlpType, llp, participants)
Map   map;
Protl self, hlp, hlpType, *llp;
Part  *participants;
{
    int i;

    xAssert(map);
    xAssert(xIsProtl(self));
    xAssert(xIsProtl(hlp));
    xAssert(xIsProtl(hlpType));
    xTrace0(protdef, TR_MAJOR_EVENTS, "default virtual open disable");
    if (defaultOpenDisable(map, hlp, hlpType, (void *)&hlpType) ==
	    XK_FAILURE) {
	return XK_FAILURE;
    }
    for (i = 0; llp[i]; i++) ;
    return llpOpenDisable(self, hlp, hlpType, participants, llp, i);
}
