/******************************************************************************
*   TinTin++                                                                  *
*   Copyright (C) 2004 (See CREDITS file)                                     *
*                                                                             *
*   This program is protected under the GNU GPL (See COPYING)                 *
*                                                                             *
*   This program is free software; you can redistribute it and/or modify      *
*   it under the terms of the GNU General Public License as published by      *
*   the Free Software Foundation; either version 2 of the License, or         *
*   (at your option) any later version.                                       *
*                                                                             *
*   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA *
*******************************************************************************/

/******************************************************************************
*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
*                                                                             *
*                      coded by Igor van den Hoven 2009                       *
******************************************************************************/

#include "tintin.h"

struct listroot *search_nest_root(struct listroot *root, char *arg)
{
	struct listnode *node;

	node = search_node_list(root, arg);

	if (node == NULL || node->root == NULL)
	{
		return NULL;
	}
	return node->root;
}

struct listnode *search_base_node(struct listroot *root, char *variable)
{
	char name[BUFFER_SIZE];

	get_arg_to_brackets(variable, name);

	return search_node_list(root, get_alnum(root->ses, name));
}

struct listnode *search_nest_node(struct listroot *root, char *variable)
{
	char name[BUFFER_SIZE], *arg;

	arg = get_arg_to_brackets(variable, name);

	while (root && *arg)
	{
		root = search_nest_root(root, get_alnum(root->ses, name));

		if (root)
		{
			arg = get_arg_in_brackets(arg, name);
		}
	}

	if (root)
	{
		return search_node_list(root, get_alnum(root->ses, name));
	}

	return NULL;
}

int search_nest_index(struct listroot *root, char *variable)
{
	char name[BUFFER_SIZE], *arg;

	arg = get_arg_to_brackets(variable, name);

	while (root && *arg)
	{
		root = search_nest_root(root, get_alnum(root->ses, name));

		if (root)
		{
			arg = get_arg_in_brackets(arg, name);
		}
	}

	if (root)
	{
		return search_index_list(root, get_alnum(root->ses, name), NULL);
	}

	return -1;
}

struct listroot *update_nest_root(struct listroot *root, char *arg)
{
	struct listnode *node;

	node = search_node_list(root, arg);

	if (node == NULL)
	{
		node = update_node_list(root, arg, "", "");
	}

	if (node->root == NULL)
	{
		node->root = init_list(root->ses, root->type, LIST_SIZE);
	}

	return node->root;
}

void update_nest_node(struct listroot *root, char *arg)
{
	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];

	while (*arg)
	{
		arg = get_arg_in_braces(arg, arg1, FALSE);
		arg = get_arg_in_braces(arg, arg2, FALSE);

		if (*arg2 == DEFAULT_OPEN)
		{
			update_nest_node(update_nest_root(root, get_alnum(root->ses, arg1)), arg2);
		}
		else if (*arg1)
		{
			update_node_list(root, get_alnum(root->ses, arg1), arg2, "");
		}

		if (*arg == COMMAND_SEPARATOR)
		{
			arg++;
		}
	}
}

int delete_nest_node(struct listroot *root, char *variable)
{
	char name[BUFFER_SIZE], *arg;
	int index;

	arg = get_arg_to_brackets(variable, name);

	while (root && *arg)
	{
		root = search_nest_root(root, get_alnum(root->ses, name));

		if (root)
		{
			arg = get_arg_in_brackets(arg, name);
		}
	}

	if (root)
	{
		index = search_index_list(root, get_alnum(root->ses, name), NULL);

		if (index != -1)
		{
			delete_index_list(root, index);

			return TRUE;
		}
	}

	return FALSE;
}

// Return the number of indices of a node.

int get_nest_size(struct listroot *root, char *variable, char *result)
{
	char name[BUFFER_SIZE], *arg;
	int index, count;

	arg = get_arg_to_brackets(variable, name);

	*result = 0;

	if (!strcmp(arg, "[]"))
	{
		if (*name == 0)
		{
			for (index = 0 ; index < root->used ; index++)
			{
				cat_sprintf(result, "{%s}", root->list[index]->left);
			}
			return root->used + 1;
		}

		if (search_nest_root(root, get_alnum(root->ses, name)) == NULL)
		{
			if (search_node_list(root, name))
			{
				return 1;
			}
		}
	}

	while (root && *name)
	{
		// Handle regex queries

		if (search_nest_root(root, get_alnum(root->ses, name)) == NULL)
		{
			if (search_node_list(root, name) == NULL)
			{
				for (index = count = 0 ; index < root->used ; index++)
				{
					if (match(NULL, root->list[index]->left, name))
					{
//						cat_sprintf(result, "{%s}", root->list[index]->right);
						show_nest_node(root->list[index], result, 0);
						count++;
					}
				}

				if (count)
				{
					return count + 1;
				}
				else
				{
					return tintin_regexp_check(name); // so using a regex returns "" instead of "0"
				}
			}
		}

		root = search_nest_root(root, get_alnum(root->ses, name));

		if (root)
		{
			if (!strcmp(arg, "[]"))
			{
				for (index = 0 ; index < root->used ; index++)
				{
					cat_sprintf(result, "{%s}", root->list[index]->left);
				}
				return root->used + 1;
			}
			arg = get_arg_in_brackets(arg, name);
		}
	}

	return 0;
}


