/*
 * node.c
 * Implementation of Node and it's collections.
 *
 * Copyright (C) Leni Mayo 2001-2002
 *
 *	This program is free software; you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License, version 2, as
 *	published by the Free Software Foundation.
 *	
 *	This program is distributed in the hope that it will be useful,
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *	GNU General Public License for more details.
 *	
 *	You should have received a copy of the GNU General Public License
 *	along with this program; if not, write to the Free Software
 *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <stdlib.h> /* for free()    */
#include <string.h>
#include <glib.h>
#include "log.h"
#include "pidmap.h"
#include "serviceid.h"
#include "node.h"

static void asStringCallback(gpointer key, gpointer value, gpointer pUserData);
static void foreachCallback(gpointer key, gpointer value, gpointer pUserData);
static void toListCallback(gpointer key, gpointer value, gpointer pUserData);

typedef struct
{
	CallbackServiceId fn;
	void    *pUserData;
} ForEachUserData;

Nodes * nodesNew()
{
	GHashTable *pTable;

	pTable = g_hash_table_new(NULL, NULL);

	return pTable;
}

void nodesDelete(Nodes *pTable)
{
	if (pTable)
	{
		g_hash_table_foreach(pTable, callbackFreeValue, NULL);

		g_hash_table_destroy(pTable);
	}
}

void nodesForeach(Nodes *pTable, CallbackServiceId fn, void *pUserData)
{
	ForEachUserData userData;
	userData.fn = fn;
	userData.pUserData = pUserData;

	g_hash_table_foreach(pTable, foreachCallback, &userData);
}

GSList * nodesGet(Nodes *pTable)
{
	GSList *pListReturn = NULL;

	g_hash_table_foreach(pTable, toListCallback, &pListReturn);

	return pListReturn;
}

Node * nodeAdd(Nodes *pTable, const ServiceId id)
{
	gpointer value;
	Node *pNode;

	assert(pTable);
	assert(id != 0);

	/* assert: no other Node with this serviceid is present
	*/
	value = g_hash_table_lookup(pTable, id);
	assert(value == NULL);

	pNode = malloc(sizeof(Node));  /* leni TODO: test memory alloc */
	pNode->id = id;
	pNode->fsm = eStateSpirit;
	pNode->pUserData = NULL;
	pNode->stopwatch = 0;

	g_hash_table_insert(pTable, id, pNode);

	return pNode;
}

void nodeRemove(Nodes *pTable, ServiceId id)
{
	gpointer value;  /* value is a (Node *) */

	assert(pTable);
	assert(id != 0);

	value = g_hash_table_lookup(pTable, id);

	assert(value != NULL);

	g_hash_table_remove(pTable, id);

	free(value);
}

Node * nodeFromId(Nodes *pTable, const ServiceId id)
{
	gpointer value;

	assert(pTable);

	value = g_hash_table_lookup(pTable, id);

	return value;
}

Node * nodeFromName(Nodes *pTable, const ServiceName name)
{
	ServiceId id = serviceIdFromName(name);
	Node *pReturn = NULL;

	assert(pTable);

	if (id)
	{
		pReturn = nodeFromId(pTable, id);
	}

	return pReturn;
}

void asStringCallback(gpointer key, gpointer value, gpointer pUserData)
{
	SafeBuf *pX = (SafeBuf *) pUserData;
	char buf[400];

	sprintfTo(pX, "    %s\n", nodeAsString((Node *) value, buf, sizeof(buf)));
}

void foreachCallback(gpointer key, gpointer value, gpointer pUserData)
{
	ForEachUserData *pForEachUserData = pUserData;
	Node *pNode = (Node *) value;

	assert(pNode);
	assert(pForEachUserData != NULL);

	(pForEachUserData->fn)(pNode->id, pForEachUserData->pUserData);
}

void toListCallback(gpointer key, gpointer value, gpointer pUserData)
{
	GSList **ppList = pUserData;
	Node *pNode = (Node *) value;

	assert(pNode && ppList);

	*ppList = g_slist_prepend(*ppList, pNode);
}

const char * nodeAsString(Node *pNode, char *buf, int bufsiz)
{
	SafeBuf x;

	assert(pNode);

	x.buf    = buf;
	x.bufsiz = bufsiz;

	sprintfTo(&x, "%s, %s, %4.2f seconds, userdata: %s",
	    serviceIdAsString(pNode->id), stateAsString(pNode->fsm),
		((float) pNode->stopwatch)/1000.0,
		(pNode->pUserData == NULL ? "no" : "yes"));

	return buf;
}

const char * nodesAsString(Nodes *pTable, char *buf, int bufsiz)
{
	SafeBuf x;

	x.buf    = buf;
	x.bufsiz = bufsiz;

	g_hash_table_foreach(pTable, asStringCallback, &x);
	
	return buf;
}
