/*-----------------
* Copyright (C) 2001-2003, CompHEP Collaboration
*------------------------------------------------------
* $Id: mk_tab.c,v 1.7 2003/06/25 18:46:42 kryukov Exp $
*
* $Log: mk_tab.c,v $
* Revision 1.7  2003/06/25 18:46:42  kryukov
* *** empty log message ***
*
* Revision 1.6  2003/06/17 11:13:59  sherstnv
* mk_tab now is re-linked by user in $WDIR/usr
* It is necessary for replace U-variables if user develops own ones.
*
* Revision 1.5  2003/05/01 12:19:29  sherstnv
* Pri ne otsutstvii file s imenem zadannom v kom.stroke
* vivoditsya kratkiy help.
*
* Revision 1.4  2003/04/22 09:01:22  kryukov
* Apply indent to improve readability of files
*
* Revision 1.3  2003/04/20 17:55:03  kryukov
* Clean up warnings during make
*
*/
#include <stdio.h>
#include <string.h>
#include "num/include/tag_reader.h"
#include "num/include/tag_parser.h"
#include "num/include/event_reader.h"
#include "num/include/4_vector.h"
#include "num/include/phys_val.h"
#include "service2/include/paragraphs.h"
#include "symb/include/model.h"
#include "e_tools.h"

#define const
#include "out_ext.h"
#undef const

static void
wrongParam (int N)
{
  if (N)
    fprintf (stderr, "Wrong parameter %d\n", N);
  else
    fprintf (stderr, "Wrong number of parameters \n");
  fprintf (stderr, "Parameters:\n"
           " 1- file name,\n"
           " 2- name of variable,\n"
           " 3- minimum limit,\n"
           " 4- maximum limit,\n" " 5- number of bins(<=300).\n");
}


static void
ShowHelp (int N)
{
  if (N == 0)
    {
      fprintf (stdout, "Short help:\n"
"  Using: mk_tab {name_of_file_with_events} Var Param_min Param_max Nbins\n\n"    
"The program mk_tab constructs a histogram for variable \"Var\" in the limits\n"
"from \"Param_min\" to \"Param_max\". This histogram will have \"Nbins\" bins\n");
    }
  else
    {
      fprintf (stdout, "Long help:\n"
"Using: mk_tab {name_of_file_with_events} Var Param_min Param_max Nbins\n\n"
"The program mk_tab constructs a histogram for variable \"Var\" in the limits\n"
"from \"Param_min\" to \"Param_max\". This histogram will have \"Nbins\" bins"
"Bla-bla-bla...\n");
    }
}


static int
keep_histo (double *hist, double *dhist, char key, char *plist, double minX,
            double maxX, int nbin)
{
  int i;
  char xname[200];
  char yname[200];
  char xunits[100];

  for (i = 0; i < nin_ + nout_; i++)
    {
      if (i == nin_)
        fprintf (stdout, " ->");
      else if (i)
        fprintf (stdout, ",");
      pinf_ (1, i + 1, xname, NULL);
      fprintf (stdout, " %s", xname);
    }

  if (nin_ == 2)
    {
      sprintf (yname, "Diff. cross section [pb");
    }
  else
    {
      sprintf (yname, "Diff. width [GeV");
    }
  fprintf (stdout, "\n");

  xName (key, plist, xname, xunits);
  fprintf (stdout, "x-axis: \"%s\"  from %f to %f N_bins= %d\n", xname, minX,
           maxX, nbin);
  fprintf (stdout, "%s", yname);
  if (xunits[0])
    fprintf (stdout, "/%s", xunits);
  fprintf (stdout, "]");

  for (i = 0; i < nbin; i++)
    {
      fprintf (stdout, "\n%-12E +/-  %-12E", hist[i], dhist[i]);
    }
  fprintf (stdout, "\n");
  return 1;
}


static double CS = 0;
static int
readCS (FILE * flow)
{
  fscanf (flow, "%lf", &CS);
  return 0;
}

static double totCS = 0;
static int
readTotCS (FILE * flow)
{
  char buff[STRSIZE];

  fgets (buff, 1024, flow);
  sscanf (buff, "= %lf", &totCS);
  return 0;
}

static long nEvents = 0;
static int
readNEvents (FILE * flow)
{
  fscanf (flow, "%ld", &nEvents);
  return 0;
}


