// This file mainly due to Kevin McGown, with modifications by Michael Rubinstein

#ifndef Lexplicit_formula_H
#define Lexplicit_formula_H

inline Complex xxx_phi(Double A, Double x_0, Complex x); // the phi in the explicit formula
inline Complex xxx_phi_hat(Double A, Double x_0, Complex x); //its fourier transform

/***************************************************************************************************/

inline Complex xxx_phi(Double A, Double x_0, Complex x)
{
  return exp(-A*(x-x_0)*(x-x_0));
}

inline Complex xxx_phi_hat(Double A, Double x_0, Complex x)
{
  return sqrt(Pi/A) * exp(-2*Pi*I*x_0*x - Pi*Pi*x*x/A);
}

/***************************************************************************************************/

template <class ttype>
int L_function <ttype>::
dirichlet_coeffs_log_diff(int num_coeffs, Complex *c)
{

  Complex b[num_coeffs+1];
  int j, n, d1, ind;
  Complex total, total2, temp;

  if (what_type_L != 1 && what_type_L != -1
    && num_coeffs > number_of_dirichlet_coefficients)
  {
      cout << "Don't have enough Dirichlet coefficients." << endl;
      return 1;
  }
  b[1] = 1;

  if(my_verbose!=0) cout << "Computing " << num_coeffs << " Dirichlet coefficients of the logarithmic derivative" << endl;
  //XXXXXXXX this should be computed just once, not each time test is called

  for (n=2;n<=num_coeffs;n++)
  {
    total = 0;
    total2 = 0;
    for (j=1;j<=n/2;j++)
      if (n % j == 0)
      {
        d1 = n/j;
        if (what_type_L == -1)
          temp = b[j];
        else if (what_type_L == 1)
        {
          ind = d1 % period;
          if (ind == 0)
            ind = period;
          temp = dirichlet_coefficient[ind]*b[j];
        }
        else
          temp = dirichlet_coefficient[d1]*b[j];
        total -= temp;
        total2 += temp*LOG(d1);
      }
    b[n] = total;
    c[n] = total2;
    if(my_verbose>5) cout << "c[" << n << "] = " << c[n] << endl;
  }

  return 0;
}

/************************************************************************************************/

template <class ttype>
int L_function <ttype>::
test_explicit_formula(Double A, Double x_0, Double *zero_table, int number_zeros, Complex *c, int num_coeffs)
{
  Double t, t_begin, t_end, t_step, u;
  Double D;
  Double total;
  Double term1, term2, term3;
  int p, n, x, j;
  Double temp;
  Double LHS, RHS;
  //Complex *c;
  //int num_coeffs;
  int flag;

  //num_coeffs = 150; //XXXXXXXXXX should depend on test required
  //c = new Complex[num_coeffs+1]; //XXXXXXX move to L.h
  //dirichlet_coeffs_log_diff(num_coeffs, c);

  //compute the possible contribution from poles

  term1 = 0;
  for (j=1;j<=number_of_poles;j++)
    term1 += real(xxx_phi(A, x_0, (pole[j]-0.5)/I));

  // compute the contribution from the Gamma factors (integral of the log diff)

  t_step = 0.02;
  D = ceil(sqrt(DIGITS*log(10.0)/A)/t_step) * t_step;
  t_begin = x_0 - D;
  t_end = x_0 + D;
  total = 0;

  for (t=t_begin;t<=t_end;t=t+t_step)
  {
    temp = 0;
    for (j=1;j<=this->a;j++)
    {
      temp +=  2*real(log_GAMMA(gamma[j]/2 + I*t*gamma[j]+lambda[j], 1)*gamma[j]); //1 here calls the logarithmic derivative
      //temp +=  log_GAMMA(gamma[j]/2 - I*t*gamma[j]+conj(lambda[j]), 1)*gamma[j];
    }
    total = total + real(xxx_phi(A, x_0, t)) * temp;
    //cout << t << " total " << total << endl;
  }

  term2 = t_step*total + 2*log(Q)*sqrt(Pi/A);
  term2 = 1/(2*Pi) * term2;

  //compute the contribution from the Dirichlet coefficients

  x = num_coeffs;
  //extend_prime_table(x);

  j = 0;
  p = get_prime(j);
  term3 = 0;

  while (p <= x)
  {
    n = p;
    while (n <= x)
    {
      temp = 2*real(c[n]*xxx_phi_hat(A, x_0, LOG(n)/(2*Pi)));// + conj(c[n])*xxx_phi_hat(A, x_0, -LOG(n)/(2*Pi)); 
      term3 += two_inverse_sqrt(n)*temp;
      n = n * p;
      //cout << n << "term3 " << term3 << endl;
    }
    j = j + 1;
    p = get_prime(j);
  }
  term3 = 1/(4*Pi) * term3;

  /*** COMPUTE RHS ***/

  RHS = term1 + term2 - term3;

  /*** COMPUTE LHS ***/

  LHS = 0;
  //we will want to truncate this automatically
  for (j=0;j<=number_zeros-1;j++)
  {

    u=zero_table[j]-x_0;
    u=u*u*A;
    if(u<2.3*DIGITS*2) LHS += exp(-u);
    //LHS += exp(-A*(zero_table[j]-x_0)*(zero_table[j]-x_0));
  }

  /*** Display Results ***/

  //if (my_verbose > 3)
  if (my_verbose==0)
  {
    cout << endl << endl;
    cout << "*** Testing Explicit Formula for L ***" << endl;
    cout << "A = " << A << endl;
    cout << "x_0 = " << x_0 << endl;
    cout << "D = " << D << endl;
    cout << "TERM 1:  " << term1 << endl;
    cout << "TERM 2:  " << term2 << endl;
    cout << "TERM 3:  " << term3 << endl;
    cout << "RHS:  " << RHS << endl;
    cout << "LHS:  " << LHS << endl;
    cout << "LHS - RHS:  " << LHS-RHS << endl;
    cout << "CUTOFF:  " << pow(10.0, -DIGITS/3) << endl;
  }

  //cout << "A = " << A << ", x_0 = " << x_0 << ", ";
  cout << " x_0=" << x_0 << ",";
  cout << "LHS = " << LHS << ", RHS = " << RHS << ", DIFF = " << abs((LHS - RHS)) << ", ";

  // I arbitrarily chose DIGITS/3.
  if (abs((LHS - RHS)) < pow(10.0,-DIGITS/3))
  {
    flag = 0;
    //cout << "PASS." << endl;
  }
  else
  {
    flag = 1;
    //cout << "FAIL!" << endl;
  }

  return flag;
}

#endif
