#ifdef WIN32
#define EXPORTED __declspec(dllexport)
#else
#define EXPORTED
#endif
#include <stdio.h>
#include "idl_export.h"


// ==========    1D ============================//

//********** 1D rebinning with yerr and ewid ***************//
 EXPORTED int rebin1d_nat_yew(IDL_LONG* ndat, double* x, double* y,
    double* yerr, double* ewid, IDL_LONG *nx,
    double *xmin, double *xstep,
    IDL_LONG* num_x, double* tmp_x, double* tmp_y,
    double* tmp_e, double* tmp_w)
{
    long i, ix;

    for (i = 0L; i < (*ndat); i++){
        ix = (long)((x[i] - (*xmin)) / (*xstep));
        if ((ix < 0) || (ix >= (*nx))) return 1;
        num_x[ix]++;
        tmp_x[ix] += x[i];
        tmp_y[ix] += y[i];
        tmp_e[ix] += yerr[i]*yerr[i];
        tmp_w[ix] += ewid[i];
        }
    return 0;
}

 EXPORTED int rebin1d_yew(int argc, void* argv[]) {
    return rebin1d_nat_yew((IDL_LONG *) argv[0],(double *) argv[1], (double *) argv[2],
    (double *) argv[3], (double *) argv[4], (IDL_LONG *) argv[5],
    (double *) argv[6], (double *) argv[7],
    (IDL_LONG *) argv[8], (double *) argv[9], (double *) argv[10],
    (double *) argv[11], (double *) argv[12]);
}

//********** 1D rebinning with yerr ***************//
 EXPORTED int rebin1d_nat_ye(IDL_LONG* ndat, double* x, double* y,
    double* yerr,  IDL_LONG *nx,
    double *xmin, double *xstep,
    IDL_LONG* num_x, double* tmp_x, double* tmp_y,
    double* tmp_e)
{
    long i, ix;

    for (i = 0L; i < (*ndat); i++){
        ix = (long)((x[i] - (*xmin)) / (*xstep));
        if ((ix < 0) || (ix >= (*nx))) return 1;
        num_x[ix]++;
        tmp_x[ix] += x[i];
        tmp_y[ix] += y[i];
        tmp_e[ix] += yerr[i]*yerr[i];
        }
    return 0;
}

 EXPORTED int rebin1d_ye(int argc, void* argv[]) {
    return rebin1d_nat_ye((IDL_LONG *) argv[0],(double *) argv[1], (double *) argv[2],
    (double *) argv[3], (IDL_LONG *) argv[4],
    (double *) argv[5], (double *) argv[6],
    (IDL_LONG *) argv[7], (double *) argv[8], (double *) argv[9],
    (double *) argv[10]);
}

//********** 1D rebinning with ewid ***************//
 EXPORTED int rebin1d_nat_yw(IDL_LONG* ndat, double* x, double* y,
    double* ewid,  IDL_LONG *nx,
    double *xmin, double *xstep,
    IDL_LONG* num_x, double* tmp_x, double* tmp_y,
    double* tmp_w)
{
    long i, ix;

    for (i = 0L; i < (*ndat); i++){
        ix = (long)((x[i] - (*xmin)) / (*xstep));
        if ((ix < 0) || (ix >= (*nx))) return 1;
        num_x[ix]++;
        tmp_x[ix] += x[i];
        tmp_y[ix] += y[i];
        tmp_w[ix] += ewid[i];
        }
    return 0;
}

 EXPORTED int rebin1d_yw(int argc, void* argv[]) {
    return rebin1d_nat_yw((IDL_LONG *) argv[0],(double *) argv[1], (double *) argv[2],
    (double *) argv[3], (IDL_LONG *) argv[4],
    (double *) argv[5], (double *) argv[6],
    (IDL_LONG *) argv[7], (double *) argv[8], (double *) argv[9],
    (double *) argv[10]);
}

//********** 1D rebinning data only ***************//
 EXPORTED int rebin1d_nat_y(IDL_LONG* ndat, double* x, double* y,
    IDL_LONG *nx,
    double *xmin, double *xstep,
    IDL_LONG* num_x, double* tmp_x, double* tmp_y)
{
    long i, ix;

    for (i = 0L; i < (*ndat); i++){
        ix = (long)((x[i] - (*xmin)) / (*xstep));
        if ((ix < 0) || (ix >= (*nx))) return 1;
        num_x[ix]++;
        tmp_x[ix] += x[i];
        tmp_y[ix] += y[i];
        }
    return 0;
}

 EXPORTED int rebin1d_y(int argc, void* argv[])
{
    return rebin1d_nat_y((IDL_LONG *) argv[0],(double *) argv[1], (double *) argv[2],
    (IDL_LONG *) argv[3],
    (double *) argv[4], (double *) argv[5],
    (IDL_LONG *) argv[6], (double *) argv[7], (double *) argv[8]);
}






