#ifndef __NIH_ITERATORS
#define __NIH_ITERATORS
/**
 * Author: James Hunt <james.hunt@ubuntu.com>
 * Description: Unofficial set of functions to use in gdb
 * (where their upper-case NIH macro equivalents are not available).
 * To build with a main driver:
 *
 *  gcc -DMAIN_DRIVER -std=gnu99 -g -Wall -pedantic -o nih_iterators nih_iterators.c `pkg-config --cflags --libs libnih`
 *
 **/
#include <nih/test.h>
#include <nih/macros.h>
#include <nih/list.h>
#include <nih/hash.h>
#include <nih/tree.h>
#include <nih/main.h>
#include <nih/timer.h>
#include <nih/error.h>
#include <nih/option.h>
#include <nih/command.h>
#include <nih/logging.h>
#include <nih/alloc.h>
#include <nih/string.h>

typedef int (*NihListHandler) (NihList *entry, void *data);

int nih_list_foreach (const NihList *list, size_t *len,
		       NihListHandler handler, void *data)
	__attribute__((unused));

int nih_hash_foreach (const NihHash *hash, size_t *len,
		      NihListHandler handler, void *data)
	__attribute__((unused));

int nih_tree_foreach (NihTree *tree, size_t *len,
		      NihTreeFilter handler, void *data)
	__attribute__((unused));

size_t nih_list_count (const NihList *list)
	__attribute__((unused));

size_t nih_hash_count (const NihHash *hash)
	__attribute__((unused));

size_t nih_tree_count (NihTree *tree)
	__attribute__((unused));

/**
 * dummy_nih_list_handler:
 *
 * @entry: list entry,
 * @data: data passed to function.
 *
 * Dummy list handler that can be used with gdb:
 *
 * - set a break on this function.
 * - pass this function to the appropriate *_foreach() function.
 * - when the breakpoint is triggered, cast @entry to the appropriate type
 *   for display/manipulation. Example:
 *
 *   print *(JobClass *)entry;
 *
 * Returns: 1 always.
 **/
int
dummy_nih_list_handler (NihList *entry, void *data)
{
	/* gcc magic to stop function from being optimized away */
	asm ("");

	return 1;
}

/**
 * nih_list_foreach:
 *
 * @list: list,
 * @len: optional output parameter that will contain length of list,
 * @handler: optional function called for each list entry,
 * @data: optional data to pass to handler along with list entry.
 *
 * Iterate over specified list.
 *
 * One of @len or @handler may be NULL.
 * If @handler is NULL, list length will still be returned in @len.
 * If @handler returns 1, @len will be set to the number of list entries
 * processed successfully up to that point.
 *
 * Returns: 0 on success, or -1 if handler returns an error.
 **/
int
nih_list_foreach (const NihList *list, size_t *len,
		NihListHandler handler, void *data)
{
	int ret;

	nih_assert (list);

	if (len) *len = 0;

	if (!len && !handler) return 0;

	NIH_LIST_FOREACH (list, iter) {
		if (handler) {
			ret = handler (iter, data);
			if (ret == FALSE) return -1;
		}
		if (len) ++*len;
	}

	return 0;
}

/**
 * nih_hash_foreach:
 *
 * @hash: hash,
 * @len: optional output parameter that will contain count of hash entries,
 * @handler: optional function called for each hash entry,
 * @data: optional data to pass to handler along with hash entry.
 *
 * Iterate over specified hash.
 *
 * One of @len or @handler may be NULL.
 * If @handler is NULL, count of hash entries will still be returned in @len.
 * If @handler returns 1, @len will be set to the number of hash entries
 * processed successfully up to that point.
 *
 * Returns: 0 on success, or -1 if handler returns an error.
 **/
int
nih_hash_foreach (const NihHash *hash, size_t *len,
		NihListHandler handler, void *data)
{
	int ret;

	nih_assert (hash);

	if (len) *len = 0;

	if (!len && !handler) return 0;

	NIH_HASH_FOREACH (hash, iter) {
		if (handler) {
			ret = handler (iter, data);
			if (ret == FALSE) return -1;
		}
		if (len) ++*len;
	}

	return 0;
}


/**
 * nih_tree_foreach:
 *
 * @tree: tree,
 * @len: optional output parameter that will contain count of tree nodes,
 * @handler: optional function called for each tree node,
 * @data: optional data to pass to handler along with tree node.
 *
 * Iterate over specified tree.
 *
 * One of @len or @handler may be NULL.
 * If @handler is NULL and @len is non-NULL, count of tree nodes will
 * still be returned in @len.
 * If @handler returns 1, @len will be set to the number of tree nodes
 * processed successfully up to that point.
 *
 * Returns: 0 on success, or -1 if handler returns an error.
 **/
int
nih_tree_foreach (NihTree *tree, size_t *len,
		NihTreeFilter handler, void *data)
{
	int ret;

	nih_assert (tree);

	if (len) *len = 0;

	if (!len && !handler) return 0;

	NIH_TREE_FOREACH_FULL (tree, iter, handler, data) {
		if (handler) {
			ret = handler (iter, data);
			if (!ret) return -1;
		}
		if (len) ++*len;
	}

	return 0;
}

/**
 * nih_list_count:
 *
 * @list: list.
 * 
 * Returns: count of number of entries in @list.
 **/
size_t
nih_list_count (const NihList *list)
{
	size_t len = 0;
	int ret;

	nih_assert (list);

	ret = nih_list_foreach (list, &len, NULL, NULL);

	return (ret == -1 ? 0 : len);
}

/**
 * nih_hash_count:
 *
 * @hash: hash.
 * 
 * Returns: count of number of entries in @hash.
 **/
size_t
nih_hash_count (const NihHash *hash)
{
	size_t len = 0;
	int ret;

	nih_assert (hash);

	ret = nih_hash_foreach (hash, &len, NULL, NULL);

	return (ret == -1 ? 0 : len);
}

/**
 * nih_tree_count:
 *
 * @tree: tree.
 * 
 * Returns: count of number of entries in @tree.
 **/
size_t
nih_tree_count (NihTree *tree)
{
	size_t len = 0;
	int ret;

	nih_assert (tree);

	ret = nih_tree_foreach (tree, &len, NULL, NULL);

	return (ret == -1 ? 0 : len);
}

#ifdef MAIN_DRIVER
int
handler (NihList *entry, void *data)
{
	NihListEntry *node = (NihListEntry *)entry;

	nih_message ("got str='%s'", node->str);
	return 1;
}

int
main (int argc, char *argv[])
{
	size_t              len;
	nih_local NihList  *list;
	NihListEntry       *node = NULL;

	list = NIH_MUST ( nih_list_new (NULL));

	nih_assert (list->prev == list);
	nih_assert (list->next == list);

	/* node 1 */
	node = NIH_MUST (nih_list_entry_new (list));
	nih_assert (node);

	node->str = NIH_MUST (nih_strdup (node, "hello world"));
	nih_list_add (list, &node->entry);

	/* node 2 */
	node = NIH_MUST (nih_list_entry_new (list));
	nih_assert (node);

	node->str = NIH_MUST (nih_strdup (node, "wibble"));
	nih_list_add (list, &node->entry);

	nih_list_foreach (list, &len, handler, NULL);

	nih_message ("(len=%lu, %lu)",
            (unsigned long int)len,
            (unsigned long int)nih_list_count (list));

	nih_message ("Finished (len=%lu)",
            (unsigned long int)len);

	return (0);
}

#endif /* MAIN_DRIVER */
#endif /* __NIH_ITERATORS */
