/*
 * Copyright (C) 1992 WIlfried Koch, Palanterstr. 46, D-5000 Koeln 41 (Germany)
 * All rights reserved.
 *
 * This software may be freely copied, modified, and redistributed
 * provided that this copyright notice is preserved on all copies.
 *
 * You may not distribute this software, in whole or in part, as part of
 * any commercial product without the express consent of the authors.
 *
 * There is no warranty or other guarantee of fitness of this software
 * for any purpose.  It is provided solely "as is".
 * Initial version
*/
#include "rrloops.h"

static bool_t      LineComplete=FALSE;
static bool_t      FrameComplete=FALSE;
static bool_t      ComputeComplete=FALSE;

int  ServicesInNetwork=NULL;
int  ServicesOnServer=NULL;
int  ConnectionsInNetwork=NULL;

RRreqList  	*rrreqo=NULL;          	/** requests to be sent	       **/
RRreqList  	*rrreqs=NULL;          	/** send requests              **/

RRreqList  	*rrreqr=NULL;          	/** sorted List of Received requests   **/
RRServerList    *Servers=NULL;         	/** List of available Services	       **/

RRConnList  	*Connects=NULL;        	/** LIST of Connections	   	       **/
RRConnList	*curcon=NULL;           /** current Connection		       **/


struct timeval LISTENTIMEOUT = { 1,0} ;
struct timeval TIMEOUT = {25 , 0 };
struct timeval MTIMEOUT = {3  , 0 };
struct timeval REQTIMEOUT = {0  ,300 }; /** Timeout for trying Connections    **/
struct timeval RETRYTIMEOUT= {0  , 100 }; /** Timeout for trying Connections(UDP)  **/
struct timeval FORCETIMEOUT= {4  , 0 }; /** Timeout for forcing Connections(UDP)  **/
struct timeval FORCERETRYTIMEOUT= {0  , 200000 }; /** Timeout for forcing Connections(UDP)  **/
struct timeval NOTIMEOUT = {0 , 0 };
time_t RRID;

int minx,maxx,miny,maxy,frame;
int Render_Number_of_Squares, Frame_Number_of_Squares, PendingSquares;

RRProgStruct RRProg={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL} ; 

int LineSend,FrameSend,RenderSend;

char *MyHostname;


static LightWeightProc LWTable[]={
	{ RRInitRender,	  RENDER_BEGIN },
	{ RRInitFrame,	  FRAME_BEGIN} ,
	{ RRSendRequest,  REQUEST_TO_SEND },
	{ RRNextRequest,  REQUEST_SEND },
	{ RRReqAlloc,	  REQUEST_TO_ALLOCATE},
	{ RRPend,	  TO_PEND},
	{ NULL, DONOTHING}
		
};
static int LWProcedureIndex = NULL;
static LightWeightMask LWMask = REQUEST_TO_SEND;

static unsigned long int next = 1;

int RRrand()
   {
   next = next * 1103515245L + 12345L;
   return ((int) (next / 0x10000L) & 0x7FFF);
   }

void RRsrand(seed)
   unsigned int seed;
   {
   next = seed;
   }
void RRAbort()
{
	SetLWFlag(SCENE_RECEIVED);
}

