/*
 * stack.c - does the handling of stack functions
 *
 * written by matthew green
 * finished by Jeremy Nelson (ESL)
 *
 * copyright (C) 1993.
 */

#if 0
static	char	rcsid[] = "@(#)$Id: stack.c,v 1.12 1994/07/02 02:32:13 mrg Exp $";
#endif

#include "irc.h"

#include "stack.h"
#include "window.h"
#include "hook.h"
#include "ircaux.h"
#include "output.h"
#include "list.h"

static	OnStack	*	on_stack = NULL;
static  AliasStack *	alias_stack = NULL;
static	AliasStack *	assign_stack = NULL;
#ifdef notyet
static	SetStack *	set_stack = NULL;
static	AliasStack *	alias_get 	 _((char *, int));
static	AliasStack *	alias_stack_find _((char *, int));
static	void		alias_stack_add  _((AliasStack *, int));
#endif

extern Alias *alias_list[];
#include "alias.h"

#ifdef __STDC__
static	void	do_stack_on (int type, char *args)
#else
static	void	do_stack_on(type, args)
int	type;
char	*args;
#endif
{
	char	foo[4];
	int	len, cnt, i, which = 0;
	Hook	*list;
	NumericList *nhook, *nptr, *ntmp = (NumericList *) 0;

	if (!on_stack && (type == STACK_POP || type == STACK_LIST))
	{
		say("ON stack is empty!");
		return;
	}
	if (!args || !*args)
	{
		say("Missing event type for STACK ON");
		return;
	}
	len = strlen(args);
	for (cnt = 0, i = 0; i < NUMBER_OF_LISTS; i++)
	{
		if (!my_strnicmp(args, hook_functions[i].name, len))
		{
			if (strlen(hook_functions[i].name) == len)
			{
				cnt = 1;
				which = i;
				break;
			}
			else
			{
				cnt++;
				which = i;
			}
		}
		else if (cnt)
			break;
	}
	if (!cnt)
	{
		if (is_number(args))
		{
			which = atoi(args);
			if (which < 1 || which > 999)
			{
				say("Numerics must be between 001 and 999");
				return;
			}
			which = -which;
		}
		else
		{
			say("No such ON function: %s", args);
			return;
		}
	}
	if (which < 0)
	{
		sprintf(foo, "%3.3u", -which);
		if ((nhook = (NumericList *) find_in_list((List **)&numeric_list, foo, 0)) != NULL)
			list = nhook->list;
		else
			list = NULL;
	}
	else
		list = hook_functions[which].list;

	if (type == STACK_PUSH)
	{
		OnStack	*new;
		new = (OnStack *) new_malloc(sizeof(OnStack));
		new->next = on_stack;
		on_stack = new;
		new->which = which;
		new->list = list;
		if (which < 0)
		{
			if (nhook == numeric_list)
			{
				if (nhook)
				{
					numeric_list = nhook->next;
					new_free(&nhook->name);
					new_free((char **)&nhook);
				}
				return;
			}
			for (nptr = numeric_list; nptr; ntmp = nptr, nptr = nptr->next)
			{
				if (nptr == nhook)
				{
					ntmp->next = nptr->next;
					new_free(&nptr->name);
					new_free((char **)&nptr);
					return;
				}
			}
		}
		else
			hook_functions[which].list = NULL;
		return;
	}
	else if (type == STACK_POP)
	{
		OnStack	*p, *tmp = (OnStack *) 0;

		for (p = on_stack; p; tmp = p, p = p->next)
		{
			if (p->which == which)
			{
				if (p == on_stack)
					on_stack = p->next;
				else
					tmp->next = p->next;
				break;
			}
		}
		if (!p)
		{
			say("No %s on the stack", args);
			return;
		}
		if ((which < 0 && nhook) || hook_functions[which].list)
			remove_hook(which, NULL, 0, 0, 1);	/* free hooks */
		if (which < 0)
		{
			/* look -- do we have any hooks already for this numeric? */
			if ((nptr = (NumericList *) find_in_list((List **)&numeric_list, foo, 0)) == NULL)
			{
				if (p->list)	/* not just a placeholder? */
				{
					/* No. make a new list and put the stack on it */
					nptr = (NumericList *) new_malloc(sizeof(NumericList));
					nptr->name = NULL;
					nptr->list = p->list;
					malloc_strcpy(&(nptr->name), foo);
					add_to_list((List **)&numeric_list, (List *)nptr);
				}
			}
			else
			{
				Hook *tmp, *next;

				/* If there is already a list, we have to clobber it */
				for(tmp = nptr->list; tmp; tmp = next)
				{
					next = tmp->next;
					tmp->not = 1;
					new_free(&(tmp->nick));
					new_free(&(tmp->stuff));
					wait_new_free((char **)&tmp);
				}
				nptr->list = p->list;
			}
		}
		else
			hook_functions[which].list = p->list;
		new_free((char **)&p);
		return;
	}
	else if (type == STACK_LIST)
	{
		int	slevel = 0;
		OnStack	*osptr;

		for (osptr = on_stack; osptr; osptr = osptr->next)
		{
			if (osptr->which == which)
			{
				Hook	*hptr;

				slevel++;
				say("Level %d stack", slevel);
				for (hptr = osptr->list; hptr; hptr = hptr->next)
					show_hook(hptr, args);
			}
		}

		if (!slevel)
			say("The STACK ON %s list is empty", args);
		return;
	}
	say("Unknown STACK ON type ??");
}

