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

#include "tag_reader.h"
#include "tag_parser.h"
#include "tag_writer.h"

static FILE *evfile = NULL;

void 
tag_writer (FILE * file, elementary_tag * tag)
{
  int i, k;
  int len;

  fprintf (file, "##%s:", tag->tagname);
  len = strlen (tag->tagname);
  for (i = 0; i < tag->tagsize; i++)
    {
      fprintf (file, " %s,", tag->commands[i]);
      if (!((i + 1) % 5) && i != tag->tagsize - 1)
	{
	  fprintf (file, "\n");
	  for (k = 0; k < len + 3; k++)
	    {
	      fputc (' ', file);
	    }
	}
    }
  fprintf (file, ";\n");
}

int
cap_writer (FILE * file, tags * p)
{
  int i;

  for (i = 0; i < p->number_of_tags; i++)
    tag_writer (file, p->tag[i]);
  fprintf (file, ";\n");
  return 0;
}

int
change_cap (tags * t, int nEvents, double mult, double rmax, double cs, double er)
{
  int n;
  int N, Nold;
  double maxW, ml, old_ml;
  string_comnd com;

  n = get_tag (0, t, "total");
  if (n != -1)
    {
      Nold = get_ival (0, "Nevent", t->tag[n]);
      N = nEvents + Nold;
      strcpy (com.name, "Nevent");
      change_ival (N, 8 - intlen (N), com, t->tag[n]);
      strcpy (com.name, "CrosSec");
      change_fval (cs, com, t->tag[n]);
      strcpy (com.name, "CrosSecErr");
      change_fval (er, com, t->tag[n]);
    }
  else
    {
      fprintf (stderr, "***Error! The total tag has not been found...\n");
      return -1;
    }

  n = get_tag (0, t, "process");
  if (n != -1)
    {
      strcpy (com.name, "CrosSec");
      change_fval (cs, com, t->tag[n]);
      strcpy (com.name, "CrosSecErr");
      change_fval (er, com, t->tag[n]);
    }
  else
    {
      fprintf (stderr, "***Error! The process tag has not been found...\n");
      return -1;
    }

  n = get_tag (0, t, "n_event");
  if (n != -1)
    {
      strcpy (com.name, "N");
      change_ival (N, 8 - intlen (N), com, t->tag[n]);
      old_ml = get_fval (0, "mult", t->tag[n]);
      ml = (old_ml * (double) Nold + mult * (double) nEvents) / N;
      strcpy (com.name, "mult");
      change_fval (ml, com, t->tag[n]);
      maxW = get_ival (0, "maxW", t->tag[n]);
      strcpy (com.name, "maxW");
      if (maxW < rmax)
        change_fval (rmax, com, t->tag[n]);
    }
  else
    {
      fprintf (stderr, "***Error! The n_event tag has not been found...\n");
      return -1;
    }
  return 0;
}

static int 
write_mandatory_tag (int m, tags * the_tags, char *tagname)
{
  int n;

  n = get_tag (m, the_tags, tagname);
  if (n == -1)
    {
      fprintf (stderr, "Error: problems with mandatory tags during writing procedure");
      return -1;
    }
  tag_writer (evfile, the_tags->tag[n]);
  return n;
}