bool_t RRLineReady(curreq,number)
	RRreqList *curreq;
	int number;
{
	static int lastsquare = -1;
	RRreqList *tmpreq,*lastreq=NULL;
	tmpreq=curreq;
	while(curreq && number) {
		number--;
		if(curreq->next) 
			if( curreq->rrreq.sequence + 1 != curreq->next->rrreq.sequence)
				return FALSE;
		lastreq=curreq;
		curreq=curreq->next;
	}
	if(number > 0 )
		return FALSE;
	else {
		if(tmpreq->rrreq.sequence==lastsquare+1){
			lastsquare=lastreq->rrreq.sequence;
			return TRUE;
		} else {
			return FALSE;
		}
	}
	
}
	
	
void PrintReqlist(s,curreq)
	char *s; 
	RRreqList  *curreq;
{
	
	fprintf(stderr,"%s",s);
	while(curreq){
	/*	fprintf(stderr,curreq->prev ? "|%2d": "|--:",curreq->prev?curreq->prev->rrreq.sequence :(int)NULL); */
		fprintf(stderr," %d:",curreq->rrreq.sequence);
	/*	fprintf(stderr,curreq->next ?  "%2d|": "--|"  ,curreq->next?curreq->next->rrreq.sequence: (int)NULL);*/
		curreq=curreq->next;
	}
	fprintf(stderr,"\n");
}
RRreqList *
FindRequest(request, requestlist)
	RRreq *request;
	RRreqList *requestlist;
{
	RRreqList *curreq;
	curreq=requestlist;

	if((!requestlist) || (!request) )
		return NULL;

	while(curreq) {
		if(request->minx==curreq->rrreq.minx &&
		   request->maxx==curreq->rrreq.maxx &&
		   request->miny==curreq->rrreq.miny &&
		   request->maxy==curreq->rrreq.maxy &&
		   request->sequence==curreq->rrreq.sequence &&
		   request->frame==curreq->rrreq.frame &&
		   request->RRID==curreq->rrreq.RRID){
			break;
		}
	curreq=curreq->next;
	}
	return curreq;
}

RRSanity (rrprog)
	RRProgStruct  *rrprog;
{
	if(!rrprog->name) {
		fprintf(stderr, "no name in RRProg Struct \n");
		exit(1);
	} else 	{
		fprintf(stderr, " RRLib %s\n", rrprog->name); 
	}
	if (!rrprog->RR_fnct ||   ((u_long) rrprog->RR_fnct & 1) ) {
		fprintf(stderr,"Render Function not given or unaligned \n");
			exit(1);
	}
	if(!rrprog->RRxdr_fnct || ((u_long) rrprog->RRxdr_fnct & 1 ) ) {
		fprintf(stderr,"XDR Function not given or unaligned \n");
		exit(1);
	}


}

			
RRScreenSanity (rrprog)
	RRProgStruct  *rrprog;
{
	if(!rrprog->RRPlot_fnct || ((u_long) rrprog->RRPlot_fnct & 1 )  ) {
		fprintf(stderr,"Plot Function not given or unaligned, won't call\n");
		rrprog->RRPlot_fnct=NULL;
	}
	if(!rrprog->RRRefresh_fnct || ((u_long) rrprog->RRRefresh_fnct & 1 )) {
		fprintf(stderr,"Refresh Function not given or unaligned, won't call\n");
		rrprog->RRRefresh_fnct=NULL;
	}
	if(!rrprog->RRWriteLine_fnct || ((u_long) rrprog->RRWriteLine_fnct & 1 )) {
		fprintf(stderr,"WriteLine Function not given or unaligned, won't call\n");
		rrprog->RRWriteLine_fnct=NULL;
	}
	if(!rrprog->RRPause_fnct || ((u_long) rrprog->RRPause_fnct & 1 )) {
		fprintf(stderr,"Pause Function not given or unaligned, won't call\n");
		rrprog->RRPause_fnct=NULL;
	}
	if(rrprog->minx >= rrprog->maxx) {
		fprintf(stderr, " maxx %d smaller or equal minx %d\n",
			rrprog->minx,  rrprog->maxx);
			exit(1);
	}
	if(rrprog->miny >= rrprog->maxy) {
		fprintf(stderr, " maxy %d smaller or equal miny %d\n",
			rrprog->miny,  rrprog->maxy); 
			exit(1);
	}
	if(rrprog->startframe > rrprog->maxx) {
		fprintf(stderr, " startframe  %d smaller  endframe %d\n",
			rrprog->startframe,  rrprog->endframe); 
			exit(1);
	}
	if(rrprog->minx <0 || rrprog->maxx <0 || rrprog->miny <0 || rrprog->maxy <0
		           || rrprog->startframe <0 || rrprog->endframe <0 
			   || rrprog->squaresize <=0 ){
		fprintf(stderr,
	" invalid Screen minx %d maxx %d miny %d maxy %d startframe %d endframe %d\n",
	  rrprog->minx,rrprog->maxx,rrprog->miny,rrprog->maxy, rrprog->startframe, 
	  rrprog->endframe); 
	}
}
		   
		
void UnlinkConnection(conn,connlist)
	RRConnList *conn,**connlist;
{	
	RRConnList *prevconn,*tmpconn;
	
	if( (!conn) || (!*connlist))
		return;
	if(conn==*connlist) {
		*connlist=(*connlist)->next;
		return;
	}
	prevconn= *connlist;
	tmpconn= *connlist;
	while(tmpconn) {
		if(tmpconn==conn) {
			prevconn->next=tmpconn->next;
			break;
		}
		prevconn=tmpconn;
		tmpconn=tmpconn->next;
	}
}
	
		


	

