#ifndef ARRAY_H
#define ARRAY_H

#include "Flaw.h"

#include <new>

#if defined WIN32
#pragma warning( disable : 4786 )
#endif


#include <vector>
namespace MM
{
template <typename T>
class Array : public std::vector<T>
{
public:
    T const & operator[] (int i) const
    {
        using namespace std;

        #ifndef NDEBUG
        if (i < 0  ||  i >= (int)size())
            FLAW (Text("Out of range: i=") + i + ", size=" + size());
        #endif

        //return std::vector<T>::operator[](i); 
        //return (*(begin() + i));
        return (*(this->vector<T>::begin() + i));
    }

    T & operator[](int i)
    {
        using namespace std;

        #ifndef NDEBUG
        if (i < 0  ||  i >= (int)size())
            FLAW (Text("Out of range: i=") + i + ", size=" + size());
        #endif

        //return std::vector<T>::operator[](i); 
        //return (*(begin() + i));
        return (*(this->vector<T>::begin() + i));
    }
    
    int size () const
    {
        using namespace std;
        return this->vector<T>::size();
    }

    /*void remove_at (int index)
    {
    }//*/
};
}//MM
//*/


/*namespace MM
{

void * raw_memory_alloc (size_t   size    );
void   raw_memory_free  (void   * memblock);

template <class T>
class Array_iterator;

template <class T>
class Array
{
    T                  *data_;
    T                  *end_;
    int                 data_counter_;
    int                 mem_counter_;

public:
    typedef T           value_type;
    typedef T*          iterator;
    typedef const T*    const_iterator;
    typedef T&          reference;
    typedef const T&    const_reference;
    typedef T*          pointer;
    typedef const T*    const_pointer;

    iterator            begin()                     {return data_;}
    const_iterator      begin() const               {return data_;}
    iterator            end  ()                     {return end_;}
    const_iterator      end  () const               {return end_;}
    //iterator            end  ()                     {return data_ + size();}
    //const_iterator      end  () const               {return data_ + size();}
    reference           front()                     {return data_[0];}
    const_reference     front() const               {return data_[0];}
    reference           back ()                     {return data_[size()-1];}
    const_reference     back () const               {return data_[size()-1];}

    reference           operator [] (int loc);
    const_reference     operator [] (int loc) const;

    int                 size    () const            
    {
        return data_counter_;
    }
    int                 capacity() const            {return mem_counter_;}

    //reference           add       (const T& t);      //fix test reference
    int                 add       (const T& t);    
    void                push_back (const T& t)       {add( t );}

    int                 find (const T & item);
    void                remove_at( int index );
//    void                remove( const T & );
//    void                add_at  ( const T& t, int loc );
//    void                detach  ( int   loc );              //fix ~ ; erase; clear
    void                reserve (int more);
    void                cancel_reserve();                    
    typename Array<T>::iterator  erase (typename Array<T>::iterator first, 
                                        typename Array<T>::iterator last);
    void                clear ();

    const Array<T> &    operator =  (const Array<T> &);
    const Array<T> &    operator += (const Array<T> &);

                        Array ();
    explicit            Array (int memory);
                        Array (const Array<T> & t);
                       ~Array ();

    friend class Array_iterator<T>;

private:

    void                realloc (int n);
//fix to policy    virtual int         new_capacity (int n) {return int(1.99 * n - 0.985);}
    int                 new_capacity (int n) {return int(1.99 * n - 0.985);}
    //    1 2 4 8 16
    void                destroy();
};

//============================================================================

template <class T>
class Fast_array : public Array<T>
{
    int                 new_capacity (int n) {return 4 * n;}
    //    4 16
};

//=================================================== =========================

template <class T>
class Compact_array : public Array<T>
 {
    int                 new_capacity (int n) {return int(1.329 * n - 0.32);}
    //    1 2 3 4 6 8 11 15
};

//============================================================================

template <class T>
class Array_iterator
{
    T                   *data_;
    int                 data_counter_;
    int                 position_;

public:
    Array_iterator (Array<T> & array)
    : data_(array.data_), data_counter_(array.data_counter_), position_(0)
    {
    }

    int                 size     () {return data_counter_;     }
    void                first    () {position_ = 0;            }
    void                next     () {++position_;              }
    bool                is_valid () {return position_ < size();}
    T &                 current  () {return data_[ position_ ];}
};

//============================================================================

template <class T> inline T& Array<T>::
operator [] (int loc)
{
    #ifndef NDEBUG
    if (loc < 0  ||  loc >= data_counter_)
        FLAW ("Out of range.");
    #endif

    return data_[loc];
}

template <class T> inline const T& Array<T>::
operator [] (int loc) const
{
    #ifndef NDEBUG
    if (loc < 0  ||  loc >= data_counter_)
        FLAW ("Out of range.");
    #endif

    return data_[loc];
}

template <class T>  Array<T>::
Array ()
: data_(0), end_(0), data_counter_(0), mem_counter_(0)
{
}

template <class T>  Array<T>::
Array (int memory)
: data_(0), end_(0), data_counter_(0), mem_counter_(0)
{
    reserve (memory);
}

template <class T>  Array<T>::
~Array ()
{
    destroy();
}

template <class T> inline void Array<T>::
destroy()
{
    for (int i=0;  i<data_counter_;  ++i)
    {
        data_[i].~T();
    }
    raw_memory_free (data_);
    data_         = 0;
    end_          = 0;
    data_counter_ = 0;
    mem_counter_  = 0;
}

//template <class T> inline Array<T>::reference Array<T>::
template <class T> inline int Array<T>::
add (const T& t)
{
    if (mem_counter_ <= data_counter_)
    {
        int size = new_capacity (data_counter_+ 1);
        realloc (size);
    }

    new (&data_[data_counter_]) T(t);
    ++data_counter_;
    end_ = data_ + data_counter_;
//    return data_[data_counter_ - 1];
    return data_counter_ - 1;
}

template <class T> inline void Array<T>::
remove_at (int index)
{
    erase (begin() + index, begin() + index + 1);
}

template <class T> inline int  Array<T>::
find (const T & item)
{
    int i = 0;

    while (i < size())
    {
        if (data_[i] == item)    return i;
        ++i;
    }
    FLAW ("Item not found.");
}

//template <class T > inline void  Array<T>::
//remove( const T & item )
//{
//    int i = find( item );
//    remove_at( i );
//}
//
//template <class T > inline void  Array<T>::
//remove( const T & item )
//{
//    for( int i = 0;  i < size();  ++i )
//        if( & data_[ i ] == & item )
//        {
//            remove( i );
//            return;
//        }
//    throw Item_not_found_exception();
//}

template <class T>  void  Array<T>::
realloc (int n)
{
    if (n < data_counter_)
        FLAW ("Size less then capacity.");

    void * raw_memory = raw_memory_alloc (n * sizeof(T));
    T    * tmp_memory = static_cast <T*> (raw_memory);
    for (int i=0;  i<data_counter_;  ++i)
    {
        new (&tmp_memory[i]) T(data_[i]);
        data_[i].~T();
    }
    raw_memory_free (data_);
    data_ = tmp_memory;
    end_ = data_ + data_counter_;
    mem_counter_ = n;
}

//template <class T> inline void  Array<T>::
//add_at( const T& t, int loc )
//{
//    int i;
//
//    #ifndef NDEBUG                       
//    if( loc < 0 || loc > data_counter_ ) 
//        throw Out_of_range_exception();
//    #endif
//
//    if( mem_counter_ <= data_counter_ )
//        realloc( new_capacity( data_counter_+ 1 ) ); 
//
//    for( i=data_counter_-1;  i>=loc;  i-- )  
//        data_[i+1] = data_[i];
//
//    ++data_counter_;
//    data_[loc] = t;
//}

template <class T>  void Array<T>::
reserve (int more)
{
    realloc (mem_counter_ + more);
}

template <class T>  void Array<T>::
cancel_reserve ()
{
    realloc (data_counter_);
}

template <class T> typename Array<T>::iterator Array<T>::
erase (Array<T>::iterator first, Array<T>::iterator last)
{
    while (last != end())
    {
        new (first) T(*last);
        ++first;
        ++last;
    }

    iterator result = first;

    while (first != end())
    {
        first->~T();
        typename Array<T>::iterator tmp = first;
        ++first;
        tmp = 0;
    }

    //result = 0;//fix
        
    data_counter_ = result - begin();
    end_ = data_ + size();
    return result;
}

template <class T>  void Array<T>::
clear ()
{
    erase (begin(), end());
}

template <class T>  const Array<T> &  Array<T>::
operator = (const Array<T> & t)
{
    if (this != &t)
    {
        destroy();
        *this += t;
    }
    return *this;
}

template <class T>  const Array<T> &  Array<T>::
operator += (const Array<T> & t)
{
    realloc (size() + t.size());
    for (int i=0;  i<t.size();  ++i)
        data_[data_counter_++] = t.data_[i];
    end_ = data_ + size();
    return *this;
}

template <class T>  Array<T>::
Array (const Array<T> & t)
: 
    data_(0), end_(0), data_counter_(0), mem_counter_(0)
{
    *this += t;
}

}//MM
//*/

#endif//ARRAY_H