// ==========    2D ============================//




//********** 2D rebinning with zerr and ewid ***************//
 EXPORTED int rebin2d_nat_zew(IDL_LONG* ndat,double* x, double* y, double* z,
    double* zerr, double* ewid, IDL_LONG *nx, IDL_LONG *ny,
    double *xmin, double *xstep, double* ymin, double *ystep,
    IDL_LONG* num_x, double* tmp_x, IDL_LONG* num_y, double* tmp_y,
    IDL_LONG* num_z, double* tmp_z, double* tmp_e, double* tmp_w)
{
    long i, ix, iy;

    for (i = 0L; i < (*ndat); i++){
        ix = (long)((x[i] - (*xmin)) / (*xstep));
        iy = (long)((y[i] - (*ymin)) / (*ystep));
        if ((ix < 0) || (ix >= (*nx)) || (iy < 0) || (iy >= (*ny))) return 1;
        num_x[ix]++;
        num_y[iy]++;
        tmp_x[ix] += x[i];
        tmp_y[iy] += y[i];
        tmp_z[ix + iy * (*nx)] += z[i];
        num_z[ix + iy * (*nx)]++;
        tmp_e[ix + iy * (*nx)] += zerr[i]*zerr[i];
        tmp_w[ix + iy * (*nx)] += ewid[i];
        }
    return 0;
}

 EXPORTED int rebin2d_zew(int argc, void* argv[])
{
    return rebin2d_nat_zew((IDL_LONG *) argv[0],(double *) argv[1], (double *) argv[2], (double *) argv[3],
    (double *) argv[4], (double *) argv[5], (IDL_LONG *) argv[6], (IDL_LONG *) argv[7],
    (double *) argv[8], (double *) argv[9], (double *) argv[10], (double *) argv[11],
    (IDL_LONG *) argv[12], (double *) argv[13], (IDL_LONG *) argv[14], (double *) argv[15],
    (IDL_LONG *) argv[16], (double *) argv[17], (double *) argv[18], (double *) argv[19]);
}


//********** 2D rebinning with zerr ********************//
 EXPORTED int rebin2d_nat_ze(IDL_LONG* ndat,double* x, double* y, double* z, double* zerr,
    IDL_LONG *nx, IDL_LONG *ny,
    double *xmin, double *xstep, double* ymin, double *ystep,
    IDL_LONG* num_x, double* tmp_x, IDL_LONG* num_y, double* tmp_y,
    IDL_LONG* num_z, double* tmp_z, double* tmp_e)
{
    long i, ix, iy;

    for (i = 0L; i < (*ndat); i++){
        ix = (long)((x[i] - (*xmin)) / (*xstep));
        iy = (long)((y[i] - (*ymin)) / (*ystep));
        if ((ix < 0) || (ix >= (*nx)) || (iy < 0) || (iy >= (*ny))) return 1;
        num_x[ix]++;
        num_y[iy]++;
        tmp_x[ix] += x[i];
        tmp_y[iy] += y[i];
        tmp_z[ix + iy * (*nx)] += z[i];
        num_z[ix + iy * (*nx)]++;
        tmp_e[ix + iy * (*nx)] += zerr[i]*zerr[i];
        }
    return 0;
}

 EXPORTED int rebin2d_ze(int argc, void* argv[])
{
    return rebin2d_nat_ze((IDL_LONG *) argv[0],(double *) argv[1], (double *) argv[2], (double *) argv[3],
    (double *) argv[4], (IDL_LONG *) argv[5], (IDL_LONG *) argv[6],
    (double *) argv[7], (double *) argv[8], (double *) argv[9], (double *) argv[10],
    (IDL_LONG *) argv[11], (double *) argv[12], (IDL_LONG *) argv[13], (double *) argv[14],
    (IDL_LONG *) argv[15], (double *) argv[16], (double *) argv[17]);
}