void UnlinkListRequest(request,requestlist)
	RRreqList *request;
	RRreqList **requestlist;
{

	if(request->prev) {
		request->prev->next=request->next; 
	} else {
		*requestlist=request->next;
	}

	if(request->next) {
		request->next->prev=request->prev;
	} 
	request->next=request->prev=NULL;

}
void LinkListRequest(request,requestlist)
	RRreqList *request;
	RRreqList **requestlist;
{
	RRreqList *tmpreq;
	

	if(*requestlist) {
		tmpreq=(*requestlist)->prev;
		(*requestlist)->prev=request;
		request->next = *requestlist;
		request->prev=tmpreq;
		if(tmpreq)
			tmpreq->next=request;
	} else {
		request->next=NULL;
		request->prev=NULL;
	}
	if(!request->prev)
		*requestlist=request;
}

void LinkSortedListRequest(request,requestlist)
	RRreqList *request;
	RRreqList **requestlist;
{
	RRreqList *tmpreq;
	tmpreq = *requestlist;

	if(! *requestlist){
		LinkListRequest(request,requestlist);
		return;
	}
		
	while(tmpreq->next) {
		if(request->rrreq.sequence == tmpreq->rrreq.sequence)
			return;
		if(request->rrreq.sequence > tmpreq->rrreq.sequence){
			tmpreq=tmpreq->next;
			continue;
		}
		if(request->rrreq.sequence < tmpreq->rrreq.sequence)
			break;
	}
	if(request->rrreq.sequence < tmpreq->rrreq.sequence) {
		if(tmpreq==*requestlist)
			LinkListRequest(request,requestlist);
		else
			LinkListRequest(request,&tmpreq);

	} else {
		tmpreq->next=request;
		request->prev=tmpreq;
		request->next=NULL;
	}
}
RRFreeLines(reqlp,number)
	RRreqList **reqlp;
	int number;
{
	RRreqList *curreq;
	RRreqList *oreq;
	curreq = *reqlp;
	while(curreq && number-- ) {
		oreq=curreq->next;
		free(curreq->square->pixels.pixels_val);
		free(curreq->square);
		free(curreq);
		curreq=oreq;
	}
	*reqlp=curreq;
}

		

