//-----------------------------------------------------------------------------
// Copyright (c) 1995      Southeastern Universities Research Association,
//                         Continuous Electron Beam Accelerator Facility
//
// This software was developed under a United States Government license
// described in the NOTICE file included as part of this distribution.
//
//-----------------------------------------------------------------------------
//
// Description:
//	This header file contains the class definitions for the classes
//	associated with the construction of a model request object.
//
// Author:  Walt Akers
//
// Revision History:
//   ScriptRequestObject.cc,v
// Revision 1.1  1997/02/11  17:37:24  akers
// Directory restructure
//
// Revision 1.1  1997/01/30  20:35:34  akers
// Initial installation of Script Service
//
//-----------------------------------------------------------------------------
//

#include <ScriptService.h>
#include <ScriptRequestObject.h>
#include <cdevClock.h>

int ScriptRequestObject::syncCode = 0;

// *********************************************************************
// * ScriptRequestObject::ScriptRequestObject :
// *	This constructor initializes the internals of a device/message
// *	pair associated with the model server.
// *
// *	Returns nothing.
// *********************************************************************
ScriptRequestObject::ScriptRequestObject ( char * device, char * message, cdevSystem & system)
	: cdevRequestObject(device, message, system), syncFinished(0)
	{
	}
			     

// *****************************************************************************
// * ScriptRequestObject::sendNoBlock :
// * 	This function allows the caller to submit an asynchronous message to the
// *	server for processing.
// *****************************************************************************	
int ScriptRequestObject::sendNoBlock (cdevData * in, cdevData * out) 
	{
	ScriptService     * svc     = (ScriptService *)service_;
	cdevTranObj       * xobj    = new cdevTranObj(&system_, this, out, &svc->asyncCallback);
	cdevData          * Data    = ((in==NULL)?new cdevData:new cdevData(*in));

	return svc->submit(*xobj, *Data);
	}


// *****************************************************************************
// * ScriptRequestObject::sendCallback :
// * 	This function allows the caller to submit an asynchronous message to the
// *	server for processing.
// *****************************************************************************	
int ScriptRequestObject::sendCallback (cdevData * in, cdevCallback & callback) 
	{
	ScriptService * svc     = (ScriptService *)service_;
	cdevTranObj   * xobj    = new cdevTranObj(&system_, this, NULL, new cdevCallback(callback));
	cdevData      * Data    = ((in==NULL)?new cdevData:new cdevData(*in));
	
	xobj->enableDeleteCbk();
	return svc->submit(*xobj, *Data);
	}


// *****************************************************************************
// * ScriptRequestObject::send : 
// *	The send interface is used to provide synchronous I/O with the service.
// *
// *	Returns CDEV_SUCCESS on success or CDEV_ERROR on error.
// *****************************************************************************
int ScriptRequestObject::send ( cdevData * in, cdevData * out )
	{
	int             status  = CDEV_SUCCESS;
	ScriptService * svc     = (ScriptService *)service_;
	cdevCallback  * cb      = new cdevCallback(ScriptService::syncCallbackFunc, (void *)++syncCode);
	cdevTranObj   * xobj    = new cdevTranObj(&system_, this, out, cb);
	cdevData      * Data    = ((in==NULL)?new cdevData:new cdevData(*in));

	xobj->enableDeleteCbk();
	if((status = svc->submit(*xobj, *Data))==CDEV_SUCCESS)
		{	
		// *************************************************************
		// * I used to wait for a response here only if the outbound 
		// * cdevData object was non-null.  However, that provided 
		// * unexpected behavior to the client.  Now I wait whether 
		// * output data is expected or not.
		// *************************************************************
		cdevTimeValue t((double)SEND_WAIT_PERIOD);
		cdevClock timer;
		timer.schedule(NULL,t);

		// *************************************************************
		// * WAITING WITH system_.pend():
		// * 	Previously I was using system_.pend() to process events 
		// *	while waiting for the service to respond.  This resulted 
		// *	in a lock-up when the connection could not be 
		// * 	established or if the connection collapsed while in use.
		// *
		// * WAITING WITH system_.poll():
		// *	When in a heavy inbound traffic situation, the calls from other
		// *	services will trample all over the inbound data coming from the
		// *	model service.  This results in unreliable delivery and 
		// *	processing of messages from the model server.
		// * 
		// * WAITING WITH service_.poll():
		// *	So far so good.
		// *************************************************************
		for(syncFinished=0; !syncFinished && !timer.expired(); svc->poll());
		if   (!syncFinished)
			{
			status = CDEV_ERROR;
			system_.reportError(
				CDEV_SEVERITY_ERROR, 
				"cdevRequestObject", 
				this,
				"Transaction wasn't processed after %i seconds",
				SEND_WAIT_PERIOD);
			}
		else status = syncStatus;
		}
	return status;
	}