//********** 2D rebinning with ewid **********************//
 EXPORTED int rebin2d_nat_zw(IDL_LONG* ndat,double* x, double* y, double* z,
    double* ewid, IDL_LONG *nx, IDL_LONG *ny,
    double *xmin, double *xstep, double* ymin, double *ystep,
    IDL_LONG* num_x, double* tmp_x, IDL_LONG* num_y, double* tmp_y,
    IDL_LONG* num_z, double* tmp_z, double* tmp_w)
{
    long i, ix, iy;

    for (i = 0L; i < (*ndat); i++){
        ix = (long)((x[i] - (*xmin)) / (*xstep));
        iy = (long)((y[i] - (*ymin)) / (*ystep));
        if ((ix < 0) || (ix >= (*nx)) || (iy < 0) || (iy >= (*ny))) return 1;
        num_x[ix]++;
        num_y[iy]++;
        tmp_x[ix] += x[i];
        tmp_y[iy] += y[i];
        tmp_z[ix + iy * (*nx)] += z[i];
        num_z[ix + iy * (*nx)]++;
        tmp_w[ix + iy * (*nx)] += ewid[i];
        }
    return 0;
}

 EXPORTED int rebin2d_zw(int argc, void* argv[])
{
    return rebin2d_nat_zw((IDL_LONG *) argv[0],(double *) argv[1], (double *) argv[2], (double *) argv[3],
    (double *) argv[4], (IDL_LONG *) argv[5], (IDL_LONG *) argv[6],
    (double *) argv[7], (double *) argv[8], (double *) argv[9], (double *) argv[10],
    (IDL_LONG *) argv[11], (double *) argv[12], (IDL_LONG *) argv[13], (double *) argv[14],
    (IDL_LONG *) argv[15], (double *) argv[16], (double *) argv[17]);
}


//********** 2D rebinning data only **********************//
 EXPORTED int rebin2d_nat_z(IDL_LONG* ndat,double* x, double* y, double* z,
    IDL_LONG *nx, IDL_LONG *ny,
    double *xmin, double *xstep, double* ymin, double *ystep,
    IDL_LONG* num_x, double* tmp_x, IDL_LONG* num_y, double* tmp_y,
    IDL_LONG* num_z, double* tmp_z)
{
    long i, ix, iy;

    for (i = 0L; i < (*ndat); i++){
        ix = (long)((x[i] - (*xmin)) / (*xstep));
        iy = (long)((y[i] - (*ymin)) / (*ystep));

        if ((ix < 0) || (ix >= (*nx)) || (iy < 0) || (iy >= (*ny))) return 1;
        num_x[ix]++;
        num_y[iy]++;
        tmp_x[ix] += x[i];
        tmp_y[iy] += y[i];
        tmp_z[ix + iy * (*nx)] += z[i];
        num_z[ix + iy * (*nx)]++;
        }
    return 0;
}

 EXPORTED int rebin2d_z(int argc, void* argv[])
{
    return rebin2d_nat_z((IDL_LONG *) argv[0],(double *) argv[1], (double *) argv[2], (double *) argv[3],
    (IDL_LONG *) argv[4], (IDL_LONG *) argv[5],
    (double *) argv[6], (double *) argv[7], (double *) argv[8], (double *) argv[9],
    (IDL_LONG *) argv[10], (double *) argv[11], (IDL_LONG *) argv[12], (double *) argv[13],
    (IDL_LONG *) argv[14], (double *) argv[15]);
}



// ==========    3D ============================//