void RRWriteLines(reqlist,number)
       RRreqList *reqlist;
       int number;
{
	RRreqList *curreq;
	rpc_Pixel *pixels,*curpixel;
	int linecnt,row;
	int tmpnum;
	
	curreq=reqlist;

	fprintf(stderr,"\nWriting Square(s): ");
	
	tmpnum=number;
	while(curreq && tmpnum--){
               fprintf(stderr,"%d ",curreq->rrreq.sequence);
               curreq=curreq->next;
	}
	curreq=reqlist;

	if((SCREENXSIZE <= SQUARESIZE) && (SCREENYSIZE <= SQUARESIZE)) {
		rpc_Pixel *pixels;
		pixels=curreq->square->pixels.pixels_val;
		for(row=SCREENMINY; row<SCREENYSIZE; row++){
			(*RRProg.RRWriteLine_fnct)(pixels,
					      curreq->rrreq.sequence,
					      curreq->rrreq.miny+row,
	  			 	      SCREENXSIZE );
			pixels+=SCREENXSIZE;
		}
		fprintf(stderr," , Frame %d/%d Line %d/%d saved\n",
			reqlist->rrreq.frame,
			ENDFRAME,
			reqlist->rrreq.maxy,
			SCREENMAXY);
		return;
	}

	linecnt=(curreq->rrreq.maxy-curreq->rrreq.miny)+1;

	if(!(pixels=(rpc_Pixel*) calloc (SCREENXSIZE,sizeof(rpc_Pixel)) ))
		return;
	for(row=0; row<linecnt;row++) {
		curreq=reqlist;
		curpixel=pixels;
		tmpnum=number;
		while(curreq && tmpnum){
			ByteCopy(
				curreq->square->pixels.pixels_val+
					(row*((curreq->rrreq.maxx-curreq->rrreq.minx)+1)),
				curpixel,
				sizeof(rpc_Pixel) * 
					 ( (curreq->rrreq.maxx-curreq->rrreq.minx+1) )
			 );
			curpixel+=( (curreq->rrreq.maxx-curreq->rrreq.minx)+1 );
			curreq=curreq->next;
			tmpnum--;
		}
		curreq=reqlist;
		(*RRProg.RRWriteLine_fnct)(pixels,
				           reqlist->rrreq.frame,
		 		           reqlist->rrreq.miny+row,
	  			 	   SCREENXSIZE );
	}
	free(pixels);	
	fprintf(stderr," , Frame %d/%d Line %d/%d saved\n",
		reqlist->rrreq.frame,
		ENDFRAME,
		reqlist->rrreq.maxy,
		SCREENMAXY);
}
void RRForceWrite(reqlist) 
	RRreqList **reqlist;
{
	RRreqList *tmpreq;

	if(!reqlist)
		return;
	tmpreq= *reqlist;
	if(!tmpreq)
		return;
	
	if(RRLineReady(tmpreq,SQUARES_IN_X)) {
		if((SCREENXSIZE <= SQUARESIZE) && (SCREENYSIZE <= SQUARESIZE)) 
			if(RRProg.RRPlot_fnct)
				(void) (*RRProg.RRPlot_fnct)(tmpreq->square);
		if(RRProg.RRWriteLine_fnct)
			RRWriteLines(tmpreq,SQUARES_IN_X);
		RRFreeLines(reqlist,SQUARES_IN_X);
	}

	if(tmpreq->rrreq.maxy==SCREENMAXY) {
		if(RRProg.RRPause_fnct)
			(*RRProg.RRPause_fnct)(frame);	
	}
}

void *RRSquare(square)
       rpc_square *square;
{
	RRreqList *curreq;
	RRConnList *currecon;
	curreq=FindRequest(&square->req,rrreqs);

	if( ! curreq ){
		fprintf(stderr,"\n");
		ConnectionInfo(&square->req.connect,stderr);
		fprintf(stderr," Square %d,wrong Server\n",
			square->req.sequence);	
		return(NULL);
	}
	if(BUSYCHECK) {
		if(currecon) {
			currecon->conn.busy=FALSE;
		}
	}
	curcon=RRFindConnection(&curreq->rrreq.connect,Connects);
	fprintf(stderr,   "\nSquare %2d received:", curreq->rrreq.sequence);
	UnlinkListRequest(curreq,&rrreqs);
	LinkSortedListRequest(curreq,&rrreqr);
	PrintReqlist(  "Squares to be sorted:",rrreqr);
	curreq->square=(rpc_square*)malloc(sizeof(rpc_square));
	if(!curreq->square)
		return NULL;
	bcopy(square,curreq->square,sizeof(rpc_square));
	RRForceRequest();
	

	if( ! ((SCREENXSIZE <= SQUARESIZE) && (SCREENYSIZE <= SQUARESIZE) )) 
		if(RRProg.RRPlot_fnct)
			(void) (*RRProg.RRPlot_fnct)(square);
	
	if(RRProg.RRRefresh_fnct)
		(void) (*RRProg.RRRefresh_fnct)();
	if(rrreqr)
	    rrreqr->prev=NULL;
	RRForceWrite(&rrreqr);
	PendingSquares--;		
}

void *RRNewService(conn)
	RRConnList *conn;
{
	bool_t res;
	if(strcmp(RRProg.name,conn->conn.progname)){
		fprintf(stderr, "Server is %s\n",conn->conn.progname);
		res=FALSE;
		return &res;
	}
	res=TRUE;
	conn->next=Connects;
	Connects=conn;
	curcon=conn;
	fprintf(stderr,"\n");
	ConnectionInfo(&curcon->conn,stderr);
	ConnectionsInNetwork++;
	fprintf(stderr," ACK %4d \n",ConnectionsInNetwork);
	RRForceRequest();
	RRForceRequest();
	
	return (void*) res;
}

