#ifndef __AMSCPPNARRAY_HPP__
#define __AMSCPPNARRAY_HPP__

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

#include <vector>
#include <new>
#include <initializer_list>
#include <thread>

#include <amsmath/amsmath.hpp>
#include <amsutil/amsutil.hpp>

namespace ams
{
namespace narray
{

// Forward declaration of the operator- template function
//template<typename T> class narray;
//template<typename T> narray<T> operator-(const narray<T> &n);

typedef int64_t narray_size_t;

static const int narray_success = 1;
static const int narray_failure = -1;

//problem size at which to begin using threaded operations
static const narray_size_t narray_thread_sz = 5000;

//maximum number of threads to use
static const int narray_max_threads = 50;

template<typename T> class narray
{
    public:
    narray_size_t length;
    T *data;

    narray();
    narray(const narray<T>& other);
    narray(narray<T>&& other) noexcept;

    narray<T>& operator=(const narray<T>& other);
    narray<T>& operator=(narray<T>&& other) noexcept;
    
    narray<T>& operator=(const std::vector<T>& other);
    narray(const std::initializer_list<T> initlist);
    narray<T>& operator=(const std::initializer_list<T> initlist);
    ~narray();

    int resize(const narray_size_t newlength);
    const narray_size_t size() const;

    T& operator[](const narray_size_t ind);
    const T& operator[](const narray_size_t ind) const;
    T& at(const narray_size_t ind);
    const T& at(const narray_size_t ind) const;

    void clear(); //erases all elements, sets size to 0
    void setall(const T& val); //sets all elements to val

    //Comparators
    bool operator==(const narray<T>& other) const;
    bool operator!=(const narray<T>& other) const;

    //Operations
    narray<T> operator+(const narray<T>& other) const;
    narray<T> operator-(const narray<T>& other) const;
    narray<T> operator*(const narray<T>& other) const;
    narray<T> operator/(const narray<T>& other) const;
    narray<T> operator+(const T val) const;
    narray<T> operator-(const T val) const;
    narray<T> operator*(const T val) const;
    narray<T> operator/(const T val) const;
    template<class U> friend narray<U> operator-(const narray<U> &n);
    narray<T> applyfn(T (*fnptr)(T)) const;

    //min,max
    T min() const;
    T max() const;

    
    //subarray operations
    narray<T> subarray(const narray_size_t ind1, const narray_size_t ind2) const;

    //permutations and sorting



};

//Initializers
template<typename T> narray<T> arange(const T low, const T high, const T incr);
template<typename T> narray<T> zeros(const narray_size_t N);
template<typename T> narray<T> ones(const narray_size_t N);

narray<float> linspacef(const float low, const float high, narray_size_t N);
narray<double> linspace(const double low, const double high, narray_size_t N);


/////////
//Tests//
/////////

void test_narray1();
void test_narray2();
void test_narray3();

}; //end namespace narray
}; //end namespace ams

#include <amscppnarray/amscppnarray_impl.hpp>
#include <amscppnarray/amscppnarray_imploper.hpp>
#include <amscppnarray/amscppnarray_implsubarray.hpp>
#include <amscppnarray/amscppnarray_implinits.hpp>

#include <amscppnarray/amscppnarray_random.hpp>
#include <amscppnarray/amscppnarray_math.hpp>

#endif