//********** 3D rebinning with ierr and ewid ***************//
 EXPORTED int rebin3d_nat_iew(IDL_LONG* ndat,double* x, double* y, double* z, double* idat,
    double* ierr, double* ewid, IDL_LONG *nx, IDL_LONG *ny, IDL_LONG *nz,
    double *xmin, double *xstep, double* ymin, double *ystep, double* zmin, double *zstep,
    IDL_LONG* num_x, double* tmp_x, IDL_LONG* num_y, double* tmp_y, IDL_LONG* num_z, double* tmp_z,
    IDL_LONG* num_i, double* tmp_i, double* tmp_e, double* tmp_w)
{
    long i, ix, iy, iz;

    for (i = 0L; i < (*ndat); i++){
        ix = (long)((x[i] - (*xmin)) / (*xstep));
        iy = (long)((y[i] - (*ymin)) / (*ystep));
        iz = (long)((z[i] - (*zmin)) / (*zstep));
        if ((ix < 0) || (ix >= (*nx)) || (iy < 0) || (iy >= (*ny))|| (iz < 0) || (iz >= (*nz))) return 1;
        num_x[ix]++;
        num_y[iy]++;
        num_z[iz]++;
        tmp_x[ix] += x[i];
        tmp_y[iy] += y[i];
        tmp_z[iz] += z[i];
        tmp_i[ix + iy * (*nx) + iz * (*nx) * (*ny)] += idat[i];
        num_i[ix + iy * (*nx) + iz * (*nx) * (*ny)]++;
        tmp_e[ix + iy * (*nx) + iz * (*nx) * (*ny)] += ierr[i]*ierr[i];
        tmp_w[ix + iy * (*nx) + iz * (*nx) * (*ny)] += ewid[i];
        }
    return 0;
}

  EXPORTED int rebin3d_iew(int argc, void* argv[])
{
    return rebin3d_nat_iew((IDL_LONG *) argv[0],(double *) argv[1], (double *) argv[2], (double *) argv[3], (double *) argv[4],
	(double *) argv[5],(double *) argv[6], (IDL_LONG *) argv[7], (IDL_LONG *) argv[8], (IDL_LONG *) argv[9],
    (double *) argv[10], (double *) argv[11], (double *) argv[12], (double *) argv[13], (double *) argv[14], (double *) argv[15],
    (IDL_LONG *) argv[16], (double *) argv[17], (IDL_LONG *) argv[18], (double *) argv[19], (IDL_LONG *) argv[20], (double *) argv[21],
    (IDL_LONG *) argv[22], (double *) argv[23], (double *) argv[24], (double *) argv[25]);
}

//********** 3D rebinning with ierr  ***************//
 EXPORTED int rebin3d_nat_ie(IDL_LONG* ndat,double* x, double* y, double* z, double* idat,
    double* ierr, IDL_LONG *nx, IDL_LONG *ny, IDL_LONG *nz,
    double *xmin, double *xstep, double* ymin, double *ystep, double* zmin, double *zstep,
    IDL_LONG* num_x, double* tmp_x, IDL_LONG* num_y, double* tmp_y, IDL_LONG* num_z, double* tmp_z,
    IDL_LONG* num_i, double* tmp_i, double* tmp_e)
{
    long i, ix, iy, iz;

    for (i = 0L; i < (*ndat); i++){
        ix = (long)((x[i] - (*xmin)) / (*xstep));
        iy = (long)((y[i] - (*ymin)) / (*ystep));
        iz = (long)((z[i] - (*zmin)) / (*zstep));
        if ((ix < 0) || (ix >= (*nx)) || (iy < 0) || (iy >= (*ny))|| (iz < 0) || (iz >= (*nz))) return 1;
        num_x[ix]++;
        num_y[iy]++;
        num_z[iz]++;
        tmp_x[ix] += x[i];
        tmp_y[iy] += y[i];
        tmp_z[iz] += z[i];
        tmp_i[ix + iy * (*nx) + iz * (*nx) * (*ny)] += idat[i];
        num_i[ix + iy * (*nx) + iz * (*nx) * (*ny)]++;
        tmp_e[ix + iy * (*nx) + iz * (*nx) * (*ny)] += ierr[i]*ierr[i];
        }
    return 0;
}

  EXPORTED int rebin3d_ie(int argc, void* argv[])
{
    return rebin3d_nat_ie((IDL_LONG *) argv[0],(double *) argv[1], (double *) argv[2], (double *) argv[3], (double *) argv[4],
	(double *) argv[5], (IDL_LONG *) argv[6], (IDL_LONG *) argv[7], (IDL_LONG *) argv[8],
    (double *) argv[9], (double *) argv[10], (double *) argv[11], (double *) argv[12], (double *) argv[13], (double *) argv[14],
    (IDL_LONG *) argv[15], (double *) argv[16], (IDL_LONG *) argv[17], (double *) argv[18], (IDL_LONG *) argv[19], (double *) argv[20],
    (IDL_LONG *) argv[21], (double *) argv[22], (double *) argv[23]);
}



