#ifndef __AMSCUDA_BINARRRW_IMPL_HPP__
#define __AMSCUDA_BINARRRW_IMPL_HPP__

namespace amscuda
{

template<typename T> int fread_ndarray(FILE *fp, cuarray<int32_t> *shape, cuarray<T> *buffer)
{
    int ret = 1;
    int I;
    long piprod;
    int32_t q;
    int cnt;

    int32_t Nd;

    if(fp!=NULL)
    {
        if(!feof(fp))
        {
            cnt = fread(&Nd,sizeof(int32_t),1,fp);
            if(Nd>0 && cnt>0)
            {
                shape->resize(Nd);
                piprod = 1;
                for(I=0;I<Nd;I++)
                {
                    cnt = fread(&q,sizeof(int32_t),1,fp);
                    shape->at(I) = q;
                    if(q>0)
                    {
                        piprod = piprod*q;
                    }
                    else
                    {
                        piprod = 0;
                    }
                }

                buffer->resize(piprod);
                if(piprod>0)
                {
                    cnt = fread((buffer->data),sizeof(T),piprod,fp);
                    if(piprod==cnt)
                    {
                        ret = 1;
                    }
                    else
                    {
                        printf("fread_ndarray, read %d values, expecting %ld\n",cnt,piprod);
                        ret = 0;
                    }
                }
            }
            else
            {
                printf("fread_ndarray: Read a number of dimensions<=0.\n");
                Nd = 0;
                shape->resize(0);
                buffer->resize(0);
            }
        }
        else
        {
            printf("fread_ndarray: fp=NULL.\n");
            ret = 0;
        }
    }
    else
    {
        ret = 0;
    }

    return ret;
}

template<typename T> int fwrite_ndarray(FILE *fp, const cuarray<int32_t> *shape, const cuarray<T> *buffer)
{
    int ret = 1;
    long piprod;
    int I;
    int32_t Nd;

    if(fp==NULL)
    {
        ret = 0;
        printf("fwrite_ndarray: fp=NULL\n");
        return ret;
    }

    piprod = 1;
    for(I=0;I<shape->size();I++)
    {
        if(shape->at(I)>0)
        {
            piprod = piprod*shape->at(I);
        }
        else
        {
            piprod = 0;
        }
    }

    Nd = (int32_t) shape->size();

    if(piprod!=buffer->size())
    {
        ret = 0;
        printf("fwrite_ndarray: buffer is size %ld, while shape is size %ld\n",(long)buffer->size(),(long)piprod);
        return ret;
    }

    fwrite(&Nd,sizeof(int32_t),1,fp);
    if(Nd>0)
    {
        fwrite(shape->data,sizeof(int32_t),Nd,fp);
        if(piprod>0)
        {
            fwrite(buffer->data,sizeof(T),buffer->size(),fp);
        }
    }

    return ret;
}

template<typename T> int fwrite_buffer(FILE *fp, const int N, const T *buffer)
{
    int ret = 0;
    int Nd = 1;
    
    if(fp==NULL)
    {
        ret = 0;
        printf("fwrite_buffer: fp=NULL\n");
        return ret;
    }

    fwrite(&Nd,sizeof(int32_t),1,fp);
    fwrite(&N,sizeof(int32_t),1,fp);
    fwrite(buffer,sizeof(T),N,fp);
    
    return ret;
}

template<typename T> int fread_buffer(FILE *fp, const int Nmax, const T *buffer)
{
    int ret = 0;
    
    int cnt;
    int32_t Nd;
    int32_t *dims = NULL;
    int piprod;
    int32_t q;
    int I;

    int Nr;


    if(fp==NULL) {ret = -1; return ret;}
    if(feof(fp)) {ret = -2; return ret;}

    cnt = fread(&Nd,sizeof(int32_t),1,fp);
    if(Nd>0 && cnt>0)
    {
        piprod = 1;
        dims = new(std::nothrow) int32_t[Nd];
        for(I=0;I<Nd;I++)
        {
            cnt = fread(&q,sizeof(int32_t),1,fp);
            dims[I] = q;
            piprod = piprod*dims[I];
            if(piprod==cnt)
            {
                ret = 1;
            }
            else
            {
                printf("fwrite_buffer, read %d values, expecting %d\n",cnt,piprod);
            }
        }

        Nr = amscuda::min<int32_t>(Nmax,piprod);
        cnt = fread(buffer,sizeof(T),Nr,fp);
    }

    if(dims!=NULL) {delete[] dims; dims=NULL;}

    return ret;
}

}; //end namespace amscuda

#endif

