/*H+ TTGenericArray.cc
*
*    SCCS ID: @(#)TTGenericArray.cc 1.5 92/11/22 SMI 
*
*    Copyright (c) 1990-1992 by Sun Microsystems, Inc.  All rights reserved.
*    See SUN_LEGAL_NOTICE file terms of the license.
*
*    PURPOSE:
*
*    Defines the member functions of the TTGenericArray class.
*
*    GLOBAL ROUTINES:
*
*    TTGenericArray::TTGenericArray (const TTGenericArray&)
*					      - Copy constructor.  Allows
*						initialization from another
*						another TTGenericArray object.
*    void TTGenericArray::addItem (TTGeneric *)
*                                             - Adds the specified item to the
*                                               end of the array.
*    TTGeneric *TTGenericArray::removeItem (int)
*					      - Removes and returns the
*                                               specified item from the array.
*    void TTGenericArray::removeItem (const TTGeneric *)
*                                             - Removes the specified item
*                                               from the array.
*    int TTGenericArray::findItem (const TTGeneric *) const
*                                             - Returns the position of the
*                                               specified item in the array.
*    TTGeneric *TTGenericArray::traverse (TTBoolean)
*                                             - Traverses the array.  If the
*                                               reset flag is set, traversal
*                                               starts at the beginning of
*                                               the array.
*    TTGenericArray &TTGenericArray::operator= (const TTGenericArray&)
*                                             - Allows assignment of one array
*                                               to another.
*    TTGeneric* &TTGenericArray::operator[] (int) const
*                                             - Allows access to the specified
*                                               item in array.  The array entry
*                                               can be read and modified.
*    TTGenericArray TTGenericArray::operator+ (const TTGenericArray&)
*                                             - Concatenates two arrays.
*
*    AUTHOR: Mark Soloway
*
*    REVISION HISTORY:
*
*    Who       When       Why                              
*    --------- ---------- ------------------------
*    MGS       09/10/90   Original creation.
*
*H-*/

// Includes
#include <stdio.h>
#include <stdlib.h>

#include "TTGenericArray.h"

/*F+ TTGenericArray::TTGenericArray (const TTGenericArray &a)
*
*    PURPOSE:
*
*    Allow creation of a new TTGenericArray from an existing TTGenericArray
*    object.
*
*    PARAMETERS:
*
*    a - The existing TTGenericArray.
*
*    REVISION HISTORY:
*
*    Who       When       Why
*    --------- ---------- ------------------------
*    MGS       09/11/90   Original creation.
*    MGS       01/27/92   Make SVR4 compatible.
*
*F-*/
TTGenericArray::TTGenericArray (const TTGenericArray& a)
{
  growSize = a.growSize;
  numItems = a.numItems;
  physicalSize = a.physicalSize;
  position = 0;
  array = new TTGeneric* [physicalSize];
  for (int i = 0; i < numItems; i++)
    array [i] = a.array [i];
}

/*F+ void TTGenericArray::addItem (TTGeneric *item)
*
*    PURPOSE:
*
*    Add a pointer to an object to the array of objects.
*
*    PARAMETERS:
*
*    item - The pointer to the object to add to the array.
*
*    PSEUDO CODE:
*
*    Increment the item counter
*    If the number of items > the physical size of memory
*      Allocate enough memory to hold the array plus the grow size
*      Copy the array into the new memory
*      Delete the old array
*      Set the array pointer to the new memory
*    Put the new item at the end of the new memory
*
*    REVISION HISTORY:
*
*    Who       When       Why                    
*    --------- ---------- ------------------------
*    MGS       09/11/90   Original creation.
*
*F-*/
void TTGenericArray::addItem (TTGeneric *item)
{
  TTGeneric **new_array = array;

  numItems++;
  if (numItems > physicalSize) {
    physicalSize += growSize;
    new_array = new TTGeneric* [physicalSize];

    for (int i=0; i < numItems-1; i++)
      new_array [i] = array [i];

    delete array;
    array = new_array;
  }

  array [numItems-1] = item;
}

