#ifndef INCLUDE_NASTARRAY_H
#define INCLUDE_NASTARRAY_H

//-----------------------------------------------------------------------------
//  NastArray.h
//-----------------------------------------------------------------------------
//
//  Copyright (C) 1998 Technische Universitaet Muenchen, Germany
//                   written by Bernhard Brueck
//
//  This file is part of Nast++
//
//-----------------------------------------------------------------------------
//  Die Klasse stellt eindimensionales Array zur Verfuehgung.
//  Die Elemente koennen ueber den operator( int,int) angesprochen werden.
//  mit Add koennen neue Werte hinzugefuegt werde. Das Array wird bei 
//  Bedarf vergroessert.
//  Vorerst wird versucht den Speicher nur immer in der Groesse von
//  Zweierpotenzen zu belegen und bei Bedarf die Groesse des Arrays
//  zu verdoppeln. Falls diese Klasse intensiver gnutzt wird ist 
//  es wahrscheinlich besser ein besseres Schema zu waehlen.
//-----------------------------------------------------------------------------
//  Aenderungen:
//     

#include "NastConfig.h"
#include "NastDebug.h"

template <class T> 
class CNastArray : public CNastObject
{
public:
    //-------------------------------------------------------------------------
    //                         Konstruktor + Destruktor
    //-------------------------------------------------------------------------

    CNastArray( int nSize = 0 );
    virtual ~CNastArray();		     //  Destruktor
    CNastArray( const CNastArray & o );	     //  Copyconstr.

    const CNastArray& operator=( const CNastArray &o );  //  Zuweisungsoperator

    //-------------------------------------------------------------------------
    //  Zugriffsfunktionen
    //-------------------------------------------------------------------------

    void add( const T &ele );		     // eine Element hinzufuegen
    void setSize( int nSize );		     // Groesse des Arrays festlegen
    void setAll( const T &ele );	     // alle Werte zuweisen
    int  size() const;			     // Groesse des Arrays

    const T& operator[]( int i ) const;	     // rhs 
    T&       operator[]( int i );	     // lhs 

    //-------------------------------------------------------------------------
    //                                Debug
    //-------------------------------------------------------------------------
    //  debugInfo    gibt Information ueber den Zustand des Objekts aus
    //  assertValid  testet das Objekt auf Integritaet
    //
    virtual void assertValid() const;
    virtual void debugDump( CNastDumpContext &dumpContext ) const;

private:
    //-------------------------------------------------------------------------
    //                           Hilfsunktionen
    //-------------------------------------------------------------------------

    int  calcSize( int nSize ) const;	     //  benoetigte Speichergroesse

    //-------------------------------------------------------------------------
    //                          Membervariablen
    //-------------------------------------------------------------------------

    T  *m_arrData;	   //  die eigentlichen Daten
    int m_nSize;	   //  tatsaechliche Groesse
    int m_nSizeAll;	   //  Groesse des allozierten Speicherplatzes
};


//-------------------------------------------------------------------------
//                             Implementation
//-------------------------------------------------------------------------

//  Konstruktor unter der Angabe der Groesse des Arrays
template<class T>
CNastArray<T>::CNastArray( int nSize /* =0 */ )
    :m_arrData ( 0 ),
     m_nSize   ( nSize ),
     m_nSizeAll( calcSize(nSize) )
{
    NAST_ASSERT( m_nSizeAll >0 );

    m_arrData  = new T[m_nSizeAll];
}

//  Copyconstr.
template<class T>
CNastArray<T>::CNastArray( const CNastArray &other )
    :CNastObject( other ),
     m_arrData  ( 0 ),
     m_nSize    ( other.m_nSize ),
     m_nSizeAll ( calcSize( other.m_nSize ) )
{
    NAST_ASSERT_VALID( &other );

    m_arrData  = new T[m_nSizeAll];

    for( int i = 0; i < m_nSize; i++)
        m_arrData[i] = other.m_arrData[i];
}

//  Destruktor
template<class T>
CNastArray<T>::~CNastArray()
{
    NAST_ASSERT_VALID( this );  

    delete [] m_arrData;
    m_arrData  = 0;
    m_nSizeAll = 0;
    m_nSize    = 0;
}

