#ifdef _GSL

#include <gsl/gsl_integration.h>

#define GSLMAXSUBINTERVAL 1000

class MDFrame *__xrd_simframe;

double integrand(double x, double y) {
  double theta, lambda;
  Vector3 el, em, en, ex, ey, edk, dk;
  double xp, yp, zp, f, sum_real, sum_imag;
  int i;

  theta  = __xrd_simframe->input[4];
  lambda = __xrd_simframe->input[5];
  en.set(__xrd_simframe->input[6], __xrd_simframe->input[7], __xrd_simframe->input[8]);
  en/=en.norm();
  ex.set(1,0,0); ey.set(0,1,0); 
  em = cross(en, ex);
  if (em.norm()<1e-3) em = cross(en,ey);
  em/=em.norm();
  el = cross(em,en);

  xp = 2*x/(1+x*x+y*y);
  yp = 2*y/(1+x*x+y*y);
  zp = (1-x*x-y*y)/(1+x*x+y*y);

  edk = en*zp+el*xp+em*yp;
  dk = edk*((2*M_PI/lambda)*(2*sin(theta)));
  
  __xrd_simframe->SHtoR();
  sum_real = sum_imag = 0.0;
  for(i=0;i<__xrd_simframe->_NP;i++)
  {
     double dotprod = dot(__xrd_simframe->_R[i], dk);
     sum_real += cos(dotprod);
     sum_imag += sin(dotprod);
  }
  f = (sum_real*sum_real+sum_imag*sum_imag) * (2*M_PI*cos(theta)) * 4.0/SQR(1+x*x+y*y); 
  
  return f;
}

struct __func2d {
   double x1, x2;
   double y1, y2;
   double (*f) (double, double);
};

static  double __f2 (double y, void * params) {
    struct __func2d *myparams = (struct __func2d *) params;
    double x = myparams->x1;
    double (*myfunc)(double, double) = myparams->f;
    //printf("integrand(%g,%g) = %g\n",x,y,myfunc(x,y));

    return myfunc (x,y);
}

static  double __f1(double x, void * params) {
    gsl_integration_workspace * w 
      = gsl_integration_workspace_alloc (GSLMAXSUBINTERVAL);

    struct __func2d *inparams = (struct __func2d *) params;
    struct __func2d  outparams;
    outparams.x1 = x;
    outparams.x2 = x;
    outparams.f  = inparams->f;

    double result, error;

    gsl_function F;
    F.function = __f2;
    F.params   = &outparams;

    gsl_integration_qags (&F, inparams->y1, inparams->y2, 0, 1e-7, GSLMAXSUBINTERVAL,
                          w, &result, &error); 

    return result;
}

double dbl_integral( double (*f) (double x, double y), double x1, double x2, double y1, double y2,
                     double epsabs, double epsrel, double *abserr )
{
 
  struct __func2d myparams;
  double result, error;
 
  gsl_integration_workspace * w 
    = gsl_integration_workspace_alloc (GSLMAXSUBINTERVAL);
 
  myparams.y1 = y1;
  myparams.y2 = y2; 
  myparams.f  =  f;

  gsl_function F;
  F.function = &__f1;
  F.params = &myparams;

  gsl_integration_qags (&F, x1, x2, epsabs, epsrel, GSLMAXSUBINTERVAL, w, &result, &error); 

  return result;
}



void MDFrame::compute_XRD_intensity()
{
 /* compute spherically averaged XRD intensity I(2theta) 

    input specified in
      double input[MAXINPUTLEN]; 

    store results in
      double output_dat[MAXOUTPUTDATLEN]; 
  */

  double gamma1, gamma2, delta1, delta2;
  double error;

  gamma1 = input[0];
  gamma2 = input[1];
  delta1 = input[2];
  delta2 = input[3];
  __xrd_simframe = this;

  output_dat[0] = dbl_integral( integrand, gamma1, gamma2, delta1, delta2, 0, 1e-7, &error );

}

#endif //_GSL
