/*
 * No rights reserved.  This code is public domain.
 *
 * Rob Mayoff <mayoff@dqd.com>
 */

static char rcsid[] = "@(#) $Id: detach.c,v 1.1 2000/03/08 15:28:34 mayoff stable $";

#include "ns.h"
#include "utils.h"

static Ns_Mutex mutex;
static Tcl_HashTable detachedChannels;

static int
detachFileCommand(ClientData data, Tcl_Interp *interp,
	int argc, char *argv[])
{
	Tcl_Channel channel;

	if (argc != 3) {
		Tcl_AppendResult(interp, "usage: ", argv[0],
			" channelId detachedName", NULL);
		return TCL_ERROR;
	}

	channel = Tcl_GetChannel(interp, argv[1], NULL);
	if (channel == NULL) {
		Tcl_AppendResult(interp, argv[1],
			" is not a valid channelId", NULL);
		return TCL_ERROR;
	}

	Ns_MutexLock(&mutex);

	{
		int newFlag;
		Tcl_HashEntry *entry;

		entry = Tcl_CreateHashEntry(&detachedChannels, argv[2], &newFlag);
		if (Tcl_GetHashValue(entry) != NULL) {
			Tcl_AppendResult(interp, "error: ", argv[2],
				" already exists in detachedChannels table", NULL);
			Ns_MutexUnlock(&mutex);
			return TCL_ERROR;
		}

		Tcl_SetHashValue(entry, channel);
		Tcl_RegisterChannel(NULL, channel);
		Tcl_UnregisterChannel(interp, channel);
	}

	Ns_MutexUnlock(&mutex);
	return TCL_OK;
}

static int
attachFileCommand(ClientData data, Tcl_Interp *interp,
	int argc, char *argv[])
{
	if (argc != 2) {
		Tcl_AppendResult(interp, "usage: ", argv[0], " detachedName", NULL);
		return TCL_ERROR;
	}

	Ns_MutexLock(&mutex);

	{
		Tcl_HashEntry *entry;
		Tcl_Channel channel;

		entry = Tcl_FindHashEntry(&detachedChannels, argv[1]);
		if (entry == NULL || Tcl_GetHashValue(entry) == NULL) {
			Tcl_AppendResult(interp, "error: ", argv[1],
			    " is not the name of a detached channel",
			    NULL);
			Ns_MutexUnlock(&mutex);
			return TCL_ERROR;
		}

		channel = (Tcl_Channel)Tcl_GetHashValue(entry);
		Tcl_SetHashValue(entry, NULL);
		Tcl_RegisterChannel(interp, channel);
		Tcl_UnregisterChannel(NULL, channel);

		Tcl_SetResult(interp, Tcl_GetChannelName(channel), TCL_VOLATILE);
	}

	Ns_MutexUnlock(&mutex);
	return TCL_OK;
}

static int
addDetachCommands(Tcl_Interp *interp, ClientData data) {
	Tcl_CreateCommand(interp, "dqd_detachfile", detachFileCommand, NULL, NULL);
	Tcl_CreateCommand(interp, "dqd_attachfile", attachFileCommand, NULL, NULL);
	return NS_OK;
}

int
detachInit(char *server, char *module)
{
	Ns_MutexInit(&mutex);
	Tcl_InitHashTable(&detachedChannels, TCL_STRING_KEYS);

	return Ns_TclInitInterps(server, addDetachCommands, NULL);
}

