#ifndef TINYSTL_VECTOR
#define TINYSTL_VECTOR

#include <memory>
#include <algorithm>

/* based uppon the basic details as outlined in Bjarne Stroustrup
   TC++PL Special Edition p568++ */

namespace std {
  
  template<class T, typename A = allocator<T> >
  class vector {
  public:
    typedef T value_type;
    
    typedef typename A::pointer         pointer;
    typedef typename A::const_pointer   const_pointer;
    typedef typename A::reference       reference;
    typedef typename A::const_reference const_reference;

    //    typedef typename A allocator_type;

    typedef pointer        iterator;
    typedef const_pointer  const_iterator;
    typedef int            size_type;
    
    vector () : v(0), m_size(0), m_alloc_size(0) {}

    vector (const vector<T,A> &other) : v(0), m_size(0), m_alloc_size(0) {
      for(size_type i=0; i<other.size(); i++) push_back(other[i]);
    }
    
    ~vector () {
      iterator q = v;
      while (q < v+size()) {
	alloc.destroy (q++);
      }
      
      alloc.deallocate (v, m_alloc_size);
      
      v = 0;
      m_alloc_size = 0;
    }
    
    T& operator[] (size_type idx) {
      return v[idx];
    }
    
    T operator[] (size_type idx) const {
      return v[idx];
    }
    
    void assign (size_type num, const T& value) {
      // TODO
    }
    
    /*
    void assign (InputIterator beg, InputIterator end) {
      // TODO
    }
    */
    
    iterator insert (iterator pos, const T& value) {
      // we keep it simple - compute the index so we are
      // on the safe side on reallocations ...
      int idx = pos - v;
      
      if (size()>0) {
	reserve (size()+1);
	alloc.construct (v+m_size, *(v+m_size-1));
	std::copy_backward (v+idx-1, v+m_size-1, v+m_size);
	++m_size;
	v[idx] = value;
	return &v[idx];
      }
      push_back(value);
      return v;
    }
    
    void resize(size_type num) {
      // TODO
    }
    
    void resize(size_type num, T& value) {
      // TODO
    }
    
    size_type capacity () {
      return m_alloc_size;
    }
    
    void reserve (size_type n) {
      if (n <= capacity()) return;
      
      if (n < size()*2)
	n = size()*2;
      
      iterator p = alloc.allocate(n);
      iterator q = v;
      
      while (q < v+size()) {
	alloc.construct (p++, *q);
	alloc.destroy (q++);
      }
      
      alloc.deallocate (v, m_alloc_size);
      
      v = p - size();
      m_alloc_size = n;
    }
    
    T& front () {
      // TODO range check
      return v [0];
    }
    
    T& back () {
      // TODO range check
      return v [m_size];
    }
    
    iterator begin () {
      return v;
    }
    
    iterator end () {
      return v + m_size;
    }
    
    const_iterator begin () const {
      return v;
    }
    
    const_iterator end () const {
      return v + m_size + 1;
    }
    
    size_type size () const {
      return m_size;
    }
    
    bool empty () const {
      return m_size == 0;
    }
    
    size_type max_size () const {
      return 2^31;
    }

    void pop_back () {
      // NOW
    }
    
    void push_back (const T& value) {
      reserve (m_size + 1);
      alloc.construct (v+m_size++, value);
    }
    
  private:
    
    A alloc;
    
    iterator v;
    size_type m_size;
    size_type m_alloc_size;
  };

}

#endif
