# ****
# Queue functions.  FIFO pipe.
# Version: 2.1.
# Authors: Ferry Firmansjah (firmanf@bigfoot.com)
#    w/ help of Christopher Meisenzahl (c_meisenzahl@yahoo.com).
#
# Revision 2.1: 8/15/2001
#    Added the queue_unpop function to add an entry
#    to the beginning of the queue.
#
# Major revision on 7/5/2000 to allow passing of array
#    instead of array name.  This revision basically
#    converts the queue or stack to use an associative
#    array instead of a sequential array.
#    This eliminates the need to use global variables,
#    and the use of "eval".
#
#
# Copyright (C) 2000 Ferry Firmansjah
# 
# 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.
# ****

####
# Syntax: queue_init (queue[]);
# Return value: E_OK
# Parameters:
#    queue: the array to be initialized as a queue
# Description: Initializes an array to be a FIFO queue.
####
public function queue_init (inout queue[]) {
	auto tmp;
	for (tmp in queue) delete queue [tmp];
	queue ["curr"] = 0;
	queue ["next"] = 0;
	return E_OK;
}

####
# Syntax: enqueue (queue[], in entry);
# Return value: E_OK
# Parameters:
#    queue: the array containing the queue
#    entry: the entry to be added to the queue
# Description: Adds an entry to the end of the FIFO queue.
####
public function enqueue (inout queue[], entry) {
	queue [queue["next"]++] = entry;
	return E_OK;
}

####
# Syntax: dequeue (queue[], out out_entry);
# Return value: default return values
# Parameters:
#    queue: the array containing the queue
#    out_entry: variable to store the returned value from the queue
# Description: Returns an entry from the front of the FIFO queue.
#    If the queue is empty, the element will return an E_OUT_OF_RANGE
#    error, and the out_entry variable will not be changed (empty).
####
public function dequeue (inout queue[], out out_entry) {
	auto res = E_OK;

	if (queue["curr"] >= queue ["next"]) {
		res = E_OUT_OF_RANGE;
	} else {
		out_entry = queue [queue["curr"]];
		delete queue [queue["curr"]];
		queue["curr"]++;
	}
	return res;
}

####
# Syntax: queue_length (queue[]);
# Return value: length of the queue
# Parameters:
#    queue: the array containing the queue.
# Description: Returns the length of the specified queue queue.
####
public function queue_length (inout queue[]) {
	return queue["next"] - queue["curr"];
}

####
# Syntax: queue_isempty (queue[]);
# Return value: TRUE or FALSE.
# Parameters:
#    queue: the array containing the queue.
# Description: Whether the queue is empty.
####
public function queue_isempty (inout queue[]) {
	return (queue_length(queue) < 1);
}

####
# Syntax: queue_push (queue[], in entry);
# Return value: E_OK
# Parameters:
#    queue: the array containing the queue
#    entry: the entry to be added to the queue
# Description: Adds an entry to the end of the FIFO queue.
#    ** Note: This basically calls enqueue.
####
public function queue_push (inout queue[], in entry) {
	return enqueue(queue, entry);
}

####
# Syntax: queue_pop (queue[], out out_entry);
# Return value: default return values
# Parameters:
#    queue: the array containing the queue
#    out_entry: variable to store the returned value from the queue
# Description: Returns an entry from the front of the FIFO queue.
#    If the queue is empty, the element will return an E_OUT_OF_RANGE
#    error, and the out_entry variable will not be changed (empty).
#    ** Note: This basically calls dequeue();
####
public function queue_pop (inout queue[], out entry) {
	return dequeue(queue, entry);
}

####
# Syntax: queue_unpop (queue[], in entry);
# Return value: E_OK
# Parameters:
#    queue: the array containing the queue
#    entry: the entry to be added to the front of the queue
# Description: Adds an entry to the front of the FIFO queue.
####
public function queue_unpop (inout queue[], entry) {
	queue["curr"]--;
	queue[queue["curr"]] = entry;
	return E_OK;
}










# ****
# Stack functions.  LIFO pipe.
# ****

####
# Syntax: stack_init (stack[]);
# Return value: E_OK
# Parameters:
#    stack: the name of the stack to be created
# Description: Creates a LIFO stack with the specified stack.
####
public function stack_init (inout stack[]) {
	auto tmp;
	for (tmp in stack) delete stack[tmp];
	stack["next"] = 0;
	return E_OK;
}

####
# Syntax: stack_push (stack[], entry);
# Return value: E_OK
# Parameters:
#    stack: the name of the stack
#    entry: the entry to be added to the stack
# Description: Adds an entry to the end of the LIFO stack.
####
public function stack_push (inout stack[], entry) {
	stack[stack["next"]++] = entry;
	return E_OK;
}

####
# Syntax: stack_pop (stack[], out_entry);
# Return value: default return values
# Parameters:
#    stack: the name of the stack
#    out_entry: variable to store the returned value from the stack
# Description: "Pops" an entry from the end of the LIFO stack.
####
public function stack_pop (inout stack[], out out_entry) {
	auto res = E_OK;

	if (stack["next"] < 1) {
		res = E_OUT_OF_RANGE;
	} else {
		out_entry = stack[stack["next"] - 1];
		delete stack[stack["next"] - 1];
		stack["next"]--;
	}
	return res;
}