int 
write_cap (FILE * file, tags ** the_tags, process_ prUP)
{
  int i, j;
  int npr = 0;
  int nproc = 1;
  int n, nn;
  int Ntot = 0;
  string_comnd com[3];

  evfile = file;
  n = write_mandatory_tag (0, the_tags[0], "beam");
  n = write_mandatory_tag (n + 1, the_tags[0], "beam");
  n = write_mandatory_tag (0, the_tags[0], "strfun");
  n = write_mandatory_tag (n + 1, the_tags[0], "strfun");

  j = -1;
  for (i = 0; i < prUP.proc_info.NprocRUP; i++)
    {
      sprintf (com[0].value, "%i", nproc);
      sprintf (com[1].value, "%i", i + 1);
      if (i >= npr)
	{
	  nproc = 1;
	  j++;
	  strcpy (com[0].name, "Nproc");
	  n = get_tag_with1com (0, the_tags[j], "total", &(com[0]));
	  if (n != -1)
	    {
	      npr += atoi (com[0].value);
	    }
	  else
	    {
	      fprintf (stderr, "1.Erorr during tags writing...\nExit.\n");
	      exit (5);
	      return -1;
	    }
	}
      else
        {
	  nproc++;
        }

      strcpy (com[0].name, "ID");
      sprintf (com[0].value, "%i", nproc);
      strcpy (com[1].name, "ID");

      n = get_tag_with_exactcom (0, the_tags[j], "process", com[0]);
      if (n == -1)
	{
	  fprintf (stderr, "2.Erorr during tags writing...\nExit.\n");
	  exit (5);
	  return -1;
	}
      if (prUP.maps[i].used == 1)
	{
	  replace_com (com[1], the_tags[j]->tag[n]);
	  tag_writer (file, the_tags[j]->tag[n]);
	  replace_com (com[0], the_tags[j]->tag[n]);

	  strcpy (com[0].name, "IDprocess");
	  strcpy (com[1].name, "IDprocess");
	  n = get_tag_with_exactcom (0, the_tags[j], "generator", com[0]);
	  if (n != -1)
	    {
	      replace_com (com[1], the_tags[j]->tag[n]);
	      tag_writer (file, the_tags[j]->tag[n]);
	      replace_com (com[0], the_tags[j]->tag[n]);
	    }

	  n = get_tag_with_exactcom (n + 1, the_tags[j], "n_event", com[0]);
	  if (n != -1)
	    {
	      int N;
	      replace_com (com[1], the_tags[j]->tag[n]);
	      N = get_ival (0, "N", the_tags[j]->tag[n]);
	      Ntot += N;
	      strcpy (com[2].name, "origN");
	      sprintf (com[2].value, "%i", N);
	      nn = replace_com (com[2], the_tags[j]->tag[n]);
	      if (nn == -1)
		add_com (com[2], the_tags[j]->tag[n]);
	      tag_writer (file, the_tags[j]->tag[n]);
	      replace_com (com[0], the_tags[j]->tag[n]);
	    }

	  n = -1;
	  do
	    {
	      n = get_tag_with_exactcom (n + 1, the_tags[j], "cut", com[0]);
	      if (n != -1)
		{
		  replace_com (com[1], the_tags[j]->tag[n]);
		  tag_writer (file, the_tags[j]->tag[n]);
		  replace_com (com[0], the_tags[j]->tag[n]);
		}
	    }
	  while (n != -1);

	  n = -1;
	  do
	    {
	      n = get_tag_with_exactcom (n + 1, the_tags[j], "parton", com[0]);
	      if (n != -1)
		{
		  replace_com (com[1], the_tags[j]->tag[n]);
		  tag_writer (file, the_tags[j]->tag[n]);
		  replace_com (com[0], the_tags[j]->tag[n]);
		}
	    }
	  while (n != -1);

	  n = get_tag_with_exactcom (n + 1, the_tags[j], "QCDinfo", com[0]);
	  if (n != -1)
	    {
	      replace_com (com[1], the_tags[j]->tag[n]);
	      tag_writer (file, the_tags[j]->tag[n]);
	      replace_com (com[0], the_tags[j]->tag[n]);
	    }

	  n = get_tag_with_exactcom (n + 1, the_tags[j], "format", com[0]);
	  if (n != -1)
	    {
	      replace_com (com[1], the_tags[j]->tag[n]);
	      tag_writer (file, the_tags[j]->tag[n]);
	      replace_com (com[0], the_tags[j]->tag[n]);
	    }
	}
    }

  n = get_tag (0, the_tags[0], "total");
  if (n != -1)
    {
      strcpy (com[2].name, "Nproc");
      sprintf (com[2].value, "%i", prUP.proc_info.NprocRUP);
      replace_com (com[2], the_tags[0]->tag[n]);
      strcpy (com[2].name, "Nevent");
      sprintf (com[2].value, "%i", Ntot);
      replace_com (com[2], the_tags[0]->tag[n]);
      tag_writer (file, the_tags[0]->tag[n]);
    }
  fprintf (file, "##:;;\n");

  return 0;
}

int 
final_write_cap (const char *outFileName, long *nRecRest, int tot)
{
  int i, n;
  int Nproc;
  int N;
  int len;
  double *sc;
  double *scerr;
  double sc0 = 0.0;
  double sc1 = 0.0;
  FILE *file;
  tags *tagsbase;
  string_comnd com;

  tagsbase = init_cap (1);
  file = fopen (outFileName, "r+");
  cup_reader (file, tagsbase);

  strcpy (com.name, "Nproc");

  n = get_tag_with1com (0, tagsbase, "total", &com);
  Nproc = atoi (com.value);
  sc = malloc (Nproc * sizeof (double));
  scerr = malloc (Nproc * sizeof (double));

  for (i = 0; i < Nproc; i++)
    {
      strcpy (com.name, "IDprocess");
      sprintf (com.value, "%i", i + 1);
      n = get_tag_with_exactcom (0, tagsbase, "n_event", com);
      if (n != -1)
	{
	  N = get_ival (0, "origN", tagsbase->tag[n]);
	  strcpy (com.name, "N");
	  sprintf (com.value, "%i", N);
	  len = intlen (N) - intlen (N - nRecRest[i]);
	  change_ival (N - nRecRest[i], len, com, tagsbase->tag[n]);
	}

      strcpy (com.name, "ID");
      sprintf (com.value, "%i", i + 1);
      n = get_tag_with_exactcom (0, tagsbase, "process", com);
      if (n != -1)
	{
	  sc[i] = get_fval (0, "CrosSec", tagsbase->tag[n]);
	  scerr[i] = get_fval (0, "CrosSecErr", tagsbase->tag[n]);
	}
    }

  for (i = 0; i < Nproc; i++)
    {
      sc0 += sc[i];
      sc1 += (scerr[i] * scerr[i]);
    }
  sc1 = sqrt (sc1);

  n = get_tag (0, tagsbase, "total");
  if (n != -1)
    {
      N = get_ival (0, "Nevent", tagsbase->tag[n]);
      strcpy (com.name, "Nevent");
      sprintf (com.value, "%i", N);
      len = intlen (N) - intlen (tot);
      change_ival (tot, len, com, tagsbase->tag[n]);
      strcpy (com.name, "CrosSec");
      change_fval (sc0, com, tagsbase->tag[n]);
      strcpy (com.name, "CrosSecErr");
      change_fval (sc1, com, tagsbase->tag[n]);
    }

  rewind (file);
  for (i = 0; i < tagsbase->number_of_tags; i++)
    {
      tag_writer (file, tagsbase->tag[i]);
    }
  fprintf (file, "##:;;\n");
  fclose (file);
  free (sc);
  free (scerr);
  return 1;
}
