#ifndef ARRAY_OF_OWN_H
#define ARRAY_OF_OWN_H

#ifndef ARRAY_OF_H
#include "Array_of.h"
#endif

#ifndef ARRAY_H
#include "Array.h"
#endif

//#ifndef OWN_H
//#include "Own.h"
//#endif

#ifndef LIVING_H
#include "Living.h"
#endif

#ifdef WIN32
#pragma warning (disable : 4786)
#endif

namespace MM
{

template <class T>
class Array_of_own : public Array_of <T>
{
//    Array <Own <T> >    impl_;
    Array <T*>          impl_;

public:
    virtual             ~Array_of_own()         {clear();}

    virtual int         size ()            const {return impl_.size ();}

    //virtual T &         operator[] (int i)       {return impl_[i] ();}
    //virtual const T &   operator[] (int i) const {return impl_[i] ();}
    virtual T &         operator[] (int i)       {return *impl_[i];}    //fix REQUIRE range
    virtual const T &   operator[] (int i) const {return *impl_[i];}    //fix REQUIRE range

    //virtual  T &        front()                  {return impl_.front()();}
    //virtual const T &   front() const            {return impl_.front()();}
    //virtual T &         back()                   {return impl_.back()();}
    //virtual const T &   back() const             {return impl_.back()();}
    virtual  T &        front()                  {return *impl_.front();}
    virtual const T &   front() const            {return *impl_.front();}
    virtual T &         back()                   {return *impl_.back();}
    virtual const T &   back() const             {return *impl_.back();}

    /*virtual void        push_back (T * adoptee)  {impl_.push_back(Own<T>(adoptee));}//fix
    virtual void        adopt (T * adoptee)      {impl_.push_back(Own<T>(adoptee));}
    virtual void        adopt (Array_of_own<T> & adoptee)
    {
        for (int i=0;  i<adoptee.size();  ++i)
        {
            impl_.push_back (adoptee.impl_[i]);
        }
        adoptee.clear();
    }//*/
    virtual void        push_back (T * adoptee)  {impl_.push_back(adoptee);}//fix
    virtual void        adopt (T * adoptee)      {impl_.push_back(adoptee);}
    virtual void        adopt (Array_of_own<T> & adoptee)
    {
        for (int i=0;  i<adoptee.size();  ++i)
        {
            impl_.push_back (adoptee.impl_[i]);
        }
        adoptee.clear();
    }

    //void                put (int index, T & item){impl_[index] = Own<T>(item); }
    //void                remove_at (int index)    {impl_.remove_at (index);}

    void                remove (T & item)
    {
        for (int i = 0;  i < size();  ++i)
            //if (&impl_[i] () == &item) 
            if (impl_[i] == &item) 
            {
                //impl_.remove_at (i);
                delete impl_[i];
                impl_.erase (impl_.begin() + i);
                return;
            }
        FLAW ("No such reference."); 
    }

    /*T *                 orphan (T & item)
    {
        for (int i = 0;  i < size();  ++i)
            if (&impl_[i] () == &item) 
            {
                T * result = impl_[i].orphan();
                //impl_.remove_at (i);
                impl_.erase (impl_.begin() + i);
                return result;
            }
        FLAW ("No such reference."); 
    }//*/
    T *                 orphan (T & item)
    {
        for (int i=0;  i<size();  ++i)
            if (impl_[i] == &item) 
            {
                T * result = impl_[i];
                impl_.erase (impl_.begin() + i);
                return result;
            }
        FLAW ("No such reference."); 
    }

    /*T *                 orphan (int index)
    {
        T * result = impl_[index].orphan();
        //impl_.remove_at (index);
        impl_.erase (impl_.begin() + index);
        return result;
    }//*/
    T *                 orphan (int index)
    {
        T * result = impl_[index];
        impl_.erase (impl_.begin() + index);
        return result;
    }

    /*void    orphan_all ()
    {
        for (int i = 0;  i < size();  ++i)
            impl_[i].orphan();
        
        clear();
    }//*/
    void    orphan_all ()
    {
        impl_.clear();
    }

    //void                clear() {impl_.clear();}
    void                clear() 
    {
        for (int i=0;  i<size();  ++i)
            delete impl_[i];

        impl_.clear();
    }

    void kill_deads ()
    {
        int removed = MM::kill_deads (impl_.begin(), impl_.end());
        impl_.erase (impl_.end()-removed, impl_.end());
    }

    void stable_kill_deads ()
    {
        for (int i=0;  i<impl_.size();  ++i)
            if (impl_[i]->is_dead())
            {
                impl_[i]->kill();
                impl_[i] = static_cast<T*>(0);
            }

        impl_.erase (stable_remove
            (impl_.begin(), impl_.end(), static_cast<T*>(0)), impl_.end());
    }
};

}//MM

#endif //ARRAY_OF_OWN_H

