#ifndef AU_ACCESSOR
#define AU_ACCESSOR

/********************\
*  auAccessor Class  *
\********************/
template <class T>
class auAccessor
{
 friend class auNullAcessorClass;
 protected:
    T*          Ptr;
    auAccessor  *Prev, *Next;
    auInt       m_Size;
 public:
    void Delete();   // Deletes the object/array being pointed to. Resets
                     // this and all auAccessors pointing there to NULL.
    void Remove();    // Stops pointing to the current address, points to NULL.
    void Assign(auAccessor &A);   // Assigns a new place to point to
    void New(long Count=1);   // Creates a new object or array on the heap.
    void Copy(auInt Extra=0);  // Creates a copy of the current object or array
                               // being pointed to, and starts pointing there.
                               // Adds extra elements if necessary.
    void CopyElements(auAccessor &A, auUInt SourceBegin, auUInt SourceEnd, auUInt DestBegin);  // Copies
                     // elements from one array to another, clips overflows
    inline auInt ArraySize(); // Returns the copy of the size of the array being 
                              // pointed to. A single object is an array of 1 element.
    inline auAccessor(); // Constructor. Initializes values to 0.
    inline auAccessor(auAccessor &A);    // Copy constructor. Calls Assign(A);
    inline ~auAccessor();    // Destructor. Calls Remove();
    inline T& operator*();
    inline T* operator->();
    inline T* operator+(long Index);
    inline T& operator[](long Index);
    inline T& operator==(auAccessor Compare); // compare pointers
    //inline T& operator==(auNullAccessor Compare) // if you really want to write "== auNull" :-)
    inline operator bool();  // Used to test if pointer is NULL
    inline auAccessor& operator=(auAccessor &A);
    inline T* Address();   // Only if you want to hack (for efficiency?).
    inline void AddressAssign(T* Addr, auInt Count);   // Only if you want to hack (for external data?).
    //inline void operator delete(void* pmem)
};

//auNullAccessor auNull;

template<class T>
void auAccessor<T>::Delete()    // Deletes the object/array being pointed to.
                                // Resets this and all auAccessors pointing there to NULL.
{
    auAccessor* a;
    if (Ptr)
    {
        if (m_Size > 1)
            delete[] Ptr;
        else
            delete Ptr;
        // Clear all previous pointers in doubly linked list...
        a = this;   // start from the current one
        while (a)
        {
            a->Ptr = 0;
            a = a->Prev;
        }
        a = Next;   // start from the next one
        while (a)
        {
            a->Ptr = 0;
            a = a->Next;
        }
    }
    m_Size = 0;
}

template<class T>
void auAccessor<T>::Remove()    // Stops pointing to the current address,
points to NULL.
{
    // Remove this object from its current doubly linked list
    if (Prev)
        Prev->Next = Next;
    if (Next)
        Next->Prev = Prev;
    // If it was already a single object, delete it.
    if (!Prev && !Next)
        Delete();
    // And we're clean again :-)
    Ptr = 0;
    Prev = 0; Next = 0;
    m_Size = 0;
}

template<class T>
void auAccessor<T>::Assign(auAccessor &A)   // Assigns a new place to point
to
{
    // Remove this object from its current doubly linked list
    Remove();
    // Add this object into A's doubly linked list
    // A will be Prev.
    Prev = &A;
    Next = A.Next;
    if (A.Next)
        A.Next->Prev = this;
    A.Next = this;
    Ptr = A.Ptr;
    m_Size = A.m_Size;
}

template<class T>
void auAccessor<T>::New(long Count)   // Creates a new object or array on
the heap.
{
    Remove();
    // Allocate new data on the free store.
    if (Count == 1)
        Ptr = new T;
    else
        Ptr = new T[Count];
    m_Size = Count;
};

