Please send questions to st10@humboldt.edu .
/*-----------------------------------------------------------
   a string_list2 is a class:
      string_list2  
   ...representing a list with:
       a size,
       the strings it currently contains          
                
   template for a function involving a string_list2:         
   ret_type process_string_list2(string_list2 a_string_list2)         
   {            
       return  ...a_string_list2.get_length()...     
               ...a_string_list2.get_element(i)...                  
    }           
-------------------------------------------------------------*/

#include "string_list2.h"
using namespace std;

// constructor

string_list2::string_list2()
{
    first = NULL;
    curr_size = 0;
}
    
// destructor

string_list2::~string_list2()
{
    string_node* next_node;
    string_node* temp;

    next_node = first;

    // walk through the list, deallocating each node

    while (next_node != NULL)
    {
        temp = next_node;
        next_node = next_node->get_next();

        delete temp;
        temp = NULL;
    }
}

// copy constructor

string_list2::string_list2(const string_list2& a_string_list2)
{
    string_node* prev_old;
    string_node* next_old;
    string_node* prev_new;
    string_node* next_new;

    // INSIDE this class -- can access private data fields;

    curr_size = a_string_list2.curr_size;

    if (curr_size == 0)
    {
        first = NULL;
    }

    else if (curr_size == 1)
    {
        first = new string_node( (a_string_list2.first)->get_value() );
    }

    else
    {
        first = new string_node( (a_string_list2.first)->get_value() );
        prev_old = a_string_list2.first;
        next_old = (a_string_list2.first)->get_next();

        prev_new = first;

        while (next_old != NULL)
        {
            next_new = new string_node( next_old->get_value() );
            prev_new->set_next(next_new);

            prev_new = next_new;
            prev_old = next_old;
            next_old = next_old->get_next();
        }
    }  
}

// selectors              

int string_list2::get_length() const
{
    return curr_size;
}

// signature: string_list2::get_element: int -> string
// purpose: expects the "index" (starting with 0, like an
//     array) of the list element desired, and produces
//     the string at that position in this string_list2
// examples: for:
//    string_list2 greetings;
//    greetings.add("hi");
//    greetings.add("hello");
//    greetings.add("howdy");
//
//    greetings.get_element(0) == "hi"
//    greetings.get_element(2) == "howdy"

string string_list2::get_element(int index) const
{
    string element_value;

    // if had time, we would throw an EXCEPTION if
    //    someone tried to access a "nonexistent" element --
    //    as a cheesy first step, we'll just return an empty string
    //    if they try that

    if (index >= curr_size)
    {
        element_value = "";
    }
    else
    {
        string_node* curr_node = first;
        
        // take a number of "steps" through the list
        //    equal to the desired index so that curr_node
        //    points to the desired list element

        for (int i=0; i<index; i++)
        {
            curr_node = curr_node->get_next();
        }

        // now curr_node should point to the index'th element

        element_value = curr_node->get_value();
    }

    return element_value;
}

// modifiers

// signature: string_list2::add: string -> void
// purpose: expects a string, and produces nothing, but
//     has the side-effect of adding the given string
//     to the end of the list (making it its last element)
// examples: after:
//     string_list2 greetings;
//     greetings.add("hi");
//
//     now:
//     greetings.get_size() == 1
//     greetings.get_element(0) == "hi"
//
//     and then after:
//     greetings.add("hello");
//
//     now:
//     greetings.get_size() == 2
//     greetings.get_element(1) == "hello"

void string_list2::add(string new_string)
{
    string_node* curr_node;

    // is this the first node in the list?

    if (first == NULL)
    {
        first = new string_node(new_string);
    }
    else
    {
        curr_node = first;

        // "walk" to end of the list

        while (curr_node->get_next() != NULL)
        {
            curr_node = curr_node->get_next();
        }

        // now curr_node points to the last node -- add
	//     the new element after this node

        curr_node->set_next( new string_node(new_string) );
    }

    curr_size++;
}

// signature: string_list2::remove: string -> bool
// purpose: expects a string, and tries to remove its
//    first instance from the calling string_list2,
//    producing true if it finds it and removes it,
//    and producing false if the string is not in the string_list2
// examples: after:
//     string_list2 greetings;
//     greetings.add("hi");
//     greetings.add("howdy");
//     greetings.add("hi");
//     greetings.add("hello");
//
//     greetings.remove("hi") == true
//     and after:
//     greetings.get_size() == 3
//     greetings.get_element(0) == "howdy"
//     (and greetings contains "howdy", "hi", "hello")
//
//     greetings.remove("bonjour") == false
//     greetings.get_size() == 3
//     greetings.get_element(0) == "howdy"
//     (and greetings contains "howdy", "hi", "hello")

bool string_list2::remove(string a_string)
{
    bool found = false;
    string_node* prev;
    string_node* curr;

    prev = NULL;
    curr = first;

    while ((!found) && (curr != NULL))
    {
        if (curr->get_value() == a_string)
        {
            found = true;
        }
        else
        {
            prev = curr;
            curr = curr->get_next();
        }
    }

    // if you FOUND it -- REMOVE it;

    if (found)
    {
        // special case: element is the FIRST in the list

        if (prev == NULL)
        {
            first = curr->get_next();
        }

        // otherwise, it is NOT the first in the list

        else
        {
            prev->set_next( curr->get_next() );
        }
       
        // either way, now safe to deallocate what curr points to,
        //    and to adjust the curr_size accordingly

        delete curr;
        curr_size--;

        return true;   // remove succeeded
    }

    else
    {
        return false;  // removal did not succeed -- string not in list
    }
}

// overloaded operator =
	
string_list2& string_list2::operator =(const string_list2& right_side)
{
    string_node* prev_node;
    string_node* next_node;
    string_node* temp;
    string_node* right_side_next;

    // only go to the trouble of copying if this isn't a 
    //     a self-assignment

    if (this != &right_side)
    {
        // deallocate the memory for current version of calling list

        next_node = first;

        // walk through the list, deallocating each node

        while (next_node != NULL)
        {
            temp = next_node;
            next_node = next_node->get_next();

            delete temp;
            temp = NULL;
        }

	curr_size = right_side.curr_size;

        if (right_side.first == NULL)
        {
            first = NULL;
        }
        else
        {
            first = new string_node( (right_side.first)->get_value() );
    
            right_side_next = (right_side.first)->get_next();
            prev_node = first;
        
            while (right_side_next != NULL)
            {
                next_node = new string_node( right_side_next->get_value() );
                prev_node->set_next( next_node );

                right_side_next = right_side_next->get_next();
                prev_node = next_node;
            }
        }
    }

    return *this;
}