/*
* Copyright (C) 2002-2008, CompHEP Collaboration
* Author: Alexander Sherstnev 
* ------------------------------------------------------
* $Id$
*
* $Log$
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <string.h>

#include "service2/include/syst.h"

#include "tag_reader.h"
#include "tag_writer.h"
#include "tag_parser.h"
#include "fill.h"
#include "validity.h"
#include "structures.h"
#include "compare.h"
#include "mix_format2.h"

int mix_format2 (const int nf, const char target[], const char names[], const int lenth)
{
  int jf, t, tt, nx;
  int nSubtot;
  int nProc;
  int *shift;
  long i,l;
  long nRectot;
  long maxnRec;
  long num;
  long **pos;
  long fpos;
  long *pos0;
  long *nRec;
  long *real_nRec;
  long *nRecRest;
  double *ri, xrn;
  double sigmatot = 0.0;
  char *prtFileName;
  char buff[1024];
  char buff1[1024];
  char **map;
  char **filename;

  FILE** infile;
  FILE* outFile;
  FILE* prtFile;
  process_ theProcessUP;
  tags **tbase;
  proc_pos *proc_position;

/****************************************************************/
/*     initialize file names                                    */

  prtFileName = "Prt.PEV";

/****************************************************************/
/*  allocate the memory space for work dimensions */
  tbase    = malloc (nf * sizeof (tags *));
  pos0     = malloc (nf * sizeof (long));
  shift    = malloc (nf * sizeof (int));
  infile   = malloc (nf * sizeof(FILE*));
  filename = malloc (nf * sizeof(char*));

  for (i = 0; i < nf; ++i) {
    filename[i] = malloc ((lenth + 1) * sizeof(char));
    strncpy (filename[i], names + i * lenth, lenth);filename[i][lenth] = 0;
    trim(filename[i]);
  }

/****************************************************************/
/* open output files for writing                                */
  prtFile = fopen (prtFileName, "w");

/****************************************************************/
/* write header of protocol file                                */
  fprintf (prtFile, "Mix program, version 2.1.00");
  fprintf (prtFile, "Files to mix and randomize:\n");

/****************************************************************/
/* check arguments - input event files                          */
  for (i = 0; i < nf; ++i) {
    infile[i] = fopen (filename[i], "r");
    if (!infile[i]) {
      fprintf (stderr, "File not found: %s\n", filename[i]);
      fprintf (prtFile, "File not found: %s\n", filename[i]);
      return 2;
    } else {
      fprintf (prtFile, "%s\n", filename[i]);
    }
  }

  for (i = 0; i < nf; ++i) {
      tbase[i] = init_cap(100);
      cup_reader (infile[i], tbase[i]);
      syntax_validity (tbase[i]);
      structure_validity (tbase[i]);
      physics_validity (tbase[i]);
      pos0[i] = ftell (infile[i]) + 1;  /* position of the 1st event beginning */
    }

  fill_LH_structures (nf, tbase, &theProcessUP, names, lenth);
  compare_extra_info (nf, tbase, &theProcessUP);
  nSubtot = theProcessUP.proc_info.NprocRUP;
  proc_position = malloc (nSubtot * sizeof (proc_pos));
  compare_processes (nf, tbase, proc_position);

