/*
 * Copyright (C) 2011-2014 Gary Kramlich <grim@reaperworld.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 */

#include "gplugin-file-tree.h"

#include <glib/gi18n.h>

/******************************************************************************
 * FileTreeEntry API
 *****************************************************************************/
GPluginFileTreeEntry *
gplugin_file_tree_entry_new(const gchar *filename) {
	GPluginFileTreeEntry *entry = NULL;

	g_return_val_if_fail(filename, NULL);

	entry = g_slice_new(GPluginFileTreeEntry);

	entry->filename = g_filename_to_utf8(filename, -1, NULL, NULL, NULL);

	/* we have to use e->filename, because g_utf8_strrchr returns a pointer
	 * in the string given too it, and not a new copy.
	 */
	entry->extension = g_utf8_strrchr(entry->filename, -1,
	                                  g_utf8_get_char("."));

	/* if we have an extension, we need to iterate past the . */
	if(entry->extension)
		entry->extension = g_utf8_next_char(entry->extension);

	return entry;
}

void
gplugin_file_tree_entry_free(GPluginFileTreeEntry *entry) {
	g_return_if_fail(entry);

	g_free(entry->filename);

	g_slice_free(GPluginFileTreeEntry, entry);

	entry = NULL;
}

/******************************************************************************
 * Helpers
 *****************************************************************************/
static gboolean
gplugin_file_tree_free_leaves(GNode *n, GPLUGIN_UNUSED gpointer d) {
	GPluginFileTreeEntry *e = n->data;

	gplugin_file_tree_entry_free(e);

	return FALSE;
}

static gboolean
gplugin_file_tree_free_non_leaves(GNode *n, GPLUGIN_UNUSED gpointer d) {
	g_free(n->data);

	return FALSE;
}

/******************************************************************************
 * FileTree API
 *****************************************************************************/
/**
 * gplugin_file_tree_new:
 * @paths: A #GList containing a list of paths to search.
 *
 * Builds a GNode tree consisting of a root node, whose children contain an
 * allocated string of a plugin directory.  The directory node's children are
 * GPluginFileTreeEntry instance for the files in that directory.
 */
GNode *
gplugin_file_tree_new(GList *paths) {
	GList *iter = NULL;
	GNode *root = NULL;

	root = g_node_new(NULL);

	for(iter = paths; iter; iter = iter->next) {
		GDir *dir = NULL;
		GError *error = NULL;
		GNode *node_dir = NULL;
		const gchar *path = (const gchar *)iter->data;
		const gchar *filename = NULL;

		dir = g_dir_open(path, 0, &error);
		if(error) {
			g_debug(_("Failed to open %s: %s"),
			        path,
			        (error->message) ? error->message : _("unknown failure"));

			g_error_free(error);
			error = NULL;

			continue;
		}

		/* we have a usable directory, so prepend it into the tree */
		node_dir = g_node_new(g_strdup(path));
		g_node_prepend(root, node_dir);

		/* now run through all of the files and add then to the dir node */
		while((filename = g_dir_read_name(dir)) != NULL) {
			GNode *file = NULL;
			GPluginFileTreeEntry *entry = NULL;

			entry = gplugin_file_tree_entry_new(filename);
			file = g_node_new(entry);

			g_node_prepend(node_dir, file);
		}

		/* close the dir */
		g_dir_close(dir);
	}

	return root;
}

/**
 * gplugin_file_tree_free:
 * @root: The root of the file tree
 *
 * Free's a previously created file tree.
 */
void
gplugin_file_tree_free(GNode *root) {
	g_return_if_fail(root);

	if(root->data) {
		g_node_traverse(root, G_POST_ORDER, G_TRAVERSE_LEAVES, -1,
		                gplugin_file_tree_free_leaves, NULL);
		g_node_traverse(root, G_POST_ORDER, G_TRAVERSE_NON_LEAVES, -1,
		                gplugin_file_tree_free_non_leaves, NULL);
	}

	g_node_destroy(root);
}

