// Copyright (C) 1996 DIMACS Center, Rutgers, The State University of New Jersey
// Author(s): ??, Jonathan Berry
// This software is copyrighted by the DIMACS Center at Rutgers, The State
// University of New Jersey.  IT IS PROVIDED AS IS, AND THE AUTHORS, DIMACS, AND
// RUTGERS, THE STATE UNIVERSITY OF NEW JERSEY  DISCLAIM
// ALL LIABILITY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
// DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
// IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
// NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
// MODIFICATIONS.
// The authors hereby grant permission to use, copy, modify, distribute,
// and license this software and its documentation for any purpose, provided
// that existing copyright notices are retained in all copies and that this
// notice is included verbatim in any distributions. No written agreement,
// license, or royalty fee is required for any of the authorized uses.
// Modifications to this software may be copyrighted by their authors
// and need not follow the licensing terms described here, provided that
// the new terms are clearly indicated on the first page of each file where
// they apply.
// Last File Update: 7-Aug-1997
// 
#include <iostream.h>
#ifndef Array_CC
#define Array_CC
//
// Creates an empty array of default size
//
template <class Item>
Array<Item>::Array() : _count(0)
{
    static Item it;
    _ia = new Item[_size = ARRAYSIZE];
    for (int i = 0; i < ARRAYSIZE; i++)
	_ia[i] = it;  // empty_data; //(Item)0; 
}
//
// Creates an empty array of given size sz
//
template <class Item>
Array<Item>::Array(int sz) : _count(0)
{
    static Item it;
    _ia = new Item[_size = sz];
    for (int i = 0; i < sz; i++)
	_ia[i] = it; //empty_data; //(Item)0;
}
//
// Copy constructor of array
//
template <class Item>
Array<Item>::Array(const Array<Item>& ar) : 
			_count(ar._count),
			_size(ar._size)
{
    _ia = new Item[_size];
    for (int ix = 0; ix < _size; ix++)
        _ia[ix] = ar._ia[ix];
}
template <class Item>
Array<Item>::Array(const Container<Item>& c)
{
	_count = 0;
	_ia = new Item[_size=ARRAYSIZE];
	Iterator<Item> get_next(&c);
	Item elem;
	while (get_next(elem))
		append(elem);
}
//
// Destructor of array
//
template <class Item>
Array<Item>::~Array()
{
    delete [] _ia;
}
//
// Copy the contents of array
//
template <class Item>
Array<Item>& 
Array<Item>::operator=(const Array<Item> &iA)
{
    if (this == &iA) return *this;
    delete [] _ia;
    _size = iA._size;
    _count = iA._count;
    _ia = new Item[_size];
    for (int ix=0; ix < _size;  ix++)
	_ia[ix] = iA._ia[ix];
    return *this;
}
//
// Return item of index ix
//
template <class Item>
Item& 
Array<Item>::operator[] (int ix) const 
{
    if ((ix < 0) || (ix >= _size)) {
        warning("array index out of bounds! Returning Element 0"); 
        return _ia[0];
    }
    // allow random access
    if (ix>=_count) 
	((Array<Item>&)(*this))._count=ix+1;
    return _ia[ix];
}
//
// Return the smallest element
// 
template <class Item>
Item 
Array<Item>::min()
{
    Item min_val = _ia[0];
    for (int ix = 1; ix < _count; ++ix)
        if (ElementOps<Item>::compareItems(min_val, _ia[ix]) > 0)
            min_val = _ia[ix];
    return min_val;
}
//
// Return the larggest element
//
template <class Item>
Item 
Array<Item>::max()
{
    Item max_val = _ia[0];
    for (int ix = 1; ix < _count; ++ix)
        if (ElementOps<Item>::compareItems(max_val, _ia[ix]) < 0)
            max_val = _ia[ix];
    return max_val;
}
//
// Find item in array and return index; -1 returned if not found
//
template <class Item>
int 
Array<Item>::search(const Item& val) const
{
    for (int ix = 0; ix < _count; ++ix)
        if (ElementOps<Item>::compareItems(val, _ia[ix])==0) return ix;
    return -1;
}
//
// check if the item is in the array
//
template <class Item>
Bool 
Array<Item>::memberQ(const Item& val) const
{
    for (int ix = 0; ix < _count; ++ix)
        if (ElementOps<Item>::compareItems(val, _ia[ix])==0) return TRUE;
    return FALSE;
}
//
// remove all items from the array
//
template <class Item>
void 
Array<Item>::clear()
{
    static Item it;
    for (int i = 0; i < _count; i++) 
        _ia[i] = it; // empty_data; //(Item) 0;
    _count = 0;
}
//
// Insert the item at the beginning of the array and move
// the rest of the array down to accomodate.
//
template <class Item>
ContainerNode*
Array<Item>::insert(const Item e)
{
    int iPos = 0;
    if (_count == _size) 
	resize(2*_size);
    for (int i = _count; i > iPos; i--)
        _ia[i] = _ia[i - 1];
    _ia[iPos] = e;
    _count++;
    return (ContainerNode*) 0;
}
//
// Append the item at the end of array
//
template <class Item>
ContainerNode*
Array<Item>::append(const Item e)
{
    if (_count == _size)
	resize(2*_size);
    _ia[_count] = e;
    _count++;
    return (ContainerNode*) 0;
}
//
// remove the passed item from the array
//
template <class Item>
void 
Array<Item>::remove(const Item e)
{
    int idx = search(e);
    if (idx == -1)  {
        return;
    }
    static Item it;
    for (int i = idx; i < _count - 1; i++)
        _ia[i] = _ia[i+1];
    _ia[_count-1] = it;  // empty_data; //0;
    _count--;
}
//
// remove the last item from the array and return
//
template <class Item>
Item 
Array<Item>::get()
{
    static Item it;
    if (_count == 0)
    {
	warning("can't get from empty array, return 0");
	return it;  // empty_data; //0;
    }
    if (_count > 0) {
	_count--;
	return _ia[_count];
    }
    return it;
}
template <class Item>
int
Array<Item>::order()
{
    return _size;
}
template <class Item>
ostream& 
Array<Item>::display(ostream& os) const
{
    const int lineLength = 12;
    os << "[";
    for (int ix = 0; ix < _count; ++ix)  {
        if (ix % lineLength == 0 && ix) 
	    os<< "\n\t";
	ElementOps<Item>::displayItem(os, _ia[ix]);
        if (ix % lineLength != lineLength-1 && ix != _count-1) 
	    os << " ";
    }
    os << "]" ;
    return os;
}
template<class Item>
int
Array<Item>::iterate(Iterator<Item>& iterator, Item& item) const
{
    if (iterator._index == 0) {
	// start of iteration, return first, point to next
        if (_count == 0)
            return 0;
        else {
            item = _ia[0];
            iterator._index = 1;
            return 1;
        }
    } else
        if (iterator._index >= _count || _count == 0)
            return 0;
        else {
            item = _ia[iterator._index];
            iterator._index++;
            return 1;
        }
}
//
// create an empty array of size sz
//
template <class Item>
void
Array<Item>::newArray(const Item* ar, int sz)
{
    static Item it;
    _ia = new Item[_size = sz];
    for (int ix = 0; ix < _size; ++ix)
        _ia[ix] = (ar != 0) ? ar[ix] : it;  // empty_data; //(Item) 0;
}
//
// Swap two items in the array
//
template <class Item>
void 
Array<Item>::swap(int i, int j)
{
    Item tmp = _ia[i];
    _ia[i] = _ia[j];
    _ia[j] = tmp;
}
//
// expand the array's size
//
template <class Item>
void 
Array<Item>::resize(int new_size)
{
    int i, old_size = _size, copy_ulimit;
    if (new_size == -1)
        new_size = old_size + old_size/2 + 1;
    Item *oldia = _ia;
    _ia = new Item[_size=new_size];
    copy_ulimit = (old_size > new_size) ? new_size : old_size;
	
    static Item it;
    for(i = 0; i < copy_ulimit; ++i) {
        _ia[i] = oldia[i];
	if (it != _ia[i]) 
		_count = i+1;
    }
    for (i=copy_ulimit; i < _size; ++i) 
        _ia[i] = it; // empty_data; //(Item)0;
    delete oldia;
}

#endif
