/**
 * list.h 
 *   An alternate approach to lists.
 */

#ifndef __LIST_H__
#define __LIST_H__


// +---------+--------------------------------------------------------
// | Headers |
// +---------+

#include <stdio.h>	// For FILE


// +------------------+-----------------------------------------------
// | Shared Variables |
// +------------------+

/**
 * The error message generated by various operations.
 */
extern char *list_error;


// +----------------------------+-------------------------------------
// | Constructors & Destructors |
// +----------------------------+

/**
 * Procedure:
 *   list_new
 * Parameters:
 *   [None]
 * Purpose:
 *   Create a new, empty list.
 * Produces:
 *   lst, a list
 * Problems:
 *   If no memory is available, returns NULL.
 * Preconditions:
 *   [No additional]
 * Postconditions:
 *   list_length (lst) is 0.
 */
struct list *list_new ();

/**
 * Procedure:
 *   list_free
 * Parameters:
 *   lst, a list
 * Purpose:
 *   Free all the memory associated with list (except for that associated
 *   with the strings).
 * Produces:
 *   [Nothing; Called for the side effect]
 * Preconditions:
 *   lst has not already been freed.
 * Postconditions:
 *   Memory has been freed.
 *   lst is no longer usable.
 */
void list_free (struct list *lst);

/**
 * Procedure:
 *   list_clear
 * Parameters:
 *   lst, a list
 * Purpose:
 *   Remove all of the elements of lst.
 * Produces:
 *   [Nothing; Called for the side effect]
 * Preconditions:
 *   [No additional]
 * Postconditions:
 *   list_length (lst) is 0
 */
void list_clear (struct list *lst);


// +-----------+------------------------------------------------------
// | Observers |
// +-----------+

/**
 * Procedure:
 *   list_get
 * Parameters:
 *   lst, a pointer to a list
 *   n, an integer
 * Purpose:
 *   Get the nth element of lst.
 * Produces:
 *   nth, a string
 * Preconditions:
 *   0 <= n < list_length (lst)
 * Postconditions:
 *   lst is not modified.
 *   nth is the element naturally viewed as being at position n.
 */
char *list_get (struct list *lst, int n);

/**
 * Procedure:
 *   list_length
 * Parameters:
 *   lst, a pointer to a list.
 * Purpose:
 *   Find the length of the list given by lst.
 * Produces:
 *   length, an integer
 * Preconditions:
 *   [No additional]
 * Postconditions:
 *   length is the number of elements in lst.
 */
int list_length (struct list *lst);

/**
 * Procedure:
 *   list_index_of
 * Parameters:
 *   lst, a pointer to a list
 *   str, a string
 * Purpose:
 *   Find the first index of str in lst.
 * Produces:
 *   index, an integer
 * Preconditions: 
 *   [No additional]
 * Postconditions:
 *   If lst contains str, then index >= 0 and
 *     strcmp (list_get (lst, index), str) == 0
 *     For all i, 0 <= i < index, strcmp (list_get (lst, i), str) != 0
 *   Otherwise,
 *     index is -1
 */
int list_index_of (struct list *lst, char *str);

/**
 * Procedure:
 *   list_print
 * Parameters:
 *   lst, a pointer to a list
 *   fp, a file pointer
 * Purpose:
 *   Prints lst (in Scheme form!) to fp.
 * Produces:
 *   [Nothing; Called for the side effect.]
 * Preconditions:
 *   fp must be open for writing.
 * Postconditions:
 *   fp now contains a representation of lst.
 *   lst is unchanged.
 */
void list_print (struct list *lst, FILE *fp);


// +----------+-------------------------------------------------------
// | Mutators |
// +----------+

/**
 * Procedure:
 *   list_set
 * Parameters:
 *   lst, a pointer to a list
 *   n, an integer
 *   str, a string
 * Purpose:
 *   Replace the string at position n with str.
 * Produces:
 *   ok, an integer that represents whether or not the operation
 *     succeeded
 * Preconditions:
 *   0 <= n < list_length (lst)
 * Postconditions:
 *   If the insertion succeeded, ok is nonzero and
 *     Subsequent calls to list_get (lst, n) will return str.
 *   If the insertion failed, ok is 0 and
 *     lst is unmodified
 *     list_error contains a message about the reason for failure.
 */
int list_set (struct list *lst, int n, char *str);

/**
 * Procedure:
 *   list_insert
 * Parameters:
 *   lst, a pointer to a list
 *   n, an integer
 *   str, a string
 * Purpose:
 *   Insert str at position n, shifting everything right.
 * Produces:
 *   ok, an integer that represents whether or not the operation
 *   [Nothing; Called for the side effect]
 * Preconditions:
 *   0 <= n < list_length (lst)
 * Postconditions:
 *   If the insertion succeeded, ok is nonzero and
 *     The length of lst increases by 1.
 *     Subsequent calls to list_get (lst, n) will return str.
 *     For 0 <= i < n, calls to list_get (lst, i) will return the same
 *       value that they would have returned before.
 *     For n < i < list_length (lst), calls to list_get (lst, i) return
 *       the old value of list_get (lst, i-1)
 *   If the insertion failed, ok is 0 and
 *     lst is unmodified
 *     list_error contains a message about the reason for failure.
 */
