/* -----------------------------------------------------------------------------
 *  Copyright (c) 1995,1996 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:
 *       Class implementing request objects for collections
 * 
 *  Author:  Walt Akers
 * 
 *  Revision History:
 *    cdevCollectionRequest.cc,v
// Revision 1.2  1996/11/21  16:55:00  akers
// Ongoing development
//
// Revision 1.1  1996/11/12  20:32:14  akers
// New collection device source code
//
 * -----------------------------------------------------------------------------
 */ 

#include <cdevCollectionRequest.h>
#include <cdevGrpCollectionRequest.h>

int cdevCollectionRequest::RESULT_CODE_TAG = 0;

// *****************************************************************************
// * cdevCollectionRequest::cdevCollectionRequest :
// *	This is the constructor for this abstract base class.  Because this 
// *	object has no internal data components the constructor is only required
// *	to call the constructor for the underlying cdevRequestObject.
// *
// *	It ensures that the resultCode tag has been added to the 
// *	cdevData GlobalTagTable.
// *****************************************************************************
cdevCollectionRequest::cdevCollectionRequest 
	(char **, int, char *msg, cdevSystem &sys)
	: cdevRequestObject("\0", msg, sys)
	{
	// *********************************************************************
	// * Install the RESULT_CODE_TAG at a location of 30 or higher if it 
	// * does not already exist.
	// *********************************************************************
	if(cdevData::tagC2I("resultCode", &RESULT_CODE_TAG)!=CDEV_SUCCESS)
		{
		RESULT_CODE_TAG = 0;
		for(int i=30; RESULT_CODE_TAG==0 && i<65534; i++)
			{
			cdevData::insertTag(i, "resultCode");
			cdevData::tagC2I("resultCode", &RESULT_CODE_TAG);
			}
		}
	}
	
// *****************************************************************************
// * cdevCollectionRequest::~cdevCollectionRequest :
// *	This is the virtual destructor for the class.  It is a protected 
// *	placeholder that prevents the application from deleting a 
// *	cdevCollectionRequest directly.
// *****************************************************************************
cdevCollectionRequest::~cdevCollectionRequest ( void )
	{
	}
	

// *****************************************************************************
// * cdevCollectionRequest::attachPtr :
// *	This is the factory mechanism that is used by the cdevCollection
// *	to generate a cdevCollectionRequest object.  
// *	
// *	When called, it returns either a service-specific cdevCollectionRequest 
// *	object or a cdevGrpCollectionRequest object.
// *****************************************************************************
cdevCollectionRequest * 
cdevCollectionRequest::attachPtr(cdevCollection &dev, char *msg, cdevSystem & sys)
	{
	int  serviceCount = 0;
	char serviceName[255];
	cdevCollectionRequest * result = NULL;
	
	// *********************************************************************
	// * Get the list of device names that is associated with this 
	// * collection device. 
	// *********************************************************************
	int    deviceNameCnt = 0;
	char **deviceNames   = dev.getList();
	char **deviceNamePtr = deviceNames;
	
	for(deviceNamePtr = deviceNames; *deviceNamePtr!=NULL; deviceNamePtr++)
		{
		deviceNameCnt++;
		}
		
	// *********************************************************************
	// * Obtain a pointer to the cdevDirectory device.  This will be used
	// * to lookup the name of the service that is associated with each 
	// * device/message combination.
	// *********************************************************************
	cdevDevice *dir = cdevDevice::attachPtr("cdevDirectory");

	*serviceName  = 0;
	deviceNamePtr = deviceNames;
	while(*deviceNamePtr!=NULL && serviceCount<2)
		{
		cdevData input, output;
                                
		// ************************************************************
		// * Insert the name of the device and message to be resolved.
		// ************************************************************
		input.insert("device", *deviceNamePtr);
		input.insert("message", msg);
                              
		// ************************************************************
		// Submit the request to the cdevDirectory object using the
		// send command, and output the result if successful.
		// ************************************************************
		if(dir->send("service", input, output)==CDEV_SUCCESS)
			{
			char * servicePtr;
			output.find("value", (void * &)servicePtr);
			if(servicePtr && *servicePtr)
				{
				if(*serviceName==0)
					{
					strcpy(serviceName, servicePtr);
					serviceCount = 1;
					}
				else if(strcmp(serviceName, servicePtr))
					{
					serviceCount++;
					}
				}
			}
		deviceNamePtr++;
		}
	// *********************************************************************
	// * If there is only one service involved in the cdevCollection, use
	// * the service provided cdevCollectionRequest.
	// *********************************************************************
	if(serviceCount==1) 
		{
		cdevService * service = NULL;
		if(!sys.serviceCreated(serviceName)) 
			{
			sys.loadService(serviceName);
			}
		if((service = sys.service(serviceName))!=NULL)
			{
			// *****************************************************
			// * Get the cdevCollectionRequest directly from the 
			// * service...
			// *****************************************************
			service->getCollectionRequest 
				(deviceNames, deviceNameCnt, msg, result);

			// *****************************************************
			// * Because this is a mono-service collection, the
			// * service will be inserted into the request object.
			// *****************************************************
			if(result) result->service(service);
			}
		}
	// *********************************************************************
	// * If there is more than one service involved in the cdevCollection, 
	// * return a cdevGrpCollectionRequest object.
	// *********************************************************************
	else if(serviceCount>1)
		{
		result = new cdevGrpCollectionRequest
			(deviceNames, deviceNameCnt, msg, sys);
		}

	// *********************************************************************
	// * If the result request object is not NULL, then register its name
	// * with the cdevCollection that was used to create it.
	// *********************************************************************
	if(result)
		{
		dev.registerReqObject(result);
		result->device(&dev);
		result->setContext(dev.getContext());		
		}
	else 
		{
		sys.reportError(CDEV_SEVERITY_ERROR, 
				"cdevCollectionRequest",
				NULL,
				"Attempted operation on an empty collection"
				);
		}
	// *********************************************************************
	// * Delete the array of pointers, but not the pointers themselves.
	// *********************************************************************
	delete deviceNames;
	return result;
	}