####
# Syntax: stack_length (stack[]);
# Return value: length of the stack
# Parameters:
#    stack: the name of the stack
# Description: Returns the length of the specified stack stack.
####
public function stack_length (inout stack[]) {
	return stack["next"];
}


####
# Syntax: stack_isempty (stack[]);
# Return value: TRUE or FALSE.
# Parameters:
#    stack: the array containing the stack.
# Description: Whether the stack is empty.
####
public function stack_isempty (inout stack[]) {
	return (stack_length(stack) < 1);
}




# Function Generator
static function function_generator() {
	generator_add_category ("queue_stack");
	generator_add_function ("queue_init"
		, "Initializes an array to be a FIFO queue."
		, 1
		, "array_queue"
		, "type_edit"
		, ""
	);

	generator_add_function ("enqueue"
		, "Adds an entry to the end of the FIFO queue."
		, 2
		, "array_queue"
		, "type_edit"
		, ""
		, "entry_to_add"
		, "type_edit"
		, ""
	);


	generator_add_function ("dequeue"
		, "Returns an entry from the front of the FIFO queue.\n"
		  & "If the queue is empty, the element will return an E_OUT_OF_RANGE"
		  & " error, and the out_entry variable will not be changed (empty)."
		, 2
		, "array_queue"
		, "type_edit"
		, ""
		, "out_entry"
		, "type_edit"
		, ""
	);


	generator_add_function ("queue_length"
		, "Returns the length of the specified queue queue."
		, 1
		, "array_queue"
		, "type_edit"
		, ""
	);

	generator_add_function ("queue_isempty"
		, "Whether the queue is empty. Returns TRUE or FALSE."
		, 1
		, "array_queue"
		, "type_edit"
		, ""
	);


	generator_add_function ("queue_push"
		, "Adds an entry to the end of the FIFO queue.\n"
		  & "** Note: This basically calls enqueue."
		, 2
		, "array_queue"
		, "type_edit"
		, ""
		, "entry_to_add"
		, "type_edit"
		, ""
	);


	generator_add_function ("queue_pop"
		, "Returns an entry from the front of the FIFO queue.\n"
		  & "If the queue is empty, the element will return an E_OUT_OF_RANGE"
		  & " error, and the out_entry variable will not be changed (empty).\n"
		  & "** Note: This basically calls enqueue."
		, 2
		, "array_queue"
		, "type_edit"
		, ""
		, "out_entry"
		, "type_edit"
		, ""
	);



	generator_add_function ("queue_unpop"
		, "Adds an entry to the front of the FIFO queue.\n"
		, 2
		, "array_queue"
		, "type_edit"
		, ""
		, "entry_to_add"
		, "type_edit"
		, ""
	);


	generator_add_function_to_category ("queue_stack", "queue_init");
	generator_add_function_to_category ("queue_stack", "enqueue");
	generator_add_function_to_category ("queue_stack", "dequeue");
	generator_add_function_to_category ("queue_stack", "queue_length");
	generator_add_function_to_category ("queue_stack", "queue_isempty");
	generator_add_function_to_category ("queue_stack", "queue_push");
	generator_add_function_to_category ("queue_stack", "queue_pop");
	generator_add_function_to_category ("queue_stack", "queue_unpop");



	generator_add_function ("stack_init"
		, "Creates a LIFO stack with the specified stack."
		, 1
		, "array_stack"
		, "type_edit"
		, ""
	);

	generator_add_function ("stack_push"
		, "Adds an entry to the end of the LIFO stack."
		, 2
		, "array_stack"
		, "type_edit"
		, ""
		, "entry_to_add"
		, "type_edit"
		, ""
	);


	generator_add_function ("stack_pop"
		, "'Pops' an entry from the end of the LIFO stack."
		, 2
		, "array_stack"
		, "type_edit"
		, ""
		, "out_entry"
		, "type_edit"
		, ""
	);


	generator_add_function ("stack_length"
		, "Returns the length of the specified stack stack."
		, 1
		, "array_stack"
		, "type_edit"
		, ""
	);

	generator_add_function ("stack_isempty"
		, "Whether the stack is empty."
		, 1
		, "array_stack"
		, "type_edit"
		, ""
	);


	generator_add_function_to_category ("queue_stack", "stack_init");
	generator_add_function_to_category ("queue_stack", "stack_length");
	generator_add_function_to_category ("queue_stack", "stack_isempty");
	generator_add_function_to_category ("queue_stack", "stack_push");
	generator_add_function_to_category ("queue_stack", "stack_pop");
	return TRUE;
}


# Signifies that this module has been loaded, and loads the function generator
# Can be used by calling test to minimize reloading
# of the function.
# e.g.  
# if (!func_queue_stack_loaded) {
#   reload ("func_queue_stack", 1, 1);
# }
const func_queue_stack_loaded = function_generator();


