//-----------------------------------------------------------------------------
// 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:
//   cdevSimpleRequestObject.cc,v
// Revision 1.1  1996/11/21  18:22:19  akers
// Non-Server Oriented Service
//
// Revision 1.1  1996/04/30  15:37:30  akers
// Simple CDEV Service
//
// Revision 1.1.1.1  1996/02/28  16:36:21  akers
// Initial release of support for ACE Services
//
//-----------------------------------------------------------------------------
//

#include <cdevSimpleService.h>
#include <cdevSimpleRequestObject.h>
#include <cdevClock.h>
#include <cdevTranNode.h>

// *********************************************************************
// * cdevSimpleRequestObject::cdevSimpleRequestObject :
// *	This constructor initializes the internals of a device/message
// *	pair associated with the model server.
// *
// *	Returns nothing.
// *********************************************************************
cdevSimpleRequestObject::cdevSimpleRequestObject ( char * device, char * message, cdevSystem & system)
	: cdevRequestObject(device, message, system)
	{
	cdevData::tagC2I("transaction", &TRANSACT_TAG);
	cdevData::tagC2I("transobject", &TRANSOBJ_TAG);
	}
			     

// *****************************************************************************
// * cdevSimpleRequestObject::sendNoBlock :
// * 	This function allows the caller to submit an asynchronous message to the
// *	server for processing.
// *****************************************************************************	
int cdevSimpleRequestObject::sendNoBlock (cdevData * in, cdevData * out) 
	{
	cdevSimpleService * svc     = (cdevSimpleService *)service_;
	cdevTranNode      * xobj    = new cdevTranNode(&system_, this, out, &svc->callback);
	char              * Device  = strdup(deviceName_);
	char              * Message = strdup(message_);
	cdevData          * Data    = ((in==NULL)?new cdevData:new cdevData(*in));

	svc->submit(xobj, Device, Message, Data);
	
	return CDEV_SUCCESS;
	}


// *****************************************************************************
// * cdevSimpleRequestObject::sendCallback :
// * 	This function allows the caller to submit an asynchronous message to the
// *	server for processing.
// *****************************************************************************	
int cdevSimpleRequestObject::sendCallback (cdevData * in, cdevCallback & callback) 
	{
	cdevSimpleService * svc     = (cdevSimpleService *)service_;
	cdevTranNode      * xobj    = new cdevTranNode(&system_, this, NULL, new cdevCallback(callback));
	char              * Device  = strdup(deviceName_);
	char              * Message = strdup(message_);
	cdevData          * Data    = ((in==NULL)?new cdevData:new cdevData(*in));
	
	xobj->enableDeleteCbk();
	svc->submit(xobj, Device, Message, Data);
	
	return CDEV_SUCCESS;
	}


// *****************************************************************************
// * cdevSimpleRequestObject::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 cdevSimpleRequestObject::send ( cdevData * in, cdevData * out )
	{
	int                 status  = CDEV_SUCCESS;
	cdevSimpleService * svc     = (cdevSimpleService *)service_;
	cdevTranNode      * xobj    = new cdevTranNode(&system_, this, out, &svc->callback);
	char              * Device  = strdup(deviceName_);
	char              * Message = strdup(message_);
	cdevData          * Data    = ((in==NULL)?new cdevData:new cdevData(*in));

	xobj->permanent(1);
	svc->submit(xobj, Device, Message, Data);

	// *********************************************************************
	// * 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(30.0);
	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.
	// *********************************************************************
	while(!xobj->finished() && !timer.expired()) service_->poll();
	if   (!xobj->finished())
		{
		status = CDEV_ERROR;
		system_.reportError(
			CDEV_SEVERITY_ERROR, 
			"cdevRequestObject", 
			this,
			"Transaction wasn't processed after 30 seconds");
		}
	
	delete xobj;
	return status;
	}