/*F+ TTGeneric *TTGenericArray::removeItem (int index)
*
*    PURPOSE:
*
*    Removes and returns the specified item from the array.
*
*    PARAMETERS:
*
*    index - The index of the item to remove.  The first item in the
*            array has an index of 0.
*
*    RETURN VALUES:
*
*    Returns a pointer to the item removed from the array.  Returns NULL
*    if the index is illegal.
*
*    PSEUDO CODE:
*
*    Initialize the item pointer to NULL
*    If the index is legal
*      Save the item corresponding to the index in the item pointer
*      Decrease the item counter
*      Move the items below the index up one position in the array
*    Return the item pointer
*
*    REVISION HISTORY:
*
*    Who       When       Why                    
*    --------- ---------- ------------------------
*    MGS       09/11/90   Original creation.
*
*F-*/
TTGeneric *TTGenericArray::removeItem (int index)
{
  TTGeneric *item = (TTGeneric *) NULL;

  if ((index > -1) && (index < numItems)) {
    item = array [index];

    numItems--;

    for (int i=index; i < numItems; i++)
      array [i] = array [i+1];
  }

  return item;
}

/*F+ void TTGenericArray::removeItem (const TTGeneric *item)
*
*    PURPOSE:
*
*    Removes the specified item from the array.
*
*    PARAMETERS:
*
*    item - The pointer to the item to remove.
*
*    PSEUDO CODE:
*
*    Initialize the index to an illegal value
*    Loop through the array
*      If an item in the array matches the specified item
*        Set the index value to the position of the item
*    If the index is legal
*      Decrease the item counter
*      Move the items below the index up one position in the array
*
*    REVISION HISTORY:
*
*    Who       When       Why                    
*    --------- ---------- ------------------------
*    MGS       09/11/90   Original creation.
*
*F-*/
void TTGenericArray::removeItem (const TTGeneric *item)
{
  int index = -1;

  for (int i=0; i < numItems; i++)
    if (item == array [i])
      index = i;

  if (index != -1) {
    numItems--;

    for (i=index; i < numItems; i++)
      array [i] = array [i+1];
  }
}

/*F+ int TTGenericArray::findItem (const TTGeneric *item) const
*
*    PURPOSE:
*
*    Find the specified item pointer in the array and return the position.
*
*    PARAMETERS:
*
*    item - The pointer to the item to find.
*
*    RETURN VALUES:
*
*    Returns the position of the item in the array.  If the item is not
*    found, -1 is returned.
*
*    PSEUDO CODE:
*
*    Initialize the index to -1
*    Loop through the array
*      If an item in the array matches the specified item
*        Set the index value to the position of the item
*    Return the index
*
*    REVISION HISTORY:
*
*    Who       When       Why                    
*    --------- ---------- ------------------------
*    MGS       09/11/90   Original creation.
*
*F-*/
int TTGenericArray::findItem (const TTGeneric *item) const
{
  int index = -1;

  for (int i=0; i < numItems; i++)
    if (item == array [i])
      index = i;

  return index;
}

/*F+ TTGeneric *TTGenericArray::getItem (int index) const
*
*    PURPOSE:
*
*    Returns the specified item from the array.
*
*    PARAMETERS:
*
*    index - The index of the item to get.  The first item in the
*            array has an index of 0.
*
*    RETURN VALUES:
*
*    Returns a pointer to the item in the array.  Returns NULL if the index
*    is illegal.
*
*    REVISION HISTORY:
*
*    Who       When       Why                    
*    --------- ---------- ------------------------
*    MGS       09/11/90   Original creation.
*
*F-*/
TTGeneric *TTGenericArray::getItem (int index) const
{
  if ((index > -1) && (index < numItems))
    return array [index];

  return (TTGeneric *) NULL;
}

