/*
 * CS70, Spring 2001
 *
 * Implementation of a simple container class.  The class allows the
 * user to put stuff in and get it back out, not necessarily in the
 * same order.  An iterator is also provided, so that the container
 * contents can be examined nondestructively.
 */

#include "dumbcontainer.hh"
#include <string>

/*
 * Table of contents: the following routines are defined in this file.
 *
 *			DumbContainer::DumbContainer(unsigned int maxSize_);
 *			DumbContainer::~DumbContainer();
 * bool			DumbContainer::add(const string& info);
 *					// Add a string to the container
 *					// ..returns false if add failed
 * string		DumbContainer::remove();
 *					// Remove and return a string
 * bool			DumbContainer::isEmpty() const;
 *					// Test whether container has stuff
 *
 *			DumbContainerIterator::DumbContainerIterator(
 *			  const DumbContainer& target_);
 *			DumbContainerIterator::DumbContainerIterator(
 *			  const DumbContainerIterator& source);
 *			DumbContainerIterator::~DumbContainerIterator();
 * DumbContainerIterator&
 *			DumbContainerIterator::operator=(
 *			  const DumbContainerIterator& source);
 *			DumbContainerIterator::operator bool() const;
 *					// Return true if more data left
 * DumbContainerIterator&
 *			DumbContainerIterator::operator++();
 *					// Preincrement the iterator
 * DumbContainerIterator
 *			DumbContainerIterator::operator++(int);
 *					// Postincrement the iterator
 * string&		DumbContainerIterator::operator*() const;
 *					// Return current string
 * string*		DumbContainerIterator::operator->() const;
 *					// Return current string
 */

/*
 * Construct a dumb container with a specified maximum size.
 */
DumbContainer::DumbContainer(
    unsigned int	maxSize_)	// Maximum no. of strings we can hold
    : maxSize(maxSize),
      currentSize(0),
      strings(new string[maxSize_])
    {
    }

/*
 * Destructor for dumb containers.
 */
DumbContainer::~DumbContainer()
    {
    delete[] strings;
    }

/*
 * Add a string to a dumb container.  Returns true if add succeeded,
 * false if there was no room.
 */
bool DumbContainer::add(
    const string&	info)		// String to add
    {
    if (currentSize >= maxSize)
	return false;			// Sorry, no room

    strings[currentSize] = info;

    /*
     * Just to be perverse (and to illustrate the fact that containers
     * don't have to keep things in any particular order), randomize
     * things a bit.
     */
    if (currentSize & 1)
	{
	string temp(strings[currentSize]);
	strings[currentSize] = strings[0];
	strings[0] = temp;
	}

    currentSize++;

    return true;			// Add was successful
    }

/*
 * Remove a string from a dumb container and return it.  By design,
 * the order of removal is undefined.  All the user can be assured of
 * is that all strings inserted can eventually be removed.
 */
string DumbContainer::remove()
    {
    if (currentSize == 0)
	return string("");		// If empty, give a null string

    return strings[--currentSize];
    }

/*
 * Test whether a dumb container is empty.
 */
bool DumbContainer::isEmpty()
    const
    {
    return currentSize == 0;
    }

/*
 * Create an iterator pointing at a specified dumb container.
 */
DumbContainerIterator::DumbContainerIterator(
    const DumbContainer&
			target_)	// Container we'll iterate over
    : target(&target_),
      position(0)
    {
    }

/*
 * Copy constructor for the dumb-container iterator.
 */
DumbContainerIterator::DumbContainerIterator(
    const DumbContainerIterator&
			source)		// Iterator to copy
    : target(source.target),
      position(source.position)
    {
    }

DumbContainerIterator::~DumbContainerIterator()
    {
    }

/*
 * Assignment for dumb-container iterators.
 */
DumbContainerIterator& DumbContainerIterator::operator=(
    const DumbContainerIterator&
			source)
    {
    if (this == &source)
	return *this;

    target = source.target;
    position = source.position;
    return *this;
    }

/*
 * Test whether a dumb-container iterator will be able to return more
 * data.
 */
DumbContainerIterator::operator bool()
    const
    {
    return position < target->currentSize;
    }

/*
 * Preincrement a dumb-container iterator.
 */
DumbContainerIterator& DumbContainerIterator::operator++()
    {
    if (*this)
	position++;
    return *this;
    }

/*
 * Postincrement a dumb-container iterator.
 */
DumbContainerIterator DumbContainerIterator::operator++(
    int			)		// Dummy argument required by C++
    {
    DumbContainerIterator previous(*this);
    ++(*this);
    return previous;
    }

/*
 * Return the string currently pointed to by a dumb-container
 * iterator.  If called on an expired iterator, returns a random
 * string from the container; if called on an expired iterator for an
 * empty container, returns an empty string.
 */
string& DumbContainerIterator::operator*()
    const
    {
    if (*this)
	return target->strings[position];
    else
	return target->strings[0];
    }

/*
 * Return the string currently pointed to by a dumb-container
 * iterator.  If called on an expired iterator, returns a NULL pointer
 * (which will probably segfault the caller; life is tough).
 */
string* DumbContainerIterator::operator->()
    const
    {
    if (*this)
	return &target->strings[position];
    else
	return NULL;
    }