void RRReqAlloc()
{
       static sequence=NULL;
       RRreqList *request;
       request=(RRreqList*)calloc(1,sizeof(RRreqList));
       if(sequence >=  Render_Number_of_Squares)	
		return;
       if(request){
		
 		if(maxx>SCREENMAXX){ 
			maxx=SCREENMAXX;
		} 
       		if(maxy>SCREENMAXY){
			 maxy=SCREENMAXY;
		}

		request->rrreq.RRID=RRID;
		request->rrreq.frame=frame;
		request->rrreq.minx=minx;
		request->rrreq.maxx=maxx;
		request->rrreq.miny=miny;
		request->rrreq.maxy=maxy;
		request->rrreq.sequence=sequence;
		request->rrreq.size=(maxx-minx)+1;

		LinkSortedListRequest(request,&rrreqo);
		/*fprintf(stderr,"\nblock %d %d %d %d %d %d alloced\n",sequence,frame,minx,maxx,miny,maxy);*/
		sequence++;
	}
}
void rpc_client(serverfile)
	FILE *serverfile;
{
	time(&RRID);
        signal(SIGQUIT,RRUnRegisterCallback);
        signal(SIGINT,RRUnRegisterCallback);
        signal(SIGSTOP,RRUnRegisterCallback);
	signal(SIGTERM,RRUnRegisterCallback);
	signal(SIGPIPE,RRUnRegisterCallback);
	
        signal(SIGBUS,RRUnRegisterCallbackCore);
        signal(SIGSEGV,RRUnRegisterCallbackCore);
        /*signal(SIGIOT,RRUnRegisterCallbackCore);*/

	RRSanity(&RRProg);
	RRScreenSanity(&RRProg);
	((RRArg*)(RRProg.arg))->RRID=RRID;
	GetMyHostname(&MyHostname);
	RegisterCallback();
	ClientInfo(stderr);
	fprintf(stderr," RRID %ld\n",RRID);
	GetServers(serverfile);
	fprintf(stderr,"\n	%d Service(s) in Network\n",ServicesInNetwork);
#ifndef sun
#ifndef _AIX370
        atexit(RRUnRegisterCallback);
#endif
#endif

	RRInitRender();
	RRInitFrame();
	while ( ! ListenCallback() )
		;	
	RRUnRegisterCallback(-1000);
}


bool_t ListenCallback() 		/** Writing your own svc_run() in "The Art of     **/
			 	/** Distributed Applications ",   John R. Corbin  **/
{
       CALLBACK_VAR       	/** specific variables for RPC-Tool and 	  **/
			 	/** and  underlaying network transport	layer	  **/

       switch(LISTEN_TO_NETWORK){
 
               ERROR_LISTEN:	/** in netspec.h				  **/
                        ACTION_ON_ERROR_LISTEN; 
		        break;
                
               NO_MESSAGE:	/** in netspec.h				  **/
			
			return DoClient();
 
               GOT_CALLBACK:    /** in rpcspec.h				  **/
                       ACTION_ON_CALLBACK;
       }
       return FALSE;
}
void GetServers(serverfile) 
	FILE *serverfile;
{
	char s[MAXHOSTNAMELEN];
	RRTransport transport;
	RRServerList *new;
	RRConnection conn;
	char st[300],*stp,c;
	if(!serverfile)
		return;
	while(fscanf(serverfile,"%d",&transport) && fscanf(serverfile,"%s",s) ){
		if(transport==-1)
			break;
	
		ServicesOnServer=NULL;
		conn.progname=(nm) RRProg.name;
		conn.clientname=(nm) MyHostname;
		conn.servername=(nm) strsave(s);
		conn.transport=transport;

		switch (transport) {
			case PORTMAPPER_TCPIP_ON_PORTMAPPER_TCPIP:
				stp=st;
				*stp=0;
				strcat(stp,s);
				stp=st+strlen(st);
				while((c=getc(serverfile)) != '\n') {
					*stp++=c;
				}
				sprintf(stp,"",conn.transport);
				stp=st+strlen(st);
				TAPCat(stp);
				fprintf(stderr,"executing %s\n",st);
				if(system(st)){
					new = (RRServerList*) calloc(1,sizeof(RRServerList));
					if(new) {
						new->exestring=st;
						new->server.name=NULL;
						new->next=Servers;
						Servers=new;
					}
				}
				break;

			case PORTMAPPER_TCPIP_PORTMAPPER_TCPIP:
				fprintf(stderr,"\nLooking for PORTMAPPER TCP/IP Services on %s",conn.servername);
				while (ConsultPortmapper(&conn)) {
					new = (RRServerList*) calloc(1,sizeof(RRServerList));
					if(!new)
						continue;
					new->server.name=(char*)strsave(s);
					new->exestring=NULL;
					new->next=Servers;
					Servers=new;
				}
				if(ServicesOnServer)
					fprintf(stderr,"                                                     ");
				fprintf(stderr,"       %d Service(s) detected",ServicesOnServer);
				break;
				
			case PARSEERROR:
			default:
				fprintf(stderr," Transportmethod %d not supported\n",transport);
				exit(1);
		}

				
	    } 
}
		 
			
		
