#ifndef __AMSMATHUTIL25_BUFFEROPS_IMPL_HPP__
#define __AMSMATHUTIL25_BUFFEROPS_IMPL_HPP__

namespace ams
{

    template<typename T> void buffer_set_tf(
        int threadnum,
        int nthread,
        T *buffer,
        buffer_size_t indstart, 
        buffer_size_t indstop, 
        const T val
    )
    {
        buffer_size_t I,I0,I1,Is,N;

        N = indstop-indstart;
        N = (N<0) ? 0 : N;
        //Is = N/nthread;

        Is = (nthread<=0) ? N : N/nthread;
        I0 = Is*(threadnum);
        I1 = (threadnum>=(nthread-1)) ? N : Is*(threadnum+1);
        
        // I0 = (I0<=0) ? 0 : I0;
        // I1 = (I1<=0) ? 0 : I1;
        I0 = (I0>N) ? N : I0;
        I1 = (I1>N) ? N : I1;

        for(I=I0;I<I1;I++)
        {
            buffer[I+indstart] = val;
        }
        
        return;
    }

    //threaded set - sets N elements of bufffer to val
    template<typename T> int buffer_set(T* buffer, buffer_size_t indstart, buffer_size_t indstop, const T val)
    {
        int ret = amsmathutil25_success;
        int res;
        buffer_size_t psize;
        buffer_size_t I;

        indstart = (indstart<0) ? 0 : indstart;
        indstop = (indstop<0) ? 0 : indstop;
        indstop = (indstop<indstart) ? indstart : indstop;
        psize = indstop-indstart;
        //psize = (psize<=0) ? 0 : psize; //redundant

        if(psize<amsmathutil25_threadpsz)
        {
            for(I=0;I<psize;I++)
            {
                buffer[I+indstart] = val;
            }
        }
        else
        {

            res = ams::threaded_execute(
                &buffer_set_tf<T>,(int64_t) psize,
                buffer,indstart,indstop,val
            );
            ret = res;

        }
        return ret;
    }

    //threaded set - sets N elements of bufffer to val
    template<typename T> int buffer_set_unthreaded(T* buffer, buffer_size_t N, const T val)
    {
        int ret = amsmathutil25_success;
        buffer_size_t I;

        for(I=0;I<N;I++)
        {
            buffer[I] = val;
        }

        return ret;
    }

    //threaded set - sets N elements of bufffer to val
    template<typename T> int buffer_set_unthreaded(T* buffer, buffer_size_t indstart, buffer_size_t indstop, const T val)
    {
        int ret = amsmathutil25_success;
        buffer_size_t I;
        buffer_size_t psize;

        indstart = (indstart<0) ? 0 : indstart;
        indstop = (indstop<0) ? 0 : indstop;
        indstop = (indstop<indstart) ? indstart : indstop;
        psize = indstop-indstart;

        for(I=0;I<psize;I++)
        {
            buffer[I+indstart] = val;
        }

        return ret;
    }


    //threaded set - sets N elements of bufffer to val
    template<typename T> int buffer_set(T* buffer, buffer_size_t N, const T val)
    {
        int ret = amsmathutil25_success;
        buffer_size_t I;

        if(N<amsmathutil25_threadpsz)
        {
            for(I=0;I<N;I++) buffer[I] = val;
        }
        else
        {
            ret = buffer_set<T>(buffer,0,N,val);
        }
        return ret;
    }

    template<typename T1, typename T2> void buffer_cast_copy_tf(
        int threadnum,
        int nthread,
        T1 *bufferto,
        const T2 *bufferfrom,
        buffer_size_t offsetto,
        buffer_size_t offsetfrom,
        buffer_size_t N
    )
    {
        buffer_size_t I,I0,I1,Is;

        // Is = N/(nthread-1);
        // Is = (Is<=0) ? 1 : Is;
        // I0 = Is*(threadnum);
        // I1 = Is*(threadnum+1);
        // I0 = (I0<=0) ? 0 : I0;
        // I1 = (I1<=0) ? 0 : I1;
        // I0 = (I0>N) ? N : I0;
        // I1 = (I1>N) ? N : I1;

        Is = (nthread<=0) ? N : N/nthread;
        I0 = Is*(threadnum);
        I1 = (threadnum>=(nthread-1)) ? N : Is*(threadnum+1);
        
        // I0 = (I0<=0) ? 0 : I0;
        // I1 = (I1<=0) ? 0 : I1;
        I0 = (I0>N) ? N : I0;
        I1 = (I1>N) ? N : I1;

        for(I=I0;I<I1;I++)
        {
            bufferto[I + offsetto] = (T1) (bufferfrom[I + offsetfrom]);
        }
        
        return;
    }

    //threaded copy of bufferfrom[offsetfrom + I] to bufferto[offsetto+I] I = [0,N)
    template<typename T1, typename T2> int buffer_cast_copy(T1* bufferto, const T2* bufferfrom, 
        buffer_size_t offsetto, buffer_size_t offsetfrom, buffer_size_t N)
    {
        int ret = amsmathutil25_success;
        int res;
        res = ams::threaded_execute(
            &buffer_cast_copy_tf<T1,T2>,(int64_t) N,
            bufferto,bufferfrom,offsetto,offsetfrom,N
        );
        ret = res;

        return ret;
    }

    //threaded copy of bufferfrom to bufferto
    template<typename T1, typename T2> int buffer_cast_copy(T1* bufferto, const T2* bufferfrom, buffer_size_t N)
    {
        int ret = amsmathutil25_success;
        buffer_size_t I;

        if(N<amsmathutil25_threadpsz)
        {
            for(I=0;I<N;I++) bufferto[I] = (T1) bufferfrom[I];
        }
        else
        {
            ret = buffer_cast_copy<T1,T2>(bufferto,bufferfrom,0,0,N);
        }

        return ret;
    }

    //threaded copy of bufferfrom[offsetfrom + I] to bufferto[offsetto+I] I = [0,N)
    template<typename T1, typename T2> int buffer_cast_copy_unthreaded(T1* bufferto, const T2* bufferfrom, 
        buffer_size_t offsetto, buffer_size_t offsetfrom, buffer_size_t N)
    {
        int ret = amsmathutil25_success;
        buffer_size_t I;

        for(I=0;I<N;I++)
        {
            bufferto[I+offsetto] = (T1) bufferfrom[I+offsetfrom];
        }

        return ret;
    }

    //threaded copy of bufferfrom to bufferto
    template<typename T1, typename T2> int buffer_cast_copy_unthreaded(T1* bufferto, const T2* bufferfrom, buffer_size_t N)
    {
        int ret = amsmathutil25_success;
        buffer_size_t I;

        for(I=0;I<N;I++)
        {
            bufferto[I] = (T1) bufferfrom[I];
        }

        return ret;
    }


}; //end namespace ams

#endif