template<class T>
void auAccessor<T>::Copy(auInt extra)  // Creates a copy of the current
// object or array being pointed to, and starts pointing there.
{
    // Special case.
    if (!Ptr)       // sound the alarm. :-)
        throw new auError(AU_STDERROR_MISSING);
    if (!Prev && !Next)
        return;   // the only copy, anyway.
    // Save the pointer. The data won't be deleted.
    T* p;
    p = Ptr;
    // Create new data and copy to it.
    New(m_Size+extra);
    memcpy(Ptr, p, sizeof(T) * m_Size);
    // m_Size remains the same. Unless something's weird. :-)
}

template<class T>
auInt auAccessor<T>::ArraySize() // Returns the copy of the size of the
array being pointed to. A single object is an array of 1 element.
{
    return m_Size
}

template<class T>
void auAccessor<T>::CopyElements
    (auAccessor &A,
     auUInt sb, auUInt se,
     auUInt db)   // Copies elements from one array to another
{
    if (!Ptr)       // sound the alarm. :-)
        throw new auError(AU_STDERROR_MISSING);
    if (!A.Ptr)       // sound the alarm. :-)
        throw new auError(AU_STDERROR_MISSING);
    // Bounds checks
    if (db >= m_Size)
        throw new auError(AU_STDERROR_PARAMS);
    if (sb >= A.m_Size)
        throw new auError(AU_STDERROR_PARAMS);
    // Bounds adjusting
    if (se >= A.m_Size)
        se = A.m_Size-1;
    if (db+(se-sb) >= A.m_Size)
        se = m_Size-1-(db-sb);
    memcpy(Ptr+db, A.Ptr+sb, se-sb+1);
}

template<class T>
auAccessor<T>::auAccessor() // Constructor. Initializes values to 0.
{
    // Be kind, rewind. :-)
    Ptr = 0;
    Prev = 0;
    Next = 0;
    m_Size = 0;
}

template<class T>
auAccessor<T>::auAccessor(auAccessor &A)    // Copy constructor. Calls
Assign(A);
{
    Assign(A);
}

template<class T>
auAccessor<T>::~auAccessor()    // Destructor. Calls Remove();
{
    Remove();
}

template<class T>
T& auAccessor<T>::operator*()
{
    if (!Ptr) throw new auError(AU_STDERROR_MISSING);
    return *Ptr;
}

template<class T>
T* auAccessor<T>::operator->()
{
    if (!Ptr) throw new auError(AU_STDERROR_MISSING);
    return Ptr;
}

template<class T>
T* auAccessor<T>::operator+(long Index)
{
    if (!Ptr) throw new auError(AU_STDERROR_MISSING);
    if (Index < 0) throw new auError(AU_STDERROR_BOUNDS);
    if (Index >= m_Size) throw new auError(AU_STDERROR_BOUNDS);
    return Ptr+Index;
}

template<class T>
T& auAccessor<T>::operator[](long Index)
{
    if (!Ptr) throw new auError(AU_STDERROR_MISSING);
    if (Index < 0) throw new auError(AU_STDERROR_BOUNDS);
    if (Index >= m_Size) throw new auError(AU_STDERROR_BOUNDS);
    return Ptr[Index];
}

template<class T>
T& auAccessor<T>::operator==(auAccessor Compare) // compare pointers
{
    return (Ptr == Compare.Ptr);
}

//
//inline T& auAccessor<T>::operator==(auNullAccessor Compare) // if you really want to write "== auNull" :-)
//{
//    return (Ptr == Compare.Ptr);
//}

template<class T>
auAccessor<T>::operator bool()  // Used to test if pointer is NULL
{
    if (Ptr) return true;
    else return false;
}

template<class T>
auAccessor<T>& auAccessor<T>::operator=(auAccessor &A)
{
    Assign(A);
    return A;
}

template<class T>
T* auAccessor<T>::Address()   // Only if you want to hack (for efficiency?).
{
    return Ptr;
}

template<class T>
void auAccessor<T>::AddressAssign(T* p, auInt count)   // Only if you want to hack (for efficiency?).
{
    Remove();
    Ptr = p;
    m_Size = count;
}