void RRInitRender()
{
	PendingSquares=0; 
	Render_Number_of_Squares = 
		((ENDFRAME-STARTFRAME)+1)* SQUARES_IN_X * SQUARES_IN_Y;
			
	frame=STARTFRAME-1; 
	UnSetLWFlag(RENDER_BEGIN);
	SetLWFlag(FRAME_BEGIN);
	fprintf(stderr,"        %ld Squares Size %ld\n",Render_Number_of_Squares, SQUARESIZE);
}

void RRInitFrame()
	{
	if(frame>ENDFRAME) {
        	UnSetLWFlag(FRAME_BEGIN);
		SetLWFlag(TO_PEND);
		UnSetLWFlag(REQUEST_TO_SEND);
		return;
	} else {
		frame++;
	}
        minx=SCREENMINX;
        maxx=SCREENMINX+SQUARESIZE-1; 
        miny=SCREENMINY;         
        maxy=SCREENMINY+SQUARESIZE-1;
        UnSetLWFlag(FRAME_BEGIN);
	fprintf(stderr,"        Frame %ld %ld Square(s)\n",frame,SQUARES_IN_X * SQUARES_IN_Y);
	RRReqAlloc();

}
 

void RRSendRequest()
{
	RRreqList *tmpreq;       
	RRStatus status;

	status=(!RRSERVICE_SUCCESS);
        while(status != RRSERVICE_SUCCESS) {

		if(!curcon) {
			 fprintf(stderr,"\rExpecting ACK of first Service");
			 return;
		}
		if(!rrreqo){
			RRNextRequest();
		}
		if(!rrreqo){
			RRPend();
		}
		if(!rrreqo){
			return;
		}
		fprintf(stderr,"\rtrying  ");
		ByteCopy(&curcon->conn, &(rrreqo->rrreq.connect), sizeof(RRConnection));
		ConnectionInfo( &(rrreqo->rrreq.connect),stderr );
		if(BUSYCHECK) {
			if(curcon->conn.busy) {
				fprintf(stderr, " busy ");
				curcon= (curcon->next) ? curcon->next : Connects;
				RRForceWrite(&rrreqr);
				return;
			}
		}
        	status = CallRRRequest ( &rrreqo->rrreq,&REQTIMEOUT,&RETRYTIMEOUT) ;
		switch (status) {

			case RRSERVICE_SUCCESS: 
				PendingSquares++;
				fprintf(stderr," Square %d sent\n",rrreqo->rrreq.sequence);
				tmpreq=rrreqo;
				UnlinkListRequest (rrreqo, &rrreqo );
               			LinkListRequest ( tmpreq, &rrreqs);
				curcon->conn.busy=TRUE;
				if(curcon->next){ 
					curcon=curcon->next; 
				} else { 
					curcon=Connects; 
					return; 
				}
				break;
			 
			case RRSERVICE_TIMEDOUT: 
				ByteZero(&rrreqo->rrreq.connect,sizeof(RRConnection));
				fprintf(stderr," busy");
				if(curcon->next){ 
					curcon=curcon->next; 
				} else { 
					RRForceWrite(&rrreqr);
					curcon=Connects; 
					return; 
				}
				break;
			case RRSERVICE_ARGSMARSHALLED: 
				ByteZero(&rrreqo->rrreq.connect,sizeof(RRConnection));
				fprintf(stderr," marshalled");
				if(curcon->next){ 
					curcon=curcon->next; 
				} else { 
					curcon=Connects; 
					return; 
				}
				break;
	
			case RRSERVICE_UNCONNECTABLE:
			case RRSERVICE_BROKENCONNECTION:
				fprintf(stderr,"\tunconnectable");
				{	
					
					RRreqList *tmpreq;
					while(tmpreq=FindReqByConn(rrreqs,&curcon->conn)) {
						UnlinkListRequest(tmpreq,&rrreqs);
						PendingSquares--;
						LinkSortedListRequest(tmpreq,&rrreqo);
                                        	fprintf(stderr,"\nSquare %d will be sent again\n",
							tmpreq->rrreq.sequence);
					}
				}
				UnlinkConnection(curcon, &Connects );
				if(Connects) {
					RRConnList *tmpconn;
					tmpconn=Connects;
				        fprintf(stderr,"\nConnection removed,remaining Connection(s):  \n");
					while(tmpconn){
						ConnectionInfo(&tmpconn->conn,stderr);
						fprintf(stderr,"\n");
						tmpconn=tmpconn->next;
					}
				} else {
					fprintf(stderr,"\nNo remaining Connections !\n");
				}
				free(curcon);
				curcon=Connects;
				break;
			default:
				fprintf(stderr,"\tstatus %d",status);
				
		
		}
	}
}
void RRForceRequest()
{
        RRreqList *tmpreq;
        RRStatus status;

        if(!curcon) {
		fprintf(stderr,"\rExpecting ACK of first Service");
                return;
        }
        if(!rrreqo){
                RRNextRequest();
        }
        if(!rrreqo){
                RRPend();
        }
        if(!rrreqo){
                return;
        }
        fprintf(stderr,"\rforcing ");
        ByteCopy(&curcon->conn, &(rrreqo->rrreq.connect), sizeof(RRConnection));
        ConnectionInfo( &(rrreqo->rrreq.connect),stderr );
        if(BUSYCHECK) {
                if(curcon->conn.busy) {
                        fprintf(stderr, " busy ");
                        curcon= (curcon->next) ? curcon->next : Connects;
                        RRForceWrite(&rrreqr);
                        return;
                }
        }
        status = CallRRRequest ( &rrreqo->rrreq,&FORCETIMEOUT,&FORCERETRYTIMEOUT) ;
        switch (status) {

                case RRSERVICE_SUCCESS:
                        PendingSquares++;
                        fprintf(stderr," Square %d sent\n",rrreqo->rrreq.sequence);
                        tmpreq=rrreqo;
                        UnlinkListRequest (rrreqo, &rrreqo );
                        LinkListRequest ( tmpreq, &rrreqs);
                        curcon->conn.busy=TRUE;
                        break;

                case RRSERVICE_TIMEDOUT:
                        ByteZero(&rrreqo->rrreq.connect,sizeof(RRConnection));
                        fprintf(stderr," busy");
                        if(curcon->next){
                                curcon=curcon->next;
                        } else {
                                RRForceWrite(&rrreqr);
                                curcon=Connects;
                                return;
                        }
                        break;
                case RRSERVICE_ARGSMARSHALLED:
                        ByteZero(&rrreqo->rrreq.connect,sizeof(RRConnection));
                        fprintf(stderr," marshalled");
			return;

                case RRSERVICE_UNCONNECTABLE:
                case RRSERVICE_BROKENCONNECTION:
                        fprintf(stderr,"\tunconnectable");
                        {
                        RRreqList *tmpreq;
                        while(tmpreq=FindReqByConn(rrreqs,&curcon->conn)) {
                                        UnlinkListRequest(tmpreq,&rrreqs);
                                        PendingSquares--;
                                        LinkSortedListRequest(tmpreq,&rrreqo);
                                        fprintf(stderr,"\nSquare %d will be sent again\n",
                                                        tmpreq->rrreq.sequence);
                                }
                        }
                        UnlinkConnection(curcon, &Connects );
                        if(Connects) {
                        	RRConnList *tmpconn;
                               	tmpconn=Connects;
                                fprintf(stderr,
					"\nConnection removed,remaining Connection(s):\n");
                                while(tmpconn){
                                     	ConnectionInfo(&tmpconn->conn,stderr);
                                       	fprintf(stderr,"\n");
                                       	tmpconn=tmpconn->next;
                                }
                                } else {
                                        fprintf(stderr,"\nNo remaining Connections !\n");
                                }
                                free(curcon);
                                curcon=Connects;
                                break;
                        default:
                                fprintf(stderr,"\tstatus %d",status);


                }
}


