/*
 * t4storagereg.cpp --
 *
 *	Implementation of the the T4Graph storage registry.
 *
 *	Authors: Jacob Levy and Jean-Claude Wippler.
 *		 jyl@best.com	jcw@equi4.com
 *
 * Copyright (c) 2000-2003, JYL Software Inc.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE, EVEN IF
 * JYL SOFTWARE INC. IS MADE AWARE OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "t4graphrep.h"

/*
 * Mutex protecting the storage registry:
 */

TCL_DECLARE_MUTEX(storageRegistryMutex)

/*
 * This variable holds the global storage registry. It is protected from
 * multiple concurrent access by the above mutex.
 */

static Tcl_HashTable *storageRegistry = NULL;

/*
 * Initialize the storage registry (in a thread safe manner). Returns
 * a boolean indicating whether this call was the one that set up the
 * registry.
 */

bool
T4Graph_InitStorageRegistry()
{
    bool settingUp = false;
    Tcl_MutexLock(storageRegistryMutex);

    if (storageRegistry == NULL) {
	settingUp = true;
	storageRegistry = (Tcl_HashTable *) Tcl_Alloc(sizeof(Tcl_HashTable));
	Tcl_InitHashTable(storageRegistry, TCL_ONE_WORD_KEYS);
    }

    Tcl_MutexUnlock(storageRegistryMutex);

    return settingUp;
}

/*
 * Destroy the storage registry.
 */

void
T4Graph_DestroyStorageRegistry()
{
    Tcl_MutexLock(storageRegistryMutex);

    if (storageRegistry != NULL) {
	Tcl_DeleteHashTable(storageRegistry);
	Tcl_Free((char *) storageRegistry);
	storageRegistry = NULL;
    }

    Tcl_MutexUnlock(storageRegistryMutex);
}

/*
 * Iterate over all registered storages. This function starts the iteration,
 * returns the first storage and stores the iteration information in the
 * passed Tcl_HashSearch argument.
 */

T4Storage *
T4Graph_FirstStorage(Tcl_HashSearch *searchp)
{
    Tcl_HashEntry *ep;
    T4Storage *sp = NULL;

    Tcl_MutexLock(storageRegistryMutex);

    if (storageRegistry == NULL) {
	Tcl_MutexUnlock(storageRegistryMutex);
	return NULL;
    }

    ep = Tcl_FirstHashEntry(storageRegistry, searchp);
    if (ep != NULL) {
	sp = (T4Storage *) Tcl_GetHashValue(ep);
    }
    Tcl_MutexUnlock(storageRegistryMutex);

    return sp;
}

/*
 * This function iterates to the next registered storage.
 */

T4Storage *
T4Graph_NextStorage(Tcl_HashSearch *searchp)
{
    Tcl_HashEntry *ep;
    T4Storage *sp = NULL;

    Tcl_MutexLock(storageRegistryMutex);

    if (storageRegistry == NULL) {
	Tcl_MutexUnlock(storageRegistryMutex);
	return NULL;
    }

    ep = Tcl_NextHashEntry(searchp);
    if (ep != NULL) {
	sp = (T4Storage *) Tcl_GetHashValue(ep);
    }
    Tcl_MutexUnlock(storageRegistryMutex);

    return sp;
}

/*
 * Find a T4Storage via its unique ID, if it's been registered.
 */

T4Storage *
T4Graph_FindRegisteredStorage(int id)
{
    Tcl_HashEntry *ep;

    Tcl_MutexLock(storageRegistryMutex);

    if (storageRegistry == NULL) {
	Tcl_MutexUnlock(storageRegistryMutex);
	return NULL;
    }

    ep = Tcl_FindHashEntry(storageRegistry, (const char *) id);
    Tcl_MutexUnlock(storageRegistryMutex);

    if (ep == NULL) {
	return NULL;
    }
    return (T4Storage *) Tcl_GetHashValue(ep);
}

/*
 * Create, register and return a T4Storage. If the storage is already
 * registered, return that one.
 */

T4Storage *
T4Graph_RegisterStorage(e4_Storage s, char *fnm, char *dnm)
{
    Tcl_HashEntry *ep;
    int id = s.GetTemporaryUID();
    int isnew;
    T4Storage *sp;

    Tcl_MutexLock(storageRegistryMutex);

    if (storageRegistry == NULL) {
	Tcl_MutexUnlock(storageRegistryMutex);
	return NULL;
    }

    ep = Tcl_CreateHashEntry(storageRegistry, (const char *) id, &isnew);
    if (!isnew) {
	Tcl_MutexUnlock(storageRegistryMutex);
	return (T4Storage *) Tcl_GetHashValue(ep);
    }

    sp = new T4Storage(s, fnm, dnm);
    Tcl_SetHashValue(ep, sp);

    Tcl_MutexUnlock(storageRegistryMutex);

    return sp;
}

/*
 * Unregister a storage given its ID.
 */

void
T4Graph_UnregisterStorage(int id)
{
    Tcl_HashEntry *ep;

    Tcl_MutexLock(storageRegistryMutex);

    if (storageRegistry != NULL) {
	ep = Tcl_FindHashEntry(storageRegistry, (const char *) id);
	if (ep != NULL) {
	    Tcl_DeleteHashEntry(ep);
	}
    }

    Tcl_MutexUnlock(storageRegistryMutex);
}

    