int
main (int argc, char **argv)
{
  int i, j, k, n;
  int nbin;
  int Nproc;
  int format;
  int npr;
  int in;
  int out;
  int max_format = 0;
  long Npoints;
  int *Nevents;
  int *Npartons;
  int **pnum;
  int NF;

  char key;
  char plist[MAXNP];
  char restfr[10]={0};
  char buff[STRSIZE];
  char buf[STRSIZE];
  midstr name_proc;

  double minX, maxX;
  double weight, coef;
  double *CSec;
  double *hist;
  double *dhist;
  double **mass;

  string_comnd com;
  tags *head;
  FILE *f;

  if (strcmp (argv[1], "") == 0 || strcmp (argv[1], "-h") == 0)
    {
      ShowHelp (0);
      return 1;
    }
  if ((strcmp (argv[1], "-help") == 0) || (strcmp (argv[1], "--help") == 0))
    {
      ShowHelp (1);
      return 1;
    };

  f = fopen (argv[1], "r");
  if (!f)
    {
      fprintf (stderr, "***Error! File not found: %s\n", argv[1]);
      return 2;
    }

/* Check number of input parameters and their sence */
  if (argc != 6)
    {
      wrongParam (0);
      return 1;
    }
  if (sscanf (argv[3], "%lf", &minX) != 1)
    {
      wrongParam (2);
      return 1;
    }
  if (sscanf (argv[4], "%lf", &maxX) != 1 || minX >= maxX)
    {
      wrongParam (3);
      return 1;
    }
  if (sscanf (argv[5], "%d", &nbin) != 1 || nbin <= 0)
    {
      wrongParam (4);
      return 1;
    }

  hist = malloc (nbin * sizeof (double));
  dhist = malloc (nbin * sizeof (double));

  for (i = 0; i < nbin; i++)
    {
      hist[i] = 0;
      dhist[i] = 0;
    }
  Npoints = 0;

  NF = CheckFormat (f);

  if (NF == 2)
    {
/*---  New XML-style fromat ---*/
      head = init_cap (1);
      cup_reader (f, head);
      Nproc = number_proc (head);

      Npartons = malloc (Nproc * sizeof (int));
      Nevents = malloc (Nproc * sizeof (int));
      pnum = malloc (Nproc * sizeof (int *));
      CSec = malloc (Nproc * sizeof (double));
      mass = malloc (Nproc * sizeof (double *));

      for (i = 0; i < Nproc; i++)
        {
          pnum[i] = malloc (100 * sizeof (int));
          sprintf (com.value, "%i", i + 1);

/*---  Get number of partons, cross section and parton's names from process tag  */
          strcpy (com.name, "ID");
          n = get_tag_with_exactcom (0, head, "process", &com);
          if (n == -1)
            {
              fprintf (stderr,
                       "***Error! The process tag for the %i-th subprocess has been lost.\n",
                       i + 1);
              return -1;
            }
          Npartons[i] = get_ival (0, "Nparton", head->tag[n]);
          CSec[i] = get_fval (0, "CrosSec", head->tag[n]);
          strcpy (name_proc, get_cval (0, "name", head->tag[n]));
          getNames (name_proc);

/*---  Get number of events from the n_event tag  */
          strcpy (com.name, "IDprocess");
          n = get_tag_with_exactcom (0, head, "n_event", &com);
          if (n == -1)
            {
              Nevents[i] = get_ival (0, "N", head->tag[n]);
              fprintf (stderr,
                       "***Error! The n_event tag for the %i-th subprocess has been lost.\n",
                       i + 1);
              return -1;
            }
          Nevents[i] = get_ival (0, "N", head->tag[n]);

/*---  Set format numbers for i-th subprocess  */
          sprintf (com.value, "%i", i + 1);
          format = get_tag_with_exactcom (0, head, "format", &com);
          if (format == -1)
            {
              fprintf (stderr,
                       "***Error! The format tag for the %i-th subprocess has been lost.\n",
                       i + 1);
              exit (1);
            }

          if (head->tag[format]->tagsize > max_format)
            {
              max_format = head->tag[format]->tagsize;
            }

          strcpy (com.name, "p1.3");
          n = tag_contain_com (&com, head->tag[format]);
          if (n < 1)
            {
              fprintf (stderr,
                       "***Error in format tag for the %i-th subprocess.\n",
                       i + 1);
              return -1;
            }
          pnum[i][3] = n - 2;
          strcpy (com.name, "p2.3");

          n = tag_contain_com (&com, head->tag[format]);
          if (n < 1)
            {
              fprintf (stderr,
                       "***Error in format tag for the %i-th subprocess.\n",
                       i + 1);
              return -1;
            }
          pnum[i][7] = n - 2;

          for (k = 2; k < Npartons[i]; k++)
            {
              for (j = 0; j < 3; j++)
                {
                  sprintf (com.name, "p%i.%i", k + 1, j + 1);
                  n = tag_contain_com (&com, head->tag[format]);
                  if (n > 1)
                    pnum[i][4 * k + j + 1] = n - 2;
                  else
                    pnum[i][4 * k + j + 1] = 0;
                }
            }

/*---  Get partons masses from partons tags  */
          strcpy (com.name, "IDprocess");
          sprintf (com.value, "%i", i + 1);
          n = -1;
          mass[i] = malloc (Npartons[i] * sizeof (double));
          for (j = 0; j < Npartons[i]; j++)
            {
              n = get_tag_with_exactcom (n + 1, head, "parton", &com);
              if (n == -1)
                {
                  fprintf (stderr,
                           "***Error! The number of parton tags are not equaled to the number\n"
                           "          of parton in process tag for the %i-th subprocess.\n",
                           i + 1);
                  return -1;
                }
              in = get_ival (0, "in", head->tag[n]);
              out = get_ival (0, "out", head->tag[n]);
              if (in)
                mass[i][in - 1] = get_fval (0, "mass", head->tag[n]);
              if (out)
                mass[i][out - 1] = get_fval (0, "mass", head->tag[n]);
            }
        }

      for (i = 0; i < nbin; i++)
        {
          hist[i] = 0;
          dhist[i] = 0;
        }

      nin_ = 2;
      nout_ = Npartons[0] - 2;
      if (!checkPhysVal (argv[2], &key, plist))
        {
          wrongParam (2);
          return 1;
        }
      {
        char **eventword = malloc (max_format * sizeof (char *));
        int debug = 0;
        int err;

        for (i = 0; i < 4 * nin_; i++)
          {
            pvect[i] = 0;
          }

        fgets (buf, 1000, f);
        while (fgets (buf, 1000, f))
          {
            sscanf (buf, "%i:%[^\n]", &npr, buff);
            npr--;
            err = event_parser (buff, eventword);
            if (err)
              {
                fprintf (stderr, "Error in event %i\n. Exit!", debug);
                return -1;
              }
            pvect[3] = atof (eventword[pnum[npr][3]]);
            pvect[7] = atof (eventword[pnum[npr][7]]);
            for (i = 2; i < Npartons[npr]; i++)
              for (j = 0; j < 3; j++)
                pvect[4 * i + j + 1] =
                  atof (eventword[pnum[npr][4 * i + j + 1]]);
            for (i = 0; i < nin_ + nout_; i++)
              pvect[4 * i] = ENERGY (mass[npr][i], pvect + 4 * i + 1);

            weight = CSec[npr] / Nevents[npr];
            i = nbin * (calcPhysVal (key, plist, restfr) - minX) / (maxX - minX);
            if (i >= 0 && i < nbin)
              {
                hist[i] += weight;
                dhist[i] += weight * weight;
                Npoints++;
              }
            debug++;
          }
        free (eventword);
      }
      free (Npartons);
      free (Nevents);
      free (pnum);
      free (CSec);
      free (mass);
    }
  else if (3 == NF)
    {
/*---  Old CompHEP_41.10 fromat, but the file contains some subprocesses ---*/
      int ibin;
      int stop = 0;
      int Nproc;
      int *nnin;
      int *nnout;
      char bufff[MAXINOUT + 3][STRSIZE];

      rw_paragraph rd_array0[1] = {
        {"PEVLIB_v.1.0", skipHeadLine}
      };

      rw_paragraph rd_array1[7] = {
        {"CompHEP", NULL},
        {"PROCESS", old_getNames},
        {"Initial_state", NULL},
        {"MASSES", getMasses},
        {"Cross_section(Width)", NULL},
        {"Number_of_events", NULL},
        {"----------------------------------------------------------", skipHeadLine}
      };

      rw_paragraph rd_array2[4] = {
        {"Number_of_subprocesses", NULL},
        {"Total_cross_section_(pb)", readTotCS},
        {"Events_mixed_and_randomized", NULL},
        {"Nproc", skipHeadLine}
      };

/* Define the number of subprocesses in the file*/
      while ((NULL == fgets (buff, 1000, f)) || !stop)
        {
          stop = sscanf (buff, "#Number_of_subprocesses = %d", &Nproc);
        }
      if (Nproc < 1)
        {
          fprintf (stderr,
                   "Error! unknown number of subprocesses! Nproc = %i\n",
                   Nproc);
          exit (2);
        }
      rewind (f);

      mass = malloc (Nproc * sizeof (double *));
      nnin = malloc (Nproc * sizeof (int));
      nnout = malloc (Nproc * sizeof (int));
      for (i = 0; i < Nproc; i++)
        {
          mass[i] = malloc (MAXNP * sizeof (double));
        }

/* Read first tag -> PEVLIB version */
      readParagraphs (f, 1, rd_array0);

/* Read subprocess info: particle names and masses */
      for (j = 0; j < Nproc; j++)
        {
          readParagraphs (f, 7, rd_array1);
          nnin[j] = nin_;
          nnout[j] = nout_;
          for (i = 0; i < nin_ + nout_; i++)
            {
              pinf_ (1, i + 1, NULL, mass[j] + i);
            }
        }

/* Read process info: full cross section */
      readParagraphs (f, 4, rd_array2);

      if (!checkPhysVal (argv[2], &key, plist))
        {
          wrongParam (1);
          return 1;
        }

/* Read events */
      nEvents = 0;
      while (fgets (bufff[0], 2048, f))
        {
          sscanf (bufff[0], "%i%[^\n]", &npr, bufff[1]);
          if (npr < 1 || npr > Nproc)
            {
              fprintf (stderr,
                       "Error! subprocess number is of the limits: Nproc = %i, Nproc_MAX =%i \n",
                       npr, Nproc);
              exit (3);
            }
          for (i = 0; i < 4 * nnin[npr - 1]; i++)
            {
              pvect[i] = 0;
            }

          if (nnin[npr - 1] == 2)
            {
              sscanf (bufff[1], "    %lf %lf%[^a]", pvect + 3, pvect + 7,
                      bufff[2]);
            }

          for (i = nnin[npr - 1]; i < nnin[npr - 1] + nnout[npr - 1]; i++)
            {
              double *p = pvect + 4 * i;
              sscanf (bufff[i + 2 - nnin[npr - 1]], " %lf %lf %lf%[^a]",
                      p + 1, p + 2, p + 3, bufff[i + 3 - nnin[npr - 1]]);
            }

          for (i = 0; i < nnin[npr - 1] + nnout[npr - 1]; i++)
            {
              pvect[4 * i] = ENERGY (mass[npr - 1][i], pvect + 4 * i + 1);
            }

          ibin = nbin * (calcPhysVal (key, plist, restfr) - minX) / (maxX - minX);
          if (ibin >= 0 && ibin < nbin)
            {
              hist[ibin] += 1;
              dhist[ibin] += 1;
              Npoints++;
            }
          nEvents++;
        }

/* Rewighting */
      weight = totCS / nEvents;
      for (i = 0; i < nbin; i++)
        {
          hist[i] *= weight;
          dhist[i] *= weight * weight;
        }

      free (nnin);
      free (nnout);
      for (i = 0; i < Nproc; i++)
        free (mass[i]);
      free (mass);
    }
  else if (NF == 1)
    {
/*--- Old CompHEP_41.10 fromat ---*/
      double mass[MAXNP];

      rw_paragraph rd_array[11] = {
        {"CompHEP", NULL},
        {"PROCESS", old_getNames},
        {"Initial_state", NULL},
        {"MASSES", getMasses},
        {"Cross_section(Width)", readCS},
        {"Number_of_events", readNEvents},
        {"----------------------------------------------------------",
         skipLine},
        {"Number_of_subprocesses", skipLine},
        {"Total_cross_section_(pb)", skipLine},
        {"Events_mixed_and_randomized", skipLine},
        {"Nproc", skipHeadLine}
      };
      readParagraphs (f, 11, rd_array);

      for (i = 0; i < nin_ + nout_; i++)
        {
          pinf_ (1, i + 1, NULL, mass + i);
        }

      if (!checkPhysVal (argv[2], &key, plist))
        {
          wrongParam (1);
          return 1;
        }
      weight = CS / nEvents;
      while (fscanf (f, " %d", &npr) == 1)
        {
          for (i = 0; i < 4 * nin_; i++)
            {
              pvect[i] = 0;
            }
          if (nin_ == 2)
            {
              fscanf (f, "    %lf %lf", pvect + 3, pvect + 7);
            }
          for (i = nin_; i < nin_ + nout_; i++)
            {
              double *p = pvect + 4 * i;
              fscanf (f, " %lf %lf %lf", p + 1, p + 2, p + 3);
            }
          for (i = 0; i < nin_ + nout_; i++)
            {
              pvect[4 * i] = ENERGY (mass[i], pvect + 4 * i + 1);
            }
          i = nbin * (calcPhysVal (key, plist, restfr) - minX) / (maxX - minX);
          if (i >= 0 && i < nbin)
            {
              hist[i] += weight;
              dhist[i] += weight * weight;
              Npoints++;
            }
          fgets (buff, 1000, f);
        }
    }

  coef = nbin / (maxX - minX);


  for (i = 0; i < nbin; i++)
    {
      dhist[i] = coef * sqrt (dhist[i] - hist[i] * hist[i] / Npoints);
      hist[i] *= coef;
    }
  keep_histo (hist, dhist, key, plist, minX, maxX, nbin);
  fclose (f);
  free (hist);
  free (dhist);
  return 0;
}

