/* 
 * $Id: c_main.c,v 1.1 91/05/03 03:01:53 qjb Exp Locker: qjb $
 * $Source: /afs/athena.mit.edu/astaff/project/qcs/src/RCS/c_main.c,v $
 * $Author: qjb $
 *
 * This is the main source file for the client side of the qcs library.
 */

#if !defined(lint) && !defined(SABER) || defined(RCS_HDRS)
static char *rcsid = "$Id: c_main.c,v 1.1 91/05/03 03:01:53 qjb Exp Locker: qjb $";
#endif /* !lint && !SABER || RCS_HDRS */


#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <qrpc.h>

#include "qcs.h"
#include "qcs_private.h"
#include "qcs_qrpc.h"

void qcs_setup_client_params(qcs_client_params *params, char *aname,
			     char *host, char *service, int port, int ui_fd, 
			     qcs_print_handler handle_error,
			     qcs_print_handler handle_notify,
			     qcs_print_handler handle_message,
			     qcs_select_handler handle_periodic,
			     qcs_select_handler handle_input,
			     qcs_select_handler handle_userqrpc,
			     qcs_comp_handler handle_completion)
{
    qrpc_init_tcp_client_info(&(params->client_info), host, service, port);
    bzero(params->aname, ANAME_SZ + 1);
    strncpy(params->aname, aname, ANAME_SZ);
    params->handle_error = handle_error;
    params->handle_notify = handle_notify;
    params->handle_message = handle_message;
    params->handle_periodic = handle_periodic;
    params->handle_input = handle_input;
    params->handle_completion = handle_completion;
    params->handle_userqrpc = handle_userqrpc;
    params->ui_fd = ui_fd;
}


qcs_error_t qcs_connect(qcs_t *qcs, qcs_client_params *params)
{
    qrpc_error_t status;
    qrpc_t qrpc;

    qcs->params = params;

    if (qcs->qrpc)
	qrpc_destroy(&(qcs->qrpc));

    if (status = qrpc_create_client(&qrpc, &(params->client_info), 
				    qcsi_opcodes, QCS_MINV, QCS_MAXV)) {
	strcpy(qcs->errmsg, qrpc_error_string(qrpc, status));
	if (qrpc)
	    qrpc_destroy(&qrpc);
	return (status);
    }

    if (status = qrpc_auth_to_server(qrpc, params->aname, NULL, qcs->sess_key, 
				     qcs->sched)) {
	strcpy(qcs->errmsg, qrpc_error_string(qrpc, status));
	if (qrpc)
	    qrpc_destroy(&qrpc);
	return (status);
    }
	
    qcs->qrpc = qrpc;

    return (QCS_SUCCESS);
}


static int qcsi_init_client_readset(qcs_t *qcs, fd_set *select_read_set)
{
    int max_fd = 0;
    int i;
    
    FD_ZERO(select_read_set);

    if (qcs->params->ui_fd > max_fd)
	max_fd = qcs->params->ui_fd;
    FD_SET(qcs->params->ui_fd, select_read_set);

    if (qcs->qrpc) {
	if (qcs->qrpc->in > max_fd)
	    max_fd = qcs->qrpc->in;
	FD_SET(qcs->qrpc->in, select_read_set);
    }
    
    for (i = 0; i < MAXJOBS; i++) {
	if (qcs->user_qrpc[i] && qcs->user_qrpc[i] != QCS_NO_USERQRPC) {
	    if (qcs->user_qrpc[i]->in > max_fd)
		max_fd = qcs->user_qrpc[i]->in;
	    FD_SET(qcs->user_qrpc[i]->in, select_read_set);
	}
    }
	 
    return (max_fd);
}


qcs_error_t qcs_client_mainloop(qcs_t *qcs, void *userdata)
{
    fd_set select_read_set;
    struct timeval periodic;	/* timer for select */
    struct timeval *perp;
    qcs_bool done = FALSE;
    int max_fd;
    int sel_ret;

    qcs->errmsg[0] = '\0';

    if (qcs->params->handle_periodic)
	perp = &periodic;
    else
	perp = NULL;

    while (! (done || qcs->done)) {
	
	max_fd = qcsi_init_client_readset(qcs, &select_read_set);

	periodic.tv_sec = QCS_CLIENT_PERIODIC;
	periodic.tv_usec = 0;

	sel_ret = select(max_fd + 1, &select_read_set, NULL, NULL, perp);
	switch (sel_ret) {
	  case -1:
	    if (errno != EINTR) {
		sprintf(qcs->errmsg, "select failed: %s", sys_errlist[errno]);
		done = TRUE;
	    }
	    break;
	  default:
	    if (sel_ret == 0) {
		qcs->params->handle_periodic(qcs, userdata);
	    }
	    else {
		if (FD_ISSET(qcs->params->ui_fd, &select_read_set)) 
		    done = (qcs->params->handle_input(qcs, userdata) != 
			    QCS_SUCCESS);
		if (qcs->qrpc && (FD_ISSET(qcs->qrpc->in, &select_read_set)))
		    done = (qcsi_handle_qcsserver(qcs, userdata) 
			    != QCS_SUCCESS);
		/* XXX Handle user_qrpc[i] */ 
#if 0
		if (qcs->user_qrpc && (FD_ISSET(qcs->user_qrpc->in,
						&select_read_set)))
		    done = (qcs->params->handle_userqrpc(qcs, NULL, userdata) 
			    != QCS_SUCCESS);
#endif
	    }
	    break;
	}
    }
    
    if (qcs->errmsg[0])
	return (QCS_FAILURE);
    else
	return (QCS_SUCCESS);
}