//  Zuweisungsoperator
template<class T> 
const CNastArray<T>& CNastArray<T>::operator=( const CNastArray &other )
{
    NAST_ASSERT_VALID( this );
    NAST_ASSERT_VALID( &other );

    if( this != &other )		//  keine Zuweisung auf sich selbst ?
    {
        CNastObject::operator=( other );
        m_nSize    = other.m_nSize;
        m_nSizeAll = calcSize( other.m_nSize );

        delete [] m_arrData;
        m_arrData  = new T[ m_nSizeAll ];

        for( int i = 0; i < m_nSize; i++)
            m_arrData[i] = other.m_arrData[i];
    }
    
    return *this;
}



// ----------------------------------------------------------------------------
//                                    Debug
// ----------------------------------------------------------------------------

template<class T>
void CNastArray<T>::assertValid() const
{
    NAST_ASSERT( m_arrData );		   //  Speicher belegt ?
    NAST_ASSERT( m_nSizeAll >  0 );	   //  Es ist immer mind. ein Element belegt
    NAST_ASSERT( m_nSize    >= 0 );	   //  keine negative Elementanzahl 
    NAST_ASSERT( m_nSizeAll >= m_nSize );  //  nie weniger belegt als benutzt wird
}

template<class T>
void CNastArray<T>::debugDump( CNastDumpContext &dumpContext ) const
{
    CNastObject::debugDump( dumpContext );
    dumpContext << "\t" << "CNastArray  ";
    dumpContext << "\t" << "belegt:"    << m_nSize    << "  ";
    dumpContext << "\t" << "reserviert:" << m_nSizeAll << "\n";

    //  ii statt i um einen Bug in g++2.7.2 zu umgehen
    for( int ii = 0; ii < size(); ii++)
    {
        dumpContext << "\t\t[" << ii << "] = ";
        dumpContext << operator[](ii) << "\n";
    }
}


 
// ----------------------------------------------------------------------------
//                                    Hilfsfunktionen
// ----------------------------------------------------------------------------


// Berechnet die naechsthoehere Zweierpotenz fuer nSize
template<class T> 
int CNastArray<T>::calcSize( int nSize ) const
{
    int nSizeAll = 1;
    while( nSizeAll < nSize )
        nSizeAll *= 2;

    return nSizeAll;
}

// neue Groesse des Arrays festlegen
template<class T> 
void CNastArray<T>::setSize( int nSize )
{
    if( nSize > m_nSizeAll )
    {
        // neue Groesse berechnen
        int nSizeAll = calcSize( nSize );

        // und kopieren
        T *arrOldData = m_arrData;
        m_nSizeAll    = nSizeAll;
        m_arrData     = new T[m_nSizeAll];

        //  ii statt i um einen Bug in g++2.7.2 zu umgehen
        for( int ii = 0; ii< m_nSize; ii++)
            m_arrData[ii] = arrOldData[ii];

        // alten Speicher freigeben
        delete [] arrOldData;
    }
    m_nSize = nSize;
}



// ----------------------------------------------------------------------------
//                              Memberfunktionen
// ----------------------------------------------------------------------------

//  alle Elemente im Array auf einen Wert setzen
template<class T> 
void CNastArray<T>::setAll( const T& element)
{
    for( int i = 0; i < m_nSize; i++)
        m_arrData[i] = element;
}

// ein Element hinzufuegen 
template <class T> 
inline void CNastArray<T>::add( const T &element )
{
    NAST_ASSERT_VALID( this );

    if( m_nSize < m_nSizeAll )	// noch Platz vorhanden ?
    {
        m_arrData[m_nSize++] = element;
    }
    else
    {
        int i = m_nSize;
        setSize( i + 1);
        m_arrData[i] = element;
    }
}

// lesender Zugriff auf ein Element
template <class T> 
inline const T& CNastArray<T>::operator[]( int i ) const
{				
    NAST_ASSERT_VALID( this );
    NAST_ASSERT_INDEX( i >= 0 );	
    NAST_ASSERT_INDEX( i < m_nSize );	

    return m_arrData[i];
}

// schreibender Zugriff auf ein Element
template <class T> 
inline T& CNastArray<T>::operator[]( int i )
{
    NAST_ASSERT_VALID( this );
    NAST_ASSERT_INDEX( i >= 0 );	
    NAST_ASSERT_INDEX( i < m_nSize );	

    return m_arrData[i];
}

//  Anzahl der Elemente im Array
template <class T> 
inline int CNastArray<T>::size() const
{
    NAST_ASSERT_VALID( this );
    return m_nSize;
}

#endif // INCLUDE_NASTARRAY_H
 

