#include <amscppnarray/amscppnarray.hpp>

namespace ams
{
namespace narray
{

void narray_linspacef_tf(
    narray<float> *in,
    const float low, const float high, const narray_size_t N,
    int threadnum, int nthreads
)
{
    int I0,I1,Is,I;
    float g;

    Is = in->length/nthreads;
    I0 = Is*threadnum;
    I1 = (threadnum>=(nthreads-1))? in->length: Is*(threadnum+1);
    for(I=I0;I<I1;I++)
    {
        g = ((float)I)/((float)(N-1));
        in->data[I] = low*(1.0f-g) + high*g;
    }
}


narray<float> linspacef(const float low, const float high, narray_size_t N)
{
    narray<float> ret;
    narray_size_t I;
    int J;
    int nthreads;
    std::vector<std::thread*> threads;
    float g;

    if(N<=0)
    {
        N = 0;
    }
    ret.resize(N);

    if(ret.length==0)
    {
        return ret;
    }

    if(ret.length<narray_thread_sz)
    {
        for(I=0;I<ret.length;I++)
        {
            g = ((float)I)/((float)(N-1));
            ret.data[I] = low*(1.0f-g) + high*g;
        }
    }
    else
    {
        //threaded operation
        nthreads = std::thread::hardware_concurrency();
        nthreads = (nthreads<1) ? 1 : nthreads;
        nthreads = (nthreads>narray_max_threads) ? narray_max_threads : nthreads;
        //if(nthreads<1) nthreads=1;
        //if(nthreads>narray_max_threads) nthreads = narray_max_threads;
        threads.resize(nthreads);
        for(J=0;J<nthreads;J++)
        {
            threads[J] = new(std::nothrow) std::thread(
                &narray_linspacef_tf,
                &ret,
                low,high,N,
                J,nthreads
            );
        }
        for(J=0;J<nthreads;J++)
        {
            if(threads[J]!=NULL)
            { 
                threads[J]->join(); 
                delete threads[J]; 
                threads[J]= NULL;
            }
        }
    }



    return ret;
}

void narray_linspace_tf(
    narray<double> *in,
    const double low, const double high, const narray_size_t N,
    int threadnum, int nthreads
)
{
    int I0,I1,Is,I;
    double g;

    Is = in->length/nthreads;
    I0 = Is*threadnum;
    I1 = (threadnum>=(nthreads-1))? in->length: Is*(threadnum+1);
    for(I=I0;I<I1;I++)
    {
        g = ((double)I)/((double)(N-1));
        in->data[I] = low*(1.0-g) + high*g;
    }
}

narray<double> linspace(const double low, const double high, narray_size_t N)
{
    narray<double> ret;
    narray_size_t I;
    int J;
    int nthreads;
    std::vector<std::thread*> threads;
    double g;

    if(N<=0)
    {
        N = 0;
    }
    ret.resize(N);

    if(ret.length==0)
    {
        return ret;
    }

    if(ret.length<narray_thread_sz)
    {
        for(I=0;I<ret.length;I++)
        {
            g = ((double)I)/((double)(N-1));
            ret.data[I] = low*(1.0-g) + high*g;
        }
    }
    else
    {
        //threaded operation
        nthreads = std::thread::hardware_concurrency();
        nthreads = (nthreads<1) ? 1 : nthreads;
        nthreads = (nthreads>narray_max_threads) ? narray_max_threads : nthreads;
        //if(nthreads<1) nthreads=1;
        //if(nthreads>narray_max_threads) nthreads = narray_max_threads;
        threads.resize(nthreads);
        for(J=0;J<nthreads;J++)
        {
            threads[J] = new(std::nothrow) std::thread(
                &narray_linspace_tf,
                &ret,
                low,high,N,
                J,nthreads
            );
        }
        for(J=0;J<nthreads;J++)
        {
            if(threads[J]!=NULL)
            { 
                threads[J]->join(); 
                delete threads[J]; 
                threads[J]= NULL;
            }
        }
    }



    return ret;
}


}; //end namespaces
};