/****************************************************************/
/*   allocate the memory space for dimensions                   */

  nRec = malloc (nSubtot * sizeof (long));
  real_nRec = malloc (nSubtot * sizeof (long));
  nRecRest = malloc (nSubtot * sizeof (long));
  ri = malloc (nSubtot * sizeof (double));
  pos = malloc (nSubtot * sizeof (long *));
  map = malloc (nSubtot * sizeof (char *));

  nRectot = 0;
  maxnRec = 0;
  for (i = 0; i < nSubtot; i++)
    real_nRec[i] = 0;

  t = 0;
  for (i = 0; i < nf; i++)
  {
    tt = get_tag (0, tbase[i], "total");
    if (tt != -1) {
      tt = get_ival (0, "Nproc", tbase[i]->tag[tt]);
    } else {
      fprintf (stderr, "Error: the file %s does not contain the total tag.\n", filename[i]);
      exit (2);
    }

    fseek (infile[i], pos0[i], SEEK_SET);
    while (1) {
      if (!fgets (buff, 1000, infile[i]))
        break;
      sscanf (buff, "%i", &nProc);
      num = t + nProc - 1;
      if (num < nSubtot) {
        real_nRec[num]++;
      } else {
        fprintf (stderr, "Error: process number of event exceed max process number in file %s.\n", filename[i]);
        exit (2);
      }
    }
    t += tt;
  }

  sigmatot = 0.0;
  for (i = 0; i < nSubtot; i++)
  {
    nRec[i] = proc_position[i].Nevents;
    if (real_nRec[i] != nRec[i]) {
      fprintf (stderr, "Warning! real number of events in file %s (%li) does not coinside with header info (%li).\n",
               filename[i], real_nRec[i], nRec[i]);
      nRec[i] = real_nRec[i];
    }
    nRecRest[i] = nRec[i];
    nRectot = nRectot + nRec[i];
    if (nRec[i] > maxnRec) {
      maxnRec = nRec[i];
    }
    pos[i] = malloc (nRec[i] * sizeof (long));
    map[i] = malloc (nRec[i] * sizeof (char));
    sigmatot += theProcessUP.proc_info.crossecUP[i];
  }

  t = 0;
  for (i = 0; i < nSubtot; i++) {
    real_nRec[i] = 0;
  }
  for (i = 0; i < nf; i++) {
    tt = get_tag (0, tbase[i], "total");
    if (tt != -1)
      tt = get_ival (0, "Nproc", tbase[i]->tag[tt]);
    else
      {
  	fprintf (stderr, "Error: the file %s des not contain the total tag.\n", filename[i]);
  	exit (2);
      }
    shift[i] = t;

    fseek (infile[i], pos0[i], SEEK_SET);
    while (1) {
      fpos = ftell (infile[i]);
      if (!fgets (buff, 1000, infile[i]))
  	break;
      sscanf (buff, "%i", &nProc);
      num = t + nProc - 1;
      pos[num][real_nRec[num]] = fpos;
      map[num][real_nRec[num]] = 0;
      real_nRec[num]++;
    }
    t += tt;
  }

/******************************************************************/
/* evaluate the map of subprocesses weights in the interval [0,1] */
  xrn = 0;
  for (i = 0; i < nSubtot; i++) {
    ri[i] = xrn + theProcessUP.proc_info.crossecUP[i] / sigmatot;
    xrn = ri[i];
  }

/****************************************************************/
/*         mix events from the files                            */
  outFile = fopen (target, "w");

  write_cap (outFile, tbase, theProcessUP);

  for (i = 0; i < nRectot; i++)
    {
      xrn = drand48 ();
      jf = 0;
      while (xrn > ri[jf])
        {
          jf++;
        }

      if (nRecRest[jf] == 0)
        {
          fprintf (stdout,  "mix: file %s exhausted!\n", filename [proc_position[jf].nfile]);
          fprintf (stdout,  "mix: %ld mixed/randomized events written to Mixed.PEV\n", i);
          fprintf (prtFile, "mix: %ld mixed/randomized events written to Mixed.PEV\n", i);
          fclose (outFile);
          fclose (prtFile);
          final_write_cap (target, nRecRest, i);
          free (pos);
          free (map);
          free (proc_position);
          free (tbase);
          free (pos0);
          free (shift);
          free (nRec);
          free (nRecRest);
          free (ri);
          for (i = 0; i < nf; ++i) {
            free (filename[i]);
          }
          free (filename);
          return 1;
        }
      l = 0;
      while (map[jf][l])
        {
          l++;
          if (l == nRec[jf])
            {
              l = 0;
            }
        }
      fseek (infile[proc_position[jf].nfile], pos[jf][l], SEEK_SET);
      map[jf][l] = 1;
      fgets (buff, 1000, infile[proc_position[jf].nfile]);
      sscanf (buff, "%i:%[^\n]", &nx, buff1);
      fprintf (outFile, " %i:%s\n", (int) (shift[proc_position[jf].nfile] + nx), buff1);
      nRecRest[jf] -= 1;
    }

  fprintf (stdout,  "mix: all files exhausted\n");
  fprintf (stdout,  "mix: %ld mixed/randomized events written to Mixed.PEV\n", nRectot);
  fprintf (prtFile, "mix: %ld mixed/randomized events written to Mixed.PEV\n", nRectot);
  fclose (outFile);
  fclose (prtFile);

  final_write_cap (target, nRecRest, i);
  free (pos);
  free (map);
  free (proc_position);
  free (tbase);
  free (pos0);
  free (shift);
  free (nRec);
  free (nRecRest);
  free (ri);
  for (i = 0; i < nf; ++i) {
    free (filename[i]);
  }
  free (filename);
  return 1;
}