struct listnode *get_nest_node(struct listroot *root, char *variable, char *result, int def)
{
	struct listnode *node;
	int size;

	size = get_nest_size(root, variable, result);

	if (size)
	{
		return NULL;
	}

	node = search_nest_node(root, variable);

	if (node)
	{
		show_nest_node(node, result, TRUE);

		return node;
	}

	node = search_base_node(root, variable);

	if (node || def)
	{
		strcpy(result, "");
	}
	else
	{
		sprintf(result, "$%s", variable);
	}
	return NULL;
}

int get_nest_index(struct listroot *root, char *variable, char *result, int def)
{
	struct listnode *node;
	int index, size;

	size = get_nest_size(root, variable, result);

	if (size)
	{
		sprintf(result, "%d", size - 1);

		return -1;
	}

	index = search_nest_index(root, variable);

	if (index >= 0)
	{
		sprintf(result, "%d", index + 1);

		return index;
	}

	node = search_base_node(root, variable);

	if (node || def)
	{
		strcpy(result, "0");
	}
	else
	{
		sprintf(result, "&%s", variable);
	}
	return -1;
}


struct listnode *set_nest_node(struct listroot *root, char *arg1, char *format, ...)
{
	struct listnode *node;
	char arg2[BUFFER_SIZE], name[BUFFER_SIZE], *arg;
	va_list args;

	va_start(args, format);
	vsprintf(arg2, format, args);
	va_end(args);

	arg = get_arg_to_brackets(arg1, name);

	while (*arg)
	{
		root = update_nest_root(root, get_alnum(root->ses, name));

		if (root)
		{
			arg = get_arg_in_brackets(arg, name);
		}
	}

	node = search_node_list(root, get_alnum(root->ses, name));

	if (node && node->root)
	{
		free_list(node->root);

		node->root = NULL;
	}

	if (*space_out(arg2) == DEFAULT_OPEN)
	{
		update_nest_node(update_nest_root(root, get_alnum(root->ses, name)), arg2);

		return search_node_list(root, get_alnum(root->ses, name));
	}
	else
	{
		return update_node_list(root, get_alnum(root->ses, name), arg2, "");
	}
}

struct listnode *add_nest_node(struct listroot *root, char *arg1, char *format, ...)
{
	struct listnode *node;
	char arg2[BUFFER_SIZE], name[BUFFER_SIZE], *arg;
	va_list args;

	va_start(args, format);
	vsprintf(arg2, format, args);
	va_end(args);

	arg = get_arg_to_brackets(arg1, name);

	while (*arg)
	{
		root = update_nest_root(root, get_alnum(root->ses, name));

		if (root)
		{
			arg = get_arg_in_brackets(arg, name);
		}
	}

	node = search_node_list(root, get_alnum(root->ses, name));
/*
	Adding here, so don't clear the variable.

	if (node && node->root)
	{
		free_list(node->root);

		node->root = NULL;
	}
*/
	if (*space_out(arg2) == DEFAULT_OPEN)
	{
		update_nest_node(update_nest_root(root, get_alnum(root->ses, name)), arg2);

		return search_node_list(root, get_alnum(root->ses, name));
	}
	else
	{
		return update_node_list(root, get_alnum(root->ses, name), arg2, "");
	}
}

void show_nest_node(struct listnode *node, char *result, int initialize)
{
	if (initialize)
	{
		*result = 0;
	}

	if (node->root == NULL)
	{
		if (initialize)
		{
			strcat(result, node->right);
		}
		else
		{
			cat_sprintf(result, "{%s}", node->right);
		}
	}
	else
	{
		struct listroot *root = node->root;
		int i;

		if (!initialize)
		{
			strcat(result, "{");
		}

		for (i = 0 ; i < root->used ; i++)
		{
			cat_sprintf(result, "{%s}", root->list[i]->left);

			show_nest_node(root->list[i], result, FALSE);
		}
		if (!initialize)
		{
			strcat(result, "}");
		}
	}
}

void copy_nest_node(struct listroot *dst_root, struct listnode *dst, struct listnode *src)
{
	int index;

	if (src->root == NULL)
	{
		return;
	}

	dst_root = dst->root = init_list(dst_root->ses, dst_root->type, src->root->size);

	for (index = 0 ; index < src->root->used ; index++)
	{
		dst = insert_node_list(dst_root, src->root->list[index]->left, src->root->list[index]->right, src->root->list[index]->pr);

		if (src->root->list[index]->root)
		{
			copy_nest_node(dst_root, dst, src->root->list[index]);
		}
	}
}