/****************************************************************************
*
* $RCSfile: LibraryManager.c $
* $Revision: 1.1 $
* $Date: 1997/06/29 07:52:44 $
* $Author: ssolie $
*
*****************************************************************************
*
* Copyright (c) 1997 Software Evolution.  All Rights Reserved.
*
*****************************************************************************
*
* LibraryManager.c -- Library manager module
*
* This file contains the source for using LibraryManager objects.
*/

#include <exec/memory.h>

#include <proto/exec.h>

#include "Debug.h"
#include "LibraryManager.h"


/*** Global variables ***/
IMPORT struct ExecBase *SysBase;


/*** Local data types ***/
struct LibraryManagerClass {
	struct Library **libs;	/* array of library pointers */
	UWORD num;				/* number of library pointers */
	UWORD max;				/* maximum number of library pointers */
};


/*** Local constants ***/
const UWORD LIBS_PER_ALLOC = 10;	/* array expansion factor */


/****** SERL/newLibraryManager **********************************************
*
*   NAME
*       newLibraryManager -- Create LibraryManager object
*
*   SYNOPSIS
*       lib_mgr = newLibraryManager(tags)
*
*       LibraryManager newLibraryManager(struct TagItem *);
*
*   FUNCTION
*       This function creates a new LibraryManager object.  These objects
*       track the library pointers and will automatically close all the
*       libraries that were opened when the object is destroyed.
*
*   INPUTS
*       tags - Array of TagItem's (currently set to NULL).
*
*   RESULT
*       Reference to a LibraryManager object if successful or NULL on error.
*
*   SEE ALSO
*       SERL/deleteLibraryManager()
*
*****************************************************************************
*
*/
LibraryManager newLibraryManager(struct TagItem tags[])
{
	LibraryManager this;

	D(bug("newLibraryManager(%lx)\n", tags));

	if ( tags != NULL )
		return(NULL);

	this = AllocVec(sizeof(struct LibraryManagerClass), MEMF_CLEAR);
	if ( this == NULL )
		return(NULL);

	this->num = 0;
	this->max = LIBS_PER_ALLOC;
	this->libs =
		AllocVec((ULONG)this->max * sizeof(struct Library*), MEMF_CLEAR);
	if ( this->libs == NULL )  {
		FreeVec(this);
		return(NULL);
	}

	return(this);
}


/****** SERL/deleteLibraryManager *******************************************
*
*   NAME
*       deleteLibraryManager -- Delete LibraryManager object
*
*   SYNOPSIS
*       deleteLibraryManager(lib_mgr)
*
*       VOID deleteLibraryManager(LibraryManager);
*
*   FUNCTION
*       This function deletes a LibraryManager object and closes any
*       libraries it was managing.
*
*   INPUTS
*       lib_mgr - Reference to LibraryManager or NULL.
*
*   SEE ALSO
*       SERL/newLibraryManager()
*
*****************************************************************************
*
*/
VOID deleteLibraryManager(LibraryManager this)
{
	UWORD i;

	D(bug("deleteLibraryManager(%lx)\n", this));

	if ( this != NULL )  {
		if ( this->libs != NULL )  {
			D2(bug(" closing %lu libraries\n", this->num));

			for ( i = 0; i < this->num; i++ )
				CloseLibrary(this->libs[i]);

			FreeVec(this->libs);
		}

		FreeVec(this);
	}
}


/****** SERL/openLibrary ****************************************************
*
*   NAME
*       openLibrary -- Open managed system library
*
*   SYNOPSIS
*       lib = openLibrary(lib_mgr, name, version)
*
*       struct Library *openLibrary(LibraryManager, STRPTR, ULONG);
*
*   FUNCTION
*       This function will open a system library under LibraryManager
*       control.  The LibraryManager will track the library pointer so
*       that the library may be closed when the manager is destroyed.
*
*       The version parameter is not allowed to be zero which forces the
*       caller to know the minimum version required.  This was done to
*       try to decrease future compatibility problems.
*
*   INPUTS
*       lib_mgr - Reference to LibraryManager or NULL.
*       name - Name of the library to open or NULL.
*       version - Minimum version of the library to be opened (must be > 0).
*
*   RESULT
*       Pointer to the newly opened system library or NULL on error.
*
*   SEE ALSO
*
*****************************************************************************
*
*/
struct Library *openLibrary(LibraryManager this, STRPTR name, ULONG version)
{
	struct Library **new_libs;
	struct Library *library;
	UWORD new_max;

	D(bug("openLibrary(%lx, %s, %lu)\n", this, name, version));

	if ( this == NULL || name == NULL || version == 0 )
		return(NULL);

	/*** Ensure there is space for the resource tracking ***/
	if ( this->num == this->max )  {
		new_max = this->max + LIBS_PER_ALLOC;
		new_libs =
			AllocVec((ULONG)new_max * sizeof(struct Library*), MEMF_CLEAR);
		if ( new_libs == NULL )
			return(NULL);

		CopyMem(this->libs, new_libs,
			(ULONG)this->max * sizeof(struct Library*));

		FreeVec(this->libs);

		this->libs = new_libs;
		this->max = new_max;
	}

	/*** Attempt to open the library and return the result ***/
	library = OpenLibrary(name, version);
	if ( library != NULL )  {
		this->libs[this->num] = library;
		this->num++;
	}

	return(library);
}
