/*****************************************************************
 * OS Depedent input routines:
 *
 *  WaitForSomething
 *
 *****************************************************************/

#include "Xos.h"			/* for strings, fcntl, time */

#include <errno.h>
#include <stdio.h>
#include <time.h>
#include "X.h"
#include "misc.h"
#include "opaque.h"
#include "../../glue/shared.h"

#include <signal.h>
#include "dixstruct.h"
#include "osdep.h"
#include "funcs.h"
#include "starnet.h"

extern OsCommPtr WellKnownOS, WellKnownO2;
extern OsCommPtr oneClient;
u_long sleepcount;
extern int screenIsSaved;
extern int minpriority;
#ifdef X_PRINT_PORT
extern struct tcpport PrinterPort;
#endif
#ifdef XDMCP
extern struct udpport xdmcpPort;
extern int xdmcpSocket;
#endif

extern u_char input_ready;
extern Bool NewOutputPending;
extern Bool AnyClientsWriteBlocked;
extern OsCommPtr MyPrivate[NPORTS];

extern long TimeSinceLastInputEvent();
extern void  mouseBlockHandler(void);

/*****************
 * WaitForSomething:
 *     Make the server suspend until there is
 *	1. data from clients or
 *	2. input events available or
 *	3. ddx notices something of interest (graphics
 *	   queue ready, etc.) or
 *	4. clients that have buffered replies/events are ready
 *
 *     If the time between INPUT events is
 *     greater than ScreenSaverTime, the display is turned off (or
 *     saved, depending on the hardware).  So, WaitForSomething()
 *     has to handle this also (that's why the select() has a timeout.
 *     For more info on ClientsWithInput, see ReadRequestFromClient().
 *     pClientsReady is a mask, the bits set are 
 *     indices into the o.s. depedent table of available clients.
 *     (In this case, there is no table -- the index is the socket
 *     file descriptor.)  
 *****************/

static long timeTilFrob = 0;		/* while screen saving */
#ifdef X_PRINT_PORT
static int print_open;
#endif

int
WaitForSomething(pClientsReady)
    int *pClientsReady;
{
    int i;
    long timeout;
    u_long timeouttime;
    OsCommPtr oc;
    Bool done, first;
    int nready = 0;

    /* We need a while loop here to handle 
       crashed connections and the screen saver timeout */
    for (;;)
    {
	    netsleep();
	    if (dispatchException)
		return nready;

            if (ScreenSaverTime)
	    {
                timeout = ScreenSaverTime - TimeSinceLastInputEvent();
	        if (timeout <= 0) /* may be forced by AutoResetServer() */
	        {
		    long timeSinceSave;

		    timeSinceSave = -timeout;
	            if ((timeSinceSave >= timeTilFrob) && (timeTilFrob >= 0))
                    {
		        SaveScreens(SCREEN_SAVER_ON, ScreenSaverActive);
			if (ScreenSaverInterval)
			    /* round up to the next ScreenSaverInterval */
			    timeTilFrob = ScreenSaverInterval *
				    ((timeSinceSave + ScreenSaverInterval) /
					    ScreenSaverInterval);
			else
			    timeTilFrob = -1;
		    }
    	            timeout = timeTilFrob - timeSinceSave;
		    if (timeTilFrob < 0)
			timeout = 0;
    	        }
 		else
 		{
		    if (timeout > ScreenSaverTime)
		        timeout = ScreenSaverTime;
	            timeTilFrob = 0;
		}
	    }
            else {
                timeout = 0;
		if (screenIsSaved == SCREEN_SAVER_ON)
			SaveScreens(SCREEN_SAVER_OFF, ScreenSaverReset);
	    }
	    if (NewOutputPending)
	    	FlushAllOutput();
	    netsleep();
	    for (done = FALSE, first = TRUE; !done;) {
		netsleep();
		if (WellKnownOS && WellKnownOS->tcpport.state == SEST)
		    EstablishNewConnections(&WellKnownOS);

		if (WellKnownO2 && WellKnownO2->tcpport.state == SEST)
		    EstablishNewConnections(&WellKnownO2);
#ifdef X_PRINT_PORT
		if (print_open) {
		    if (PrinterPort.inbase != PrinterPort.infree)
			print_open = PrintIt();
		} else {
		    if (PrinterPort.state == SEST)
			print_open = PrintOpen();
		}
#endif
#ifdef XDMCP
		if (xdmcpPort.inbase != xdmcpPort.infree)
			XdmcpReceivePacket(xdmcpSocket);
#endif
		netsleep();
		if (oneClient) {

		    if ((oneClient->tcpport.state != SEST &&
			oneClient->tcpport.state != SFW1 &&
			oneClient->tcpport.state != SFW2) ||
			(oneClient->flags & OS_REUSE) ||
			oneClient->tcpport.infree !=
			oneClient->tcpport.inbase) {
			    pClientsReady[nready++] = oneClient->client;
			    done = TRUE;
		    }
		} else {
		    minpriority = MAXPRIORITY;
		    for (i = 0; i < NPORTS; i++) {
			char junk[256];

			oc = MyPrivate[i];
			if (!oc)
			    continue;
			netsleep();
			if (oc->flags & OS_CLOSING) {
			    if (oc->tcpport.state == SCLOSED) {
				    SoFree(i);
				    MyPrivate[i] = 0;
				    xfree(oc);
				    if (!WellKnownOS || !WellKnownO2)
					reset_socket();
			    } else {
				(void)SoRead(oc->fd, (u_char *)junk, sizeof junk);
			    }
			    continue;
			}
			if ((oc->tcpport.state != SEST &&
			    oc->tcpport.state != SFW1 &&
			    oc->tcpport.state != SFW2) ||
			    (oc->flags & OS_REUSE) ||
			    oc->tcpport.infree != oc->tcpport.inbase) {
				if (oc->priority < minpriority)
				    minpriority = oc->priority;
				pClientsReady[nready++] = oc->client;
				done = TRUE;
			} else if (oc->priority > 0)
			    oc->priority--;
		    }
		}
		if (AnyClientsWriteBlocked)
		{

		    AnyClientsWriteBlocked = FALSE;
		    for (i = 0; i < NPORTS; i++) {

			oc = MyPrivate[i];
			if (!oc)
			    continue;
			if (!(oc->flags & OS_BLOCKED))
			    continue;
			FlushClient(oc, (char *)NULL, 0);
		    }
		}
		if (input_ready)
			done = TRUE;
		if (first && !done) {
		    XdmcpBlockHandler(&timeout);
		    mouseBlockHandler();
		    if (timeout) {
			timeouttime = timeout + n_clicks() * 55;
		    }
		    first = FALSE;
		}
		if (!done && timeout) {
		    if (n_clicks() * 55 >= timeouttime)
			    done = TRUE;
		}
	    }
	    if (!first)
		XdmcpWakeupHandler();
	    if (input_ready || nready)
		    break;
    }
    return nready;
}
