/* Copyright (C) 2001-2003, CompHEP Collaboration
 *-------------------------------------------------
 * $Id: events.c,v 1.10 2003/11/08 19:46:05 kryukov Exp $
 *
 * $Log: events.c,v $
 * Revision 1.10  2003/11/08 19:46:05  kryukov
 * To bring into according the usage of messanykey and warnanykey functions.
 *
*/
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#include "chep_crt/include/chep_crt.h"
#include "service2/include/files.h"
#include "service2/include/drandXX.h"
#include "out_ext.h"

#include "4_vector.h"
#include "const.h"
#include "cut.h"
#include "subproc.h"
#include "alphas2.h"
#include "strfun.h"
#include "vegas.h"
#include "runVegas.h"
#include "kfcodes.h"
#include "tag_reader.h"
#include "tag_parser.h"
#include "tag_writer.h"
#include "fill_tags.h"
#include "events.h"


static FILE *events_;
static int *cChains;
static int nC;
static int cBasisPower;


static void 
writeEvent (long cCub, int n, char *rand_state)
{
  int i, k, icc;
  double f;

  if (cBasisPower)
    {
      double sum = 0;
      for (i = 0; i < cBasisPower; i++)
	sum += fabs (color_weights[i]);
      sum *= drandXX ();
      for (i = 0; i < cBasisPower; i++)
	{
	  sum -= fabs (color_weights[i]);
	  if (sum <= 0)
	    break;
	}
      if (i == cBasisPower)
	i--;
      if (color_weights[i] < 0)
	n *= -1;
      icc = i;
    }

  f = calcCutFactor ();
  if (!f)
    {
      fprintf (stderr, "Error : generator have written an event \n");
      fprintf (stderr, "        which does not pass cuts.\n");
      printDetailsOfCutFactor ();
    }

  for (k = 0; k < n; k++)
    {
      double XX, YY;
      double phi_rnd = 2 * M_PI * drandXX ();
      for (i = nin_; i < nout_ + nin_; i++)
	{
	  XX = pvect[4 * i + 1];
	  YY = pvect[4 * i + 2];
	  pvect[4 * i + 1] = XX * cos (phi_rnd) - YY * sin (phi_rnd);
	  pvect[4 * i + 2] = XX * sin (phi_rnd) + YY * cos (phi_rnd);
	}
      fprintf (events_, "%2d:", 1);
      if (nin_ == 2)
	fprintf (events_, "%17.10E:%17.10E", pvect[3], pvect[7]);
      for (i = 0; i < nout_; i++)
	fprintf (events_, ":%17.10E:%17.10E:%17.10E", pvect[4 * (i + nin_) + 1], pvect[4 * (i + nin_) + 2], pvect[4 * (i + nin_) + 3]);
      fprintf (events_, ":%10.3E:", scale_ ());
      if (cBasisPower)
	{
	  int j;
	  for (j = 0; j < nC; j++)
	    fprintf (events_, "(%d %d)", cChains[2 * nC * icc + 2 * j], cChains[2 * nC * icc + 2 * j + 1]);
	}
      fprintf (events_, ":\n");
    }
}

static void
old_writeEvent (long cCub, int n, char *rand_state)
{
  int i, k;
  int icc;

  if (cBasisPower)
    {
      double sum = 0;
      for (i = 0; i < cBasisPower; i++)
	sum += fabs (color_weights[i]);
      sum *= drandXX ();
      for (i = 0; i < cBasisPower; i++)
	{
	  sum -= fabs (color_weights[i]);
	  if (sum <= 0)
	    break;
	}
      if (i == cBasisPower)
	i--;
      if (color_weights[i] < 0)
	n *= -1;
      icc = i;
    }

  for (k = 0; k < n; k++)
    {
      double XX, YY;
      double phi_rnd = 2 * M_PI * drandXX ();
      for (i = nin_; i < nout_ + nin_; i++)
	{
	  XX = pvect[4 * i + 1];
	  YY = pvect[4 * i + 2];
	  pvect[4 * i + 1] = XX * cos (phi_rnd) - YY * sin (phi_rnd);
	  pvect[4 * i + 2] = XX * sin (phi_rnd) + YY * cos (phi_rnd);
	}
      fprintf (events_, "%2d ", 1);
      if (nin_ == 2)
	fprintf (events_, "   %17.10E %17.10E", pvect[3], pvect[7]);
      for (i = nin_; i < nout_ + nin_; i++)
	fprintf (events_, " %17.10E %17.10E %17.10E", pvect[4 * i + 1],
		 pvect[4 * i + 2], pvect[4 * i + 3]);
      fprintf (events_, " %10.3E ", scale_ ());

      if (cBasisPower)
	{
	  int j;
	  fprintf (events_, "  ");
	  for (j = 0; j < nC; j++)
	    fprintf (events_, "(%d %d)", cChains[2 * nC * icc + 2 * j],
		     cChains[2 * nC * icc + 2 * j + 1]);
	}

      fprintf (events_, "\n");
    }
  }