int list_insert (struct list *lst, int n, char *str);

/** 
 * Procedure:
 *   list_append
 * Parameters:
 *   lst, a pointer to a list
 *   str, a string
 * Purpose:
 *   Adds str to the end of lst
 * Produces:
 *   ok, an integer
 * Preconditions:
 *   [No additional.]
 * Postconditions:
 *   If the append succeeded, ok is nonzero and
 *     The length of the list increased by one
 *     list_get (lst, list_length (lst) - 1) = str
 *     For all i < list_length(lst) - 1,
 *       list_get (lst, i) will return the same value as it previously did
 *   If problems occurred, ok is 0 and
 *     The list is unmodified
 */
int list_append (struct list *lst, char *str);

/** 
 * Procedure:
 *   list_prepend
 * Parameters:
 *   lst, a pointer to a list
 *   str, a string
 * Purpose:
 *   Adds str to the front of lst
 * Produces:
 *   ok, an integer
 * Preconditions:
 *   [No additional.]
 * Postconditions:
 *   If the prepend succeeded, ok is nonzero and
 *     The length of the list increased by one
 *     list_get (lst, 0) = str
 *     For all i < list_length(lst),
 *       list_get (lst, i) will return the old value of list_get (list, i=-1)
 *   If problems occurred, ok is 0 and
 *     The list is unmodified
 */
int list_prepend (struct list *lst, char *str);

/**
 * Procedure:
 *   list_delete
 * Parameters:
 *   lst, a pointer to a list 
 *   str, a string
 * Purpose:
 *   Delete the first element in lst whose car is str.
 * Produces:
 *   ok, an integer
 * Preconditions:
 *   str must appear in the list.
 *   SI = list_index_of (lst, str).
 *   ORIGINAL is equivalent to list.  That is, 
 *     list_length (ORIGINAL) == list_length (lst)
 *     for all i, 0 <= i < list_length (lst))
 *       list_get (ORIGINAL, i) == list_get (lst, i)
 * Postconditions:
 *   If the deletion succeeded, ok is nonzero and
 *     The list contains one fewer copy of str.
 *     The length of the list decreased by 1.
 *     For all i, 0 <= i < SI
 *       list_get (lst, i) == list_get (ORIGINAL, i)
 *     For all i, SI <= i < list_legth (lst)
 *       list_get (lst, i) == list_get (ORIGINAL, i+1)
 *   If problems occurred, ok is 0 and
 *     The list is unmodified
 */
int list_delete (struct list *lst, char *str);

/**
 * Procedure:
 *   list_cut
 * Parameters:
 *   lst, a pointer to a list
 *   n, an integer
 * Purpose:
 *   Cut out the nth element of lst.
 * Produces
 *   ok, an integer
 * Preconditions:
 *   0 <= n < list_length (lst)
 *   ORIGINAL is equivalent to list.  That is, 
 *     list_length (ORIGINAL) == list_length (lst)
 *     for all i, 0 <= i < list_length (lst))
 *       list_get (ORIGINAL, i) == list_get (lst, i)
 * Postconditions:
 *   If the deletion succeeded, ok is nonzero and
 *     The length of the list decreased by 1.
 *     For all i, 0 <= i < n
 *       list_get (lst, i) == list_get (ORIGINAL, i)
 *     For all i, n <= i < list_legth (lst)
 *       list_get (lst, i) == list_get (ORIGINAL, i+1)
 *   If problems occurred, ok is 0 and
 *     The list is unmodified
 */
int list_cut (struct list *lst, int n);


// +---------------+--------------------------------------------------
// | Miscellaneous |
// +---------------+

/**
 * Procedure:
 *   list_foreach
 * Parameters:
 *   lst, a pointer to a list
 *   fun, a function 
 * Purpose:
 *   Apply fun to each element of lst
 * Produces:
 *   [Nothing; Called for the side effect]
 * Preconditions:
 *   fun can be applied to strings.  (fun is permitted to mutate strings.)
 * Postconditions:
 *   We get the same effect as the following code.
 *     for (i = 0; i < list_length (lst); i++)
 *       fun (list_get (lst, i))
 * Philosophy:
 *   Permits faster iteration than the code it simultes.
 * Problems:
 *   Ignores the return value from fun.
 * Practica:
 *   // Reverse each string in a list.  
 *   list_foreach (lst, string_reverse);
 *   // Print out a list
 *   list_foreach (lst, puts);
 */
void list_foreach (struct list *lst, int (*fun)(char *));

#endif // __LIST_H__