/*F+ TTGeneric *TTGenericArray::traverse (TTBoolean reset_flag)
*
*    PURPOSE:
*
*    Traverses the array in order.  If the reset flag is set, then
*    traversal is started from the beginning of the array.
*
*    PARAMETERS:
*
*    reset_flag - If set, traversal starts from the beginning of the array.
*
*    RETURN VALUES:
*
*    Returns a pointer to an item in the array.  Returns NULL if there
*    are no more items in the array.
*
*    PSEUDO CODE:
*
*    If the reset flag is set, set the position to the beginning of the array
*    If the position is legal, return the item and increment the position
*    If the position is not legal, return NULL
*
*    REVISION HISTORY:
*
*    Who       When       Why                    
*    --------- ---------- ------------------------
*    MGS       09/11/90   Original creation.
*
*F-*/
TTGeneric *TTGenericArray::traverse (TTBoolean reset_flag)
{
  if (reset_flag) position = 0;

  if (position < numItems)
    return array [position++];

  return (TTGeneric *) NULL;
}

/*F+ TTGenericArray &TTGenericArray::operator= (const TTGenericArray& a)
*
*    PURPOSE:
*
*    Allows assignment of one array to another array.  The object pointers
*    in the array are copied, not the actual objects.  To clear an array
*    that is a copy of another array, use the dropItems member function,
*    instead of the clear function.
*
*    PARAMETERS:
*
*    a - The array to be assigned to (LHS of assignment).
*
*    RETURN VALUES:
*
*    Returns an array containing the same items as the input array.
*
*    PSEUDO CODE:
*
*    If the input array is not the same as the target array
*      Initialize the position counter
*      Set the physical size and grow size information
*      Set the items counter to the number of items in the input array
*      Delete the old target array
*      Allocate the physical size in memory
*      Copy the input array into the allocated memory
*    Return the target array
*
*    REVISION HISTORY:
*
*    Who       When       Why                    
*    --------- ---------- ------------------------
*    MGS       09/11/90   Original creation.
*
*F-*/
TTGenericArray &TTGenericArray::operator= (const TTGenericArray &a)
{
  if (&a != this) {
    growSize = a.growSize;
    numItems = a.numItems;
    physicalSize = a.physicalSize;
    position = 0;      
    delete [] array;

    array = new TTGeneric* [physicalSize];
    for (int i = 0; i < numItems; i++)
      array [i] = a.array [i];
  }

  return *this;
}

/*F+ TTGeneric* &TTGenericArray::operator[] (int index) const
*
*    PURPOSE:
*
*    Returns the specified item by reference, thereby allowing modification
*    of the array entry.
*
*    PARAMETERS:
*
*    index - The index of the item to return.  The first item in the array
*            has an index of 0.
*
*    RETURN VALUES:
*
*    Returns the item in the array by reference.  If the specified index
*    is illegal, then a message is output and a core dump is generated.
*
*    REVISION HISTORY:
*
*    Who       When       Why                    
*    --------- ---------- ------------------------
*    MGS       09/11/90   Original creation.
*
*F-*/
TTGeneric* &TTGenericArray::operator[] (int index) const
{
  if ((index > -1) && (index < numItems))
    return array [index];

  fprintf (stderr, "TTGenericArray::operator[]: Illegal index: %d\n", index);
  fprintf (stderr, "Abort with core dump...\n");
  abort ();
  return array [0]; // Dummy return to fool the compiler
}


/*F+ TTGeneric &TTGenericArray::operator+ (const TTGenericArray& a)
*
*    PURPOSE:
*
*    Concatenates two arrays together and returns the larger new array.
*
*    PARAMETERS 
*
*    a - The array to append to the end of the other array.
*
*    RETURN VALUES:
*
*    Returns the new array consisting of the two concatenated arrays.
*
*    REVISION HISTORY:
*
*    Who       When       Why                    
*    --------- ---------- ------------------------
*    MGS       09/10/90   Original creation.
*
*F-*/
TTGenericArray TTGenericArray::operator+ (const TTGenericArray &a)
{
  TTGenericArray new_array;

  for (int i=0; i < numItems; i++)
    new_array.addItem (array [i]);

  for (i=0; i < a.numItems; i++)
    new_array.addItem (a.array [i]);

  return new_array;
}