static float *fmax = NULL;
static int killMaxInfo = 1;
static long n_cube = 1000;


int 
saveEventMax (FILE * f)
{
  long l;

  fprintf (f, "nCub=%d \n", (int) n_cube);
  if (fmax)
    {
      fprintf (f, "Max:\n");
      for (l = 0; l < n_cube; l++)
	fprintf (f, "%.1E\n", fmax[l]);
    }
  else
    fprintf (f, "!Max\n");
  return 0;
}


int 
readEventMax (FILE * f)
{
  long l;
  char buff[10];

  fscanf (f, "nCub=%ld\n", &n_cube);
  fscanf (f, "%s", buff);
  if (strcmp (buff, "Max:") == 0)
    {
      fmax = malloc (n_cube * sizeof (float));
      for (l = 0; l < n_cube; l++)
	fscanf (f, "%f", fmax + l);
      killMaxInfo = 0;
    }
  else
    {
      if (fmax)
	free (fmax);
      fmax = NULL;
    }
  return 0;
}


static long nPoints = 500;
static long nEvents = 10000;
static double max = 2;
static double milk = 0.2;


int 
saveEventSettings (FILE * f)
{
  fprintf (f, "%d %d %f %f %d", (int) nPoints, simplexOn, milk, max, (int) nEvents);
  return 0;
}

static void
old_write_event_cap (void)
{
  int i;
  double cross_section;
  char version1[36] = "CompHEP version 4.2p1    ";

  fprintf (events_, "#%s\n", version1);

  fprintf (events_, "#PROCESS  ");
  for (i = 1; i <= nin_ + nout_; i++)
    {
      char buff[10];
      pinf_ (proces_1.nsub, i, buff, NULL);
      fprintf (events_, " %-4.4s", buff);
      if (i == nin_)
	fprintf (events_, "->");
    }
  fprintf (events_, "\n");

  fprintf (events_, "#Initial_state\n");

  /* w_in__(events_); */
  {
    double sqrt_S;
    vinf_ (0, NULL, &sqrt_S);
    fprintf (events_, "  SQRT(S) %E\n  Rapidity(c.m.s) %E\n", sqrt_S,
	     rapidity);
    wrt_sf__ (events_);
  }


  fprintf (events_, "#MASSES ");
  for (i = 1; i <= nin_ + nout_; i++)
    {
      double q;
      pinf_ (proces_1.nsub, i, NULL, &q);
      fprintf (events_, " %.10E", q);
    }
  fprintf (events_, "\n");

  if (integral.n_it)
    {
      cross_section = integral.s1 / integral.s0;
      fprintf (events_, "#Cross_section(Width) %E\n", cross_section);
    }
  else
    fprintf (events_, "#Cross_section(Width) Unknown\n");

  fprintf (events_, "#Number_of_events %10d\n", 0);
  fprintf (events_,
	   "#----------------------------------------------------------\n");
  fprintf (events_, "#Number_of_subprocesses = 1\n");

  if (integral.n_it)
    fprintf (events_, "#Total_cross_section_(pb) = %E\n", cross_section);
  else
    fprintf (events_, "#Cross_section(Width) Unknown\n");

  fprintf (events_, "%s = %-31d\n", "#Events_mixed_and_randomized", 0);
  fprintf (events_,
	   "#Nproc ================== Events ==========================\n");

}


int 
readEventSettings (FILE * f)
{
  fscanf (f, "%ld %d %lf %lf %ld", &nPoints, &simplexOn, &milk, &max, &nEvents);
  return 0;
}


