/*
 * multi_select.c
 *
 * x-kernel v3.3
 *
 * Copyright (c) 1993,1991,1990,1996  Arizona Board of Regents
 *
 * $Revision: 1.2 $
 * $Date: 1996/01/29 22:25:04 $
 */

/* 
 * multi_select -- The multi-select protocol determines the upper protocol ID
 * at open/openenable time by pulling the ID number off the participant stack.
 */

#include "xkernel.h"
#include "mselect.h"
#include "select_i.h"

#ifdef __STDC__

static int      extractId(Part *, long *);
static void     getProtFuncs(Protl);
static int      mselectControlSessn(Sessn, int, char *, int);
static Part     *mselectGetParticipants(Sessn);
static Sessn    mselectOpen(Protl, Protl, Protl, Part *);
static XkReturn mselectOpenDisable(Protl, Protl, Protl, Part *);
static XkReturn mselectOpenEnable(Protl, Protl, Protl, Part *);

#else

static int      extractId();
static void     getProtFuncs();
static int      mselectControlSessn();
static Part     *mselectGetParticipants();
static Sessn    mselectOpen();
static XkReturn mselectOpenDisable();
static XkReturn mselectOpenEnable();

#endif /* __STDC__ */

void
mselect_init(self)
Protl self;
{
    xTrace0(selectp, TR_GROSS_EVENTS, "MSELECT init");
    if (!xIsProtl(xGetProtlDown(self, 0))) {
	xTrace0(selectp, TR_ERRORS,
		"SELECT could not find down protocol -- not initializing");
	return;
    }
    getProtFuncs(self);
    selectCommonInit(self);
}

static int
extractId(p, id)
Part *p;
long *id;
{
    long *n;

    if (!p || partLength(p) < 1) {
	xTrace0(selectp, TR_SOFT_ERRORS, "select extractId -- bad participant");
	return -1;
    }
    n = (long *)partPop(*p);
    if (n == 0 || n == (long *)-1) {
	xTrace0(selectp, TR_SOFT_ERRORS,
		"select extractId -- bad participant stack");
	return -1;
    }
    xTrace1(selectp, TR_MORE_EVENTS, "select extractID got id == %d", *n);
    *id = *n;
    return 0;
}

static Sessn
mselectOpen(self, hlp, hlpType, p)
Protl self, hlp, hlpType;
Part  *p;
{
    long  hlpNum;
    Sessn s;

    xTrace0(selectp, TR_MAJOR_EVENTS, "MSELECT open");
    if (extractId(p, &hlpNum))
	return ERR_SESSN;
    s = selectCommonOpen(self, hlp, hlpType, p, hlpNum);
    if (xIsSessn(s)) {
	s->controlsessn    = mselectControlSessn;
	s->getparticipants = mselectGetParticipants;
    }
    return s;
}

static int
mselectControlSessn(self, op, buf, len)
Sessn self;
int   op, len;
char  *buf;
{
    return selectCommonControlSessn(self, op, buf, len);
}
  
static Part *
mselectGetParticipants(self)
Sessn self;
{
    Part   *p;
    SState *state = (SState *)self->state;

    p = xGetParticipants(xGetSessnDown(self, 0));
    if (!p)
	return NULL;
    partPush(*p, &state->hdr.id, sizeof(long));
    return p;
}

static XkReturn
mselectOpenEnable(self, hlp, hlpType, p)
Protl self, hlp, hlpType;
Part  *p;
{
    long hlpNum;

    xTrace0(selectp, TR_MAJOR_EVENTS, "MSELECT openEnable");
    if (extractId(p, &hlpNum))
	return XK_FAILURE;
    if (selectCommonOpenEnable(self, hlp, hlpType, p, hlpNum) == XK_SUCCESS)
	return xOpenEnable(self, self, xGetProtlDown(self, 0), p);
    else
	return XK_FAILURE;
}

static XkReturn
mselectOpenDisable(self, hlp, hlpType, p)
Protl self, hlp, hlpType;
Part  *p;
{
    long hlpNum;

    xTrace0(selectp, TR_MAJOR_EVENTS, "MSELECT openDisable");
    if (extractId(p, &hlpNum))
	return XK_FAILURE;
    if (selectCommonOpenDisable(self, hlp, hlpType, p, hlpNum) == XK_SUCCESS)
	return xOpenDisable(self, self, xGetProtlDown(self, 0), p);
    else
	return XK_FAILURE;
}

static void
getProtFuncs(p)
Protl 	p;
{
    p->controlprotl = selectControlProtl;
    p->open         = mselectOpen;
    p->openenable   = mselectOpenEnable;
    p->opendisable  = mselectOpenDisable;
    p->calldemux    = selectCallDemux;
    p->demux        = selectDemux;
}
