#ifndef EBASICARRAY_DEC_H
#define EBASICARRAY_DEC_H

#include "eutils.h"

#include<vector>
#include<iostream>

using namespace std;

#include "ebasearray.h"

template <class T>
class ebasicarray;

typedef ebasicarray<int> eintarray;
typedef ebasicarray<long> elongarray;
typedef ebasicarray<float> efloatarray;
typedef ebasicarray<double> edoublearray;

template <class T>
ostream &operator<<(ostream &stream,const ebasicarray<T> &var);

template <class T>
class ecbasicarray : public vector<T>,public ebasearray
{
 public:
   ecbasicarray();

   ecbasicarray(const ebasearray& arr);

   ecbasicarray(const ecbasicarray<T> &arr);
   template <class... Tarr>
   ecbasicarray(const T& value,const Tarr&... values);
   ~ecbasicarray();

   void init(size_t count);
   void init(size_t count,const T& initval);

   ebasicarray<T> &operator=(const ecbasicarray<T> &arr);
   inline size_t size() const { return(vector<T>::size()); }

   inline ebasicarray<T>& operator+=(const T &value) { vector<T>::push_back(value); return(static_cast<ebasicarray<T>&>(*this)); }

   template <class... Tarr>
   inline void ignore_return(Tarr&&... values){}
   inline void ignore_return(){}
//   inline void add(){}

   inline T& push_back(const T& v){
     vector<T>::push_back(v);
     return(vector<T>::back());
   }

   template <class... Tarr>
//   inline T& add(const T& value,const Tarr&... values) {
   inline T& add(const T& value,const Tarr&... values) {
//      if (sizeof...(values))
      push_back(value);
      ignore_return(push_back(values)...);
      return(vector<T>::back());
   }

   inline void erase(size_t i) { vector<T>::erase(vector<T>::begin()+i); }
   inline void insert(size_t i,const T& value) { vector<T>::insert(vector<T>::begin()+i,value); }

   inline T& operator[](size_t i) { return(vector<T>::operator[](i)); }
   inline const T& operator[](size_t i) const { return(vector<T>::operator[](i)); }

   ebasicarray<T> operator[](const eintarray& i) const;
   ebasicarray<T> operator[](const elongarray& i) const;

   inline T& at(size_t i) { return(vector<T>::at(i)); }
   inline const T& at(size_t i) const { return(vector<T>::at(i)); }

   inline void swap(size_t i,size_t j){ T tmp(at(j)); at(j)=at(i); at(i)=tmp; }

   ebasicarray<T>& operator+=(const ecbasicarray<T>& arr);
   ebasicarray<T>& operator-=(const ecbasicarray<T>& arr);

   ebasicarray<T> operator+(const ecbasicarray<T>& arr) const;
   ebasicarray<T> operator-(const ecbasicarray<T>& arr) const;

//   inline const T operator[](int i) const { return( ((vector<T>)(*this))[i] ); }
//   inline T &operator[](int i){ return( ((vector<T>)(*this))[i] ); }

//   ebasicarray<T> operator[](const ebasicarray<int> &iarr);
   ebasicarray<T> subset(long i,long l) const;

   ebasicarray<T>& reverse();
 
   inline void clear() { vector<T>::clear(); }

   static bool equal(const T& a,const T& b){ return(a==b); }

   long find(const T& value,long i=0l,bool (*match)(const T&,const T&)=equal) const;   
   eintarray findall(const T &value,long i=0l,bool (*match)(const T&,const T&)=equal) const;
   eintarray findall(const ecbasicarray<T> &value,long i=0l,bool (*match)(const T&,const T&)=equal) const;
   
//   ebasicarray<T> afindall(const T &value,int i=0,bool (*match)(const T&,const T&)=equal) const;
   ebasicarray<T> afindall(const ecbasicarray<T> &value,long i=0l,bool (*match)(const T&,const T&)=equal) const;

//   void erase(const ebasicarray<int> &iarr);
   friend ostream &operator<< <>(ostream &stream,const ebasicarray<T> &var);

   virtual void addvar(evar& var);
   virtual evar getvar(size_t i) const;

   void serial(estr& data) const;
   size_t unserial(const estr& data,size_t i=0);
   void serial(const efile& f) const;
   bool unserial(const efile& f);
};

template <class T>
class earray;

template <class T>
class ebasicarray : public ecbasicarray<T>
{
 public:
  ebasicarray();
  
  template <class... Tarr>
  ebasicarray(const T& v,const Tarr&... values);
  ebasicarray(const ebasicarray<T>& arr);
  ebasicarray(const earray<evar>& varr);
};

template <>
class ebasicarray<evar> : public ecbasicarray<evar>
{
};

template <class T>
T maxarr(const ebasicarray<T>& arr)
{
  if (arr.size()==0)
    throw("empty array");

  T tmp=arr[0];
  for (size_t i=1; i<arr.size(); ++i)
    if (tmp<arr[i]) tmp=arr[i];
  return(tmp);
}

template <class T>
T maxarr(const earray<T>& arr)
{
  if (arr.size()==0)
    throw("empty array");

  T tmp=arr[0];
  for (size_t i=1; i<arr.size(); ++i)
    if (tmp<arr[i]) tmp=arr[i];
  return(tmp);
}

template <class T>
T minarr(const ebasicarray<T>& arr)
{
  if (arr.size()==0)
    throw("empty array");

  T tmp=arr[0];
  for (size_t i=1; i<arr.size(); ++i)
    if (tmp>arr[i]) tmp=arr[i];
  return(tmp);
}

template <class T>
T minarr(const earray<T>& arr)
{
  if (arr.size()==0)
    throw("empty array");

  T tmp=arr[0];
  for (size_t i=1; i<arr.size(); ++i)
    if (tmp>arr[i]) tmp=arr[i];
  return(tmp);
}


#endif