void 
generateEvents (vegasGrid * vegPtr, int init, double (*func) (double *, double), char *fname, FILE * iprt)
{
  int mode = 1;
  int broken;
  void *pscr = NULL;
  void *pscr_ = NULL;
  char chck;
  midstr mess;
  double max = 2;
  double eff0;

  if (init)
    {
      if (fmax)
	free (fmax);
      fmax = NULL;
    }

ret:
  if (!fmax)
    for (mode = 1; mode != 4;)
      {
	char strmen[] = "\030"
	" sub-cubes = N1         "
	" calls     = N2         "
	" simplex search    |ONN "
	" Start search of maxima ";
	improveStr (strmen, "N1", "%d", n_cube);
	improveStr (strmen, "N2", "%d", nPoints);
	if (simplexOn)
	  improveStr (strmen, "|ONN", "|ON ");
	else
	  improveStr (strmen, "|ONN", "|OFF");
	menu1 (54, 11, "Preparing of generator", strmen, "n_prep_gen_*", &pscr_, &mode);
	switch (mode)
	  {
	  case 0:
	    return;
	  case 1:
	    correctLong (50, 15, "Number of sub-cubes:", &n_cube, 1);
	    generateVegasCubs (vegPtr, &n_cube);
	    break;
	  case 2:
	    correctLong (50, 15, "Calls for each sub-cube:", &nPoints, 1);
	    break;
	  case 3:
	    simplexOn = !simplexOn;
	    break;
	  case 4:
	    {
	      if (n_cube < 1)
		n_cube = 1;
	      fmax = malloc (n_cube * sizeof (float));
	      {
		float *fmax_ = malloc (n_cube * sizeof (float));
		float *sum = malloc (n_cube * sizeof (float));
		if (fmax && fmax_ && sum)
		  {
		    free (sum);
		    free (fmax_);
		    if (vegas_max (vegPtr, n_cube, nPoints, func, milk, &eff0, fmax) == 0)
		      {
			sprintf (mess, "Expected efficiency %f", eff0);
			messanykey (25, 15, mess);
			put_text (&pscr_);
		      }
		    else
		      mode = 1;
		  }
		else
		  {
		    if (sum)
		      free (sum);
		    if (fmax_)
		      free (fmax_);
		    if (fmax)
		      free (fmax);
		    fmax = NULL;
		    warnanykey (25, 15, "Not enough memory.\nDecrease the number of sub-cubes");
		    mode = 1;
		  }
	      }
	    }
	    break;
	  }
      }
  killMaxInfo = 0;
  for (mode = 1;;)
    {
      char strmen[] = "\030"
	"Number of events=N1     "
	" MAX*N2                 "
	" Generator (new format) "
	" Generator (old format) "
	" New search of maxima   ";
      improveStr (strmen, "N1", "%d", nEvents);
      improveStr (strmen, "N2", "%.2G", max);
      menu1 (54, 10, "", strmen, "n_gen_*", &pscr, &mode);
      switch (mode)
	{
	case 0:
	  return;
	case 1:
	  correctLong (50, 15, "", &nEvents, 1);
	  break;
	case 2:
	  correctDouble (50, 15, "Increase max in ", &max, 1);
	  break;
	case 3:
	  {
	    int broken;
	    long fileCur, fileEnd;
	    double eff, rmax, mult, neg;
	    tags *cap_info;

	    events_ = fopen (fname, "a+");
	    if (ftell (events_) == 0)
	      {
		rewind (events_);
		cap_info = init_cap_info ();
		cap_writer (events_, cap_info);
	      }
	    else
	      {
		rewind (events_);
		chck = fgetc (events_);
		chck = fgetc (events_);
		if ('#' == chck)
		  {
		    fseek (events_, 0L, SEEK_END);
		  }
		else
		  {
		    sprintf (mess,
			     "---------------\n Events in the file %s are not stored in the new format",
			     fname);
		    messanykey (5, 15, mess);
		    fclose (events_);
		    break;
		  }
		cap_info = init_cap (1);
		cup_reader (events_, cap_info);
	      }
	    fileCur = ftell (events_);
	    fseek(events_, 0L, SEEK_END);
	    fileEnd = ftell (events_);
	    fseek(events_, fileCur, SEEK_SET);

	    cStrings (proces_1.nsub, &nC, &cBasisPower, &cChains);
	    if (cBasisPower)
	      color_weights = malloc (sizeof (double) * cBasisPower);
	    broken = vegas_events (vegPtr, n_cube, nEvents, max, func, writeEvent, fmax, &eff, &rmax, &mult, &neg);
	    fclose (events_);
	    sprintf (mess, "Statistic\n efficiency: %.1E\nReached max: %.1E\n"
		     "Mult. events: %.1E \nNeg.events: %.1E \n",
		     eff, rmax, mult, neg);
	    if (broken)
	      {
		strcat (mess, "---------------\n Events are not saved");
		messanykey (25, 15, mess);
		truncate (fname, fileEnd);
	      }
	    else
	      {
		int l = strlen (mess);
		strcat (mess, "---------------\n Accept events? ");
		if (mess_y_n (25, 15, mess))
		  {
		    double cs, er;
		    integral.old = 1;
		    mess[l] = 0;
		    if (integral.n_it)
		      {
			double a, b;
			cs = integral.s1 / integral.s0;
			a = sqrt (integral.s0);
			b = fabs (integral.s1);
			er = a / b;
		      }

		    change_cap (cap_info, nEvents, mult, rmax, cs, er);
		    events_ = fopen (fname, "r+");
		    cap_writer (events_, cap_info);
		    fclose (events_);
		    full_free (cap_info);
		    fprintf (iprt, " %i events are stored in '%s'\n", (int) nEvents, fname);
		    fprintf (iprt, "%s\n", mess);
		    fflush (iprt);
		  }
		else
		  truncate (fname, fileEnd);
	      }
	    if (cBasisPower)
	      {
		free (color_weights);
		color_weights = NULL;
	      }
	  }
	  break;
	case 4:
	  {
	    long nGenerated = 0;
	    long fileEnd;
	    double eff, rmax, mult, neg;

	    char xfmt[20], NumEvents[100];
	    int ilen;

	    events_ = fopen (fname, "a+");
	    if (ftell (events_) == 0)
	      {
		old_write_event_cap ();
	      }
	    else
	      {
		rewind (events_);
		chck = fgetc (events_);
		chck = fgetc (events_);
		if ('C' == chck)
		  {
		    fseek (events_, 0L, SEEK_END);
		  }
		else
		  {
		    sprintf (mess,
			     "---------------\n Events in the file %s are not stored in the new format",
			     fname);
		    messanykey (5, 15, mess);
		    fclose (events_);
		    break;
		  }
	      }

	    fileEnd = ftell (events_);

	    cStrings (proces_1.nsub, &nC, &cBasisPower, &cChains);
	    if (cBasisPower)
	      color_weights = malloc (sizeof (double) * cBasisPower);

	    broken =
	      vegas_events (vegPtr, n_cube, nEvents, max, func,
			    old_writeEvent, fmax, &eff, &rmax, &mult, &neg);
	    fclose (events_);

	    sprintf (mess,
		     "Statistic\n efficiency: %.1E\nReached max: %.1E\n"
		     "Mult. events: %.1E \nNeg.events: %.1E \n", eff,
		     rmax, mult, neg);

	    if (broken)
	      {
		strcat (mess, "---------------\n Events are not saved");
		messanykey (25, 15, mess);
		truncate (fname, fileEnd);
	      }
	    else
	      {
		int l = strlen (mess);
		strcat (mess, "---------------\n Accept events? ");
		if (mess_y_n (25, 15, mess))
		  {
		    long nEvPos = 0;
		    long nEvPos_2 = 0;
		    integral.old = 1;
		    mess[l] = 0;
		    events_ = fopen (fname, "r+");
		    while (nEvPos_2 == 0)
		      {
			char ch;
			char word[100];
			do
			  fscanf (events_, "%c", &ch);
			while (ch != '#');
			fscanf (events_, "%s", word);
			if (strcmp (word, "Number_of_events") == 0)
			  nEvPos = ftell (events_);
			if (strcmp (word, "Events_mixed_and_randomized") == 0)
			  nEvPos_2 = ftell (events_);
		      }
		    fseek (events_, nEvPos, SEEK_SET);
		    fscanf (events_, "%ld", &nGenerated);
		    nGenerated += nEvents;

		    fseek (events_, nEvPos, SEEK_SET);
		    fprintf (events_, " %10ld", nGenerated);

		    sprintf (NumEvents, "%ld", nGenerated);
		    ilen = 32 - strlen (NumEvents);
		    sprintf (xfmt, "%s%d%s", " = %-", ilen, "ld");

		    fseek (events_, nEvPos_2, SEEK_SET);
		    fprintf (events_, xfmt, nGenerated);

		    fclose (events_);

		    fprintf (iprt, " %ld events are stored in '%s'\n",
			     nEvents, fname);
		    fprintf (iprt, "%s\n", mess);
		    fflush (iprt);
		  }
		else
		  truncate (fname, fileEnd);
	      }
	    if (cBasisPower)
	      {
		free (color_weights);
		color_weights = NULL;
	      }
	  }
	  break;
	case 5:
	  {
	    free (fmax);
	    fmax = NULL;
	    put_text (&pscr);
	    goto ret;
	  }
	  break;
	}
    }
}