#ifdef TEST

#include <stream.h>

class TTGenericInteger : public TTGeneric {
 public:
  int value;
};

main ()
{
  TTGenericArray   a1, a2, a3;
  TTGenericInteger I1, I2, I3, I4, I5, I6, I7, I8;

  I1.value = 1;
  I2.value = 2;
  I3.value = 3;
  I4.value = 4;
  I5.value = 5;
  I6.value = 6;
  I7.value = 7;
  I8.value = 8;
  
  a1.addItem (&I1);
  a1.addItem (&I2);
  a1.addItem (&I3);
  a1.addItem (&I4);

  a2.addItem (&I5);
  a2.addItem (&I6);
  a2.addItem (&I7);
  a2.addItem (&I8);

  cout << "Correct result: 1-4:" << endl;
  for (int i=0; i < a1.getSize (); i++)
    cout << ((TTGenericInteger *) a1 [i])->value << endl;
  cout << endl;

  cout << "Correct result: 5-8:" << endl;
  for (i=0; i < a2.getSize (); i++)
    cout << ((TTGenericInteger *) a2 [i])->value << endl;
  cout << endl;

  cout << "Correct result: 1-8:" << endl;
  a1 = a1 + a2;
  for (i=0; i < a1.getSize (); i++)
    cout << ((TTGenericInteger *) a1 [i])->value << endl;
  cout << endl;

  cout << "Correct result: 0:" << endl;
  a1.clear ();
  cout << a1.getSize () << endl << endl;
  cout << endl;

  cout << "Correct result: 5-8:" << endl;
  a3 = a2;
  for (i=0; i < a3.getSize (); i++)
    cout << ((TTGenericInteger *) a3 [i])->value << endl;
  cout << endl;

  a2.clear ();
  a3.dropItems ();

  a1.addItem (&I1);
  a1.addItem (&I2);
  a1.addItem (&I3);
  a1.addItem (&I4);

  cout << "Correct result: 1-4:" << endl;
  for (i=0; i < a1.getSize (); i++)
    cout << ((TTGenericInteger *) a1 [i])->value << endl;
  cout << endl;

  cout << "Correct result: 1,2,4:" << endl;
  (void) a1.removeItem (2);
  for (i=0; i < a1.getSize (); i++)
    cout << ((TTGenericInteger *) a1 [i])->value << endl;
  cout << endl;

  cout << "Correct result: 1:" << endl;
  cout << a1.findItem (&I2) << endl << endl;

  cout << "Correct result: 1,4:" << endl;
  a1.removeItem (&I2);
  for (i=0; i < a1.getSize (); i++)
    cout << ((TTGenericInteger *) a1 [i])->value << endl;
  cout << endl;

  a1.dropItems ();

  a1.addItem (&I1);
  a1.addItem (&I2);
  a1.addItem (&I3);
  a1.addItem (&I4);

  cout << "Correct result: 1-4:" << endl;
  for (i=0; i < a1.getSize (); i++)
    cout << ((TTGenericInteger *) a1 [i])->value << endl;
  cout << endl;

  cout << "Correct result: 1,2,4:" << endl;
  (void) a1.removeItem (2);
  for (i=0; i < a1.getSize (); i++)
    cout << ((TTGenericInteger *) a1 [i])->value << endl;
  cout << endl;

  cout << "Correct result: 1:" << endl;
  cout << a1.findItem (&I2) << endl << endl;

  cout << "Correct result: 1,4:" << endl;
  a1.removeItem (&I2);
  for (i=0; i < a1.getSize (); i++)
    cout << ((TTGenericInteger *) a1 [i])->value << endl;
}

#endif /* TEST */