void RRNextRequest(){
		UnSetLWFlag(REQUEST_SEND);

                if((maxy>=SCREENMAXY) && (maxx>=SCREENMAXX) ){      

			if((SCREENXSIZE > SQUARESIZE) && (SCREENYSIZE > SQUARESIZE)) {
				SetLWFlag(TO_PEND);
				
				if((!rrreqo) && (!rrreqs) && (!rrreqr)){
					RRInitFrame();
					return;
				} else {
					RRForceWrite(&rrreqr);
					return;
				}
			} else {
				UnSetLWFlag(TO_PEND);
				RRForceWrite(&rrreqr);
				RRInitFrame();
			}


       		} else {                                              
       			if(maxx==SCREENMAXX){                           
                		minx=SCREENMINX;                        
                		maxx=SCREENMINX+SQUARESIZE-1;           
                		miny+=SQUARESIZE;                       
                		maxy+=SQUARESIZE;                       
       			} else {                                              
       				minx+=SQUARESIZE;                               
       				maxx+=SQUARESIZE;
			}
		RRReqAlloc();
		}
}

void RRPend()
{	
	static RRreqList *stareq=NULL;

	if(!stareq) 
		stareq=rrreqs;
	
	if(stareq) {
		stareq=FindRequest(&stareq->rrreq,rrreqs);
		if(stareq){
			if(stareq->next)
				stareq=stareq->next;
			else
				stareq=rrreqs;
		} else {
			stareq=rrreqs;
		}
	}
	if(stareq) {
		RRStatus status;
		RRreqList *tmpreq;
		RRConnList *tmpconn;
		fprintf(stderr,"\r");
		ConnectionInfo(&stareq->rrreq.connect,stderr);
		status=TryService(&stareq->rrreq.connect, &REQTIMEOUT,&RETRYTIMEOUT);
		switch(status) {
			case RRSERVICE_SUCCESS:
			case RRSERVICE_TIMEDOUT:
				fprintf(stderr," Square%4ld/%4ld pending",stareq->rrreq.sequence,PendingSquares);
				break;
			case RRSERVICE_BROKENCONNECTION:
			case RRSERVICE_UNCONNECTABLE:
                                fprintf(stderr,"\tunconnectable");
				/*PrintReqlist("reqs ",rrreqs);*/
                                while(tmpreq=FindReqByConn(rrreqs,&stareq->rrreq.connect)) {
					UnSetLWFlag(TO_PEND);
					SetLWFlag(REQUEST_TO_SEND);
                                	UnlinkListRequest(tmpreq,&rrreqs);
                                        LinkSortedListRequest(tmpreq,&rrreqo);
					PendingSquares--;
                                        fprintf(stderr,"\nSquare %d will be sent again\n",stareq->rrreq.sequence);
                                }
				break;
		}
	} 
	RRForceWrite(&rrreqr);
}


bool_t DoClient()
{
	if(LWMask & LWTable[LWProcedureIndex].flags)
		LWTable[LWProcedureIndex].lwfunc();
	LWProcedureIndex = (LWTable[LWProcedureIndex].lwfunc == NULL ) ? (int)NULL : LWProcedureIndex+1;
	return (LWMask & SCENE_RECEIVED);
}
