//-----------------------------------------------------------------------------
// Copyright (c) 1994,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:
//		cdevSvcFind class Implementation
//
// Author:	Jie Chen
//
// Revision History:
//	 cdevSvcFinder.cc,v
// Revision 1.14  1997/08/21  13:31:17	chen
// indent a little
//
// Revision 1.13  1997/08/18  14:16:30	akers
// Ongoing development of CDEV accounting
//
// Revision 1.12  1997/08/15  18:08:31	akers
// Addition of CDEV Accounting
//
// Revision 1.11  1997/08/07  13:36:32	akers
// Converted CDEV_MAJOR_VERSION and CDEV_MINOR_VERSION to strings to support adding minor revision numbers
//
// Revision 1.10  1997/02/18  15:48:04	chen
// port to linux 2.0.x
//
// Revision 1.9  1996/03/28  19:13:34  akers
// Minor changes in support of new version
//
// Revision 1.8  1996/03/28  18:31:25  akers
// Corrected error in cdevSvcFinder.cc
//
// Revision 1.7  1996/03/27  16:02:02  akers
// Modified service loader to search multiple directories
//
// Revision 1.6  1995/10/18  17:45:36  chen
// to reflect change in shObjLoader
//
// Revision 1.5  1995/10/17  13:26:07  chen
// change to handle shobj interface change
//
// Revision 1.4  1995/10/06  19:49:39  chen
// remove explict relation with caService
//
// Revision 1.3  1995/09/20  16:14:05  chen
// Fix a bug when there is no CDEVSHOBJ
//
// Revision 1.2  1995/06/30  16:01:34  chen
// use generic list
//
// Revision 1.1.1.1  1995/06/16  17:14:07  epics
// initial import of cdev
//
//
#include <stdio.h>
#include <string.h>
#include "cdevSvcFinder.h"
#include <ctype.h>

#ifdef _CDEV_ACCOUNTING_
#include "cdevAccount.cc"
#endif

cdevSvcFinder::cdevSvcFinder (cdevSystem& system)
:ldList_(), system_(system)
	{
#ifdef _CDEV_ACCOUNTING_
	cdevGlobalAccountEntry = new cdevAccountEntry;
	atexit(removeGlobalAccountRecord);
#endif
	
#ifdef _TRACE_OBJECTS
	printf("Create cdevSvcFinder class \n");
#endif
	}

cdevSvcFinder::~cdevSvcFinder (void)
	{
#ifdef _CDEV_ACCOUNTING_
	if(cdevGlobalAccountEntry!=NULL)
		{
		delete cdevGlobalAccountEntry;
		cdevGlobalAccountEntry = NULL;
		}
#endif
	
	cdevSlistIterator sit (ldList_);
	shObjLoader *tloader = 0;
	
	for (sit.init(); !sit; ++sit) {
		tloader = (shObjLoader *)sit ();
		delete tloader;
		}
#ifdef _TRACE_OBJECTS
	printf("Delete cdevSvcFinder class \n");
#endif
	}

int
cdevSvcFinder::getService (char *serviceName,
						   cdevService* &service)
	{
#ifdef SHOBJ
	service = loadService (serviceName);
	if (service)
		return 0;
	else
		return -1;
#else
	service = findService (serviceName);
	if (service)
		return 0;
	else
		return -1;
#endif
	}

#ifdef SHOBJ
cdevService *
cdevSvcFinder::loadService (char *serviceName)
	{
	int status = -1;
	cdevService* (*create)(char *, cdevSystem *);
	cdevService *svc = NULL;
	
	// ***************************************************************************
	// * This method detect if the specified service name is already loaded, if
	// * not, it will search a list of three possible locations in an attempt to
	// * load the service.
	// ***************************************************************************
	if (!system_.serviceCreated (serviceName))
		{
		char	location[3][256];
		char *envVar = ::getenv ("CDEVSHOBJ");
		
		*location[0] = '\0';
		*location[1] = '\0';
		*location[2] = '\0';
		
		if(envVar!=NULL && *envVar)
			{
#ifdef _WIN32
			// *************************************************************
			// * The first search location is in the versioned directory
			// * under the cdev shared object directory... this would look
			// * like... "/usr/cdev/shobj/1.3/filename.so"
			// *************************************************************
			sprintf(location[0], 
				"%s\\%s\\%s.dll", 
				envVar, 
				CDEV_VERSION_STRING,
				serviceName);
			// *************************************************************
			// * The second search location is within the cdev shared object
			// * directory... this would look like... 
			// * "/usr/cdev/shobj/filename.so"
			// *************************************************************
			sprintf(location[1], 
				"%s\\%s.dll", 
				envVar, 
				serviceName);
			}
		// *********************************************************************
		// * The third search location is within the /usr/local/lib directory...
		// * This would look like... "/usr/local/lib/filename.so"
		// *********************************************************************
		GetSystemDirectory(location[2], 256);
		sprintf(location[2]+strlen(location[2]), "\\%s.dll", serviceName);
#else
		// *************************************************************
		// * The first search location is in the versioned directory
		// * under the cdev shared object directory... this would look
		// * like... "/usr/cdev/shobj/1.3/filename.so"
		// *************************************************************
		sprintf(location[0], 
			"%s/%s/%s.so", 
			envVar, 
			CDEV_VERSION_STRING,
			serviceName);
		// *************************************************************
		// * The second search location is within the cdev shared object
		// * directory... this would look like... 
		// * "/usr/cdev/shobj/filename.so"
		// *************************************************************
		sprintf(location[1], 
			"%s/%s.so", 
			envVar, 
			serviceName);
		}
	// *********************************************************************
	// * The third search location is within the /usr/local/lib directory...
	// * This would look like... "/usr/local/lib/filename.so"
	// *********************************************************************
	sprintf(location[2], "/usr/local/lib/%s.so", serviceName);
#endif
	
	// *********************************************************************
	// * Walk through the list of possible locations until the shared 
	// * library is successfully loaded, or until all options have been
	// * exhausted.
	// *********************************************************************
	status = -1;
	for(int idx=0; idx<3 && status!=0; idx++)
		{
		if(*location[idx] != 0)
			{
			shObjLoader *loader = new shObjLoader (location[idx]);
			if((status = loader->load ())==0)
				{
				char symbolName[64];
				sprintf (symbolName, "new%s", serviceName);
				symbolName[3] = toupper (symbolName[3]);
				status = loader->findProcedureSym (symbolName, (void **)&create);
				}
		
			// *************************************************************
			// * If the service was successfully loaded, then add it to the
			// * system.	Otherwise, delete the loader object.
			// *************************************************************
			if(status==0)
				{	
				svc = (*create)(serviceName, &system_);
				ldList_.add ((void *)loader);
				
				// ***********************************************************
				// * If the service was successfully loaded, use the 
				// * cdevAccountEntry object to record the transaction.
				// ***********************************************************
#ifdef _CDEV_ACCOUNTING_
				cdevGlobalAccountEntry->addService(location[idx]);
#endif	
				}
			else delete loader;
			}
		}
	}
	else svc = system_.service (serviceName);
	return svc;
}

#endif