#ifdef __STDC__
static	void	do_stack_alias (int type, char *args, int which)
#else
static	void
do_stack_alias(type, args, which)
	int	type;
	char	*args;
	int	which;
#endif
{
	char	*name;
	AliasStack	*aptr,
			**aptrptr;
	int my_which = 0;
	
	if (which == STACK_DO_ALIAS)
	{
		name = "ALIAS";
		aptrptr = &alias_stack;
		my_which = COMMAND_ALIAS;
	}
	else
	{
		name = "ASSIGN";
		aptrptr = &assign_stack;
		my_which = VAR_ALIAS;
	}

	if (!*aptrptr && (type == STACK_POP || type == STACK_LIST))
	{
		say("%s stack is empty!", name);
		return;
	}

	if (STACK_PUSH == type)
	{
		/* Dont need to unstub it, we're not actually using it. */
		Alias *alptr = find_alias(&(alias_list[my_which]), args, 1, NULL, 0);
		aptr = (AliasStack *)new_malloc(sizeof(AliasStack));
		aptr->list = alptr;
		aptr->name = m_strdup(args);
		aptr->next = aptrptr ? *aptrptr : NULL;
		*aptrptr = aptr;
		return;
	}

	if (STACK_POP == type)
	{
		Alias *alptr;
		AliasStack *prev = NULL;
		for (aptr = *aptrptr; aptr; prev = aptr, aptr = aptr->next)
		{
			/* have we found it on the stack? */
			if (!my_stricmp(args, aptr->name))
			{
				/* remove it from the list */
				if (prev == NULL)
					*aptrptr = aptr->next;
				else
					prev->next = aptr->next;

				/* throw away anything we already have */
				/* dont need to unstub it if we're tossing it */
				alptr = find_alias(&(alias_list[my_which]),args, 1, NULL, 0);
				if (alptr)
				{
					new_free((char **)&(alptr->name));
					new_free((char **)&alptr);
				}

				/* put the new one in. */
				if (aptr->list)
					insert_alias(&(alias_list[my_which]), aptr->list);

				/* free it */
				new_free((char **)&aptr->name);
				new_free((char **)&aptr);
				return;
			}
		}
		say("%s is not on the %s stack!", args, name);
		return;
	}
	if (STACK_LIST == type)
	{
		AliasStack	*tmp;

		say("%s STACK LIST", name);
		for (tmp = *aptrptr; tmp; tmp = tmp->next)
		{
			if (!tmp->list)
				say("\t%s\t<Placeholder>", tmp->name);

			else if (tmp->list->stub)
				say("\t%s STUBBED TO %s", tmp->name, tmp->list->stub);

			else
				say("\t%s\t%s", tmp->name, tmp->list->stuff);
		}
		return;
	}
	say("Unknown STACK type ??");
}

#ifdef __STDC__
static	void	do_stack_set (int type, char *args)
#else
static	void	do_stack_set(type, args)
int	type;
char	*args;
#endif
{
}

/*
 * alias_get: this returns a point to an `AliasStack' structure that
 * has be extracted from the current aliases, and removed from that
 * list.
 */
#ifdef notyet
#ifdef __STDC__
static	AliasStack* alias_get (char *args, int which)
#else
static	AliasStack* alias_get(args, which)
	char	*args;
	int	which;
#endif
{
	return (AliasStack *) 0;
}

/*
 * alias_stack_find: this returns the pointer to the struct with the
 * most recent alias for `args' in the stack.
 */
#ifdef __STDC__
static	AliasStack* alias_stack_find (char *args, int which)
#else
static	AliasStack* alias_stack_find(args, which)
	char	*args;
	int	which;
#endif
{
	return (AliasStack *) 0;
}

/*
 * alias_stack_add: this adds `aptr' to the alias/assign stack.
 */
#ifdef __STDC__
static	void	alias_stack_add (AliasStack *aptr, int which)
#else
static	void	alias_stack_add(aptr, which)
	AliasStack *aptr;
	int which;
#endif
{
	return;
}
#endif

#ifdef __STDC__
extern	void	stackcmd (char *command, char *args, char *subargs)
#else
extern	void	stackcmd(command, args, subargs)
char	*command,
	*args;
char	*subargs;
#endif
{
	char	*arg;
	int	len, type;

	if ((arg = next_arg(args, &args)) != NULL)
	{
		len = strlen(arg);
		if (!my_strnicmp(arg, "PUSH", len))
			type = STACK_PUSH;
		else if (!my_strnicmp(arg, "POP", len))
			type = STACK_POP;
		else if (!my_strnicmp(arg, "LIST", len))
			type = STACK_LIST;
		else
		{
			say("%s is unknown stack verb", arg);
			return;
		}
	}
	else
	{
		say("Need operation for STACK");
		return;
	}
	if ((arg = next_arg(args, &args)) != NULL)
	{
		len = strlen(arg);
		if (!my_strnicmp(arg, "ON", len))
			do_stack_on(type, args);
		else if (!my_strnicmp(arg, "ALIAS", len))
			do_stack_alias(type, args, STACK_DO_ALIAS);
		else if (!my_strnicmp(arg, "ASSIGN", len))
			do_stack_alias(type, args, STACK_DO_ASSIGN);
		else if (!my_strnicmp(arg, "SET", len))
			do_stack_set(type, args);
		else
		{
			say("%s is not a valid STACK type", arg);
			return;
		}
	}
	else
	{
		say("Need stack type for STACK");
		return;
	}
}