//********** 3D rebinning with  ewid ***************//
 EXPORTED int rebin3d_nat_iw(IDL_LONG* ndat,double* x, double* y, double* z, double* idat,
    double* ewid, IDL_LONG *nx, IDL_LONG *ny, IDL_LONG *nz,
    double *xmin, double *xstep, double* ymin, double *ystep, double* zmin, double *zstep,
    IDL_LONG* num_x, double* tmp_x, IDL_LONG* num_y, double* tmp_y, IDL_LONG* num_z, double* tmp_z,
    IDL_LONG* num_i, double* tmp_i,  double* tmp_w)
{
    long i, ix, iy, iz;

    for (i = 0L; i < (*ndat); i++){
        ix = (long)((x[i] - (*xmin)) / (*xstep));
        iy = (long)((y[i] - (*ymin)) / (*ystep));
        iz = (long)((z[i] - (*zmin)) / (*zstep));
        if ((ix < 0) || (ix >= (*nx)) || (iy < 0) || (iy >= (*ny))|| (iz < 0) || (iz >= (*nz))) return 1;
        num_x[ix]++;
        num_y[iy]++;
        num_z[iz]++;
        tmp_x[ix] += x[i];
        tmp_y[iy] += y[i];
        tmp_z[iz] += z[i];
        tmp_i[ix + iy * (*nx) + iz * (*nx) * (*ny)] += idat[i];
        num_i[ix + iy * (*nx) + iz * (*nx) * (*ny)]++;
        tmp_w[ix + iy * (*nx) + iz * (*nx) * (*ny)] += ewid[i];
        }
    return 0;
}

  EXPORTED int rebin3d_iw(int argc, void* argv[])
{
    return rebin3d_nat_iw((IDL_LONG *) argv[0],(double *) argv[1], (double *) argv[2], (double *) argv[3], (double *) argv[4],
	(double *) argv[5], (IDL_LONG *) argv[6], (IDL_LONG *) argv[7], (IDL_LONG *) argv[8],
    (double *) argv[9], (double *) argv[10], (double *) argv[11], (double *) argv[12], (double *) argv[13], (double *) argv[14],
    (IDL_LONG *) argv[15], (double *) argv[16], (IDL_LONG *) argv[17], (double *) argv[18], (IDL_LONG *) argv[19], (double *) argv[20],
    (IDL_LONG *) argv[21], (double *) argv[22], (double *) argv[23]);
}




//********** 3D rebinning with  data only ***************//
 EXPORTED int rebin3d_nat_i(IDL_LONG* ndat,double* x, double* y, double* z, double* idat,
    IDL_LONG *nx, IDL_LONG *ny, IDL_LONG *nz,
    double *xmin, double *xstep, double* ymin, double *ystep, double* zmin, double *zstep,
    IDL_LONG* num_x, double* tmp_x, IDL_LONG* num_y, double* tmp_y, IDL_LONG* num_z, double* tmp_z,
    IDL_LONG* num_i, double* tmp_i)
{
    long i, ix, iy, iz;

    for (i = 0L; i < (*ndat); i++){
        ix = (long)((x[i] - (*xmin)) / (*xstep));
        iy = (long)((y[i] - (*ymin)) / (*ystep));
        iz = (long)((z[i] - (*zmin)) / (*zstep));
        if ((ix < 0) || (ix >= (*nx)) || (iy < 0) || (iy >= (*ny))|| (iz < 0) || (iz >= (*nz))) return 1;
        num_x[ix]++;
        num_y[iy]++;
        num_z[iz]++;
        tmp_x[ix] += x[i];
        tmp_y[iy] += y[i];
        tmp_z[iz] += z[i];
        tmp_i[ix + iy * (*nx) + iz * (*nx) * (*ny)] += idat[i];
        num_i[ix + iy * (*nx) + iz * (*nx) * (*ny)]++;
        }
    return 0;
}

  EXPORTED int rebin3d_i(int argc, void* argv[])
{
    return rebin3d_nat_i((IDL_LONG *) argv[0],(double *) argv[1], (double *) argv[2], (double *) argv[3], (double *) argv[4],
	(IDL_LONG *) argv[5], (IDL_LONG *) argv[6], (IDL_LONG *) argv[7],
    (double *) argv[8], (double *) argv[9], (double *) argv[10], (double *) argv[11], (double *) argv[12], (double *) argv[13],
    (IDL_LONG *) argv[14], (double *) argv[15], (IDL_LONG *) argv[16], (double *) argv[17], (IDL_LONG *) argv[18], (double *) argv[19],
    (IDL_LONG *) argv[20], (double *) argv[21]);
}

