/*
 * Copyright (C) 2001-2003, CompHEP Collaboration
 *--------------------------------------------------
 *$Id: amplitudes.c,v 1.3 2003/11/08 19:46:05 kryukov Exp $
 *
 *$Log: amplitudes.c,v $
 *Revision 1.3  2003/11/08 19:46:05  kryukov
 *To bring into according the usage of messanykey and warnanykey functions.
 *
*/

#include <math.h>
#include "chep_crt/include/chep_crt.h"
#include "service2/include/os.h"

#include "symb/include/amplitudes.h"
#include "symb/include/physics.h"
#include "symb/include/s_files.h"
#include "symb/include/squar.h"
#include "symb/include/cweight.h"
#include "symb/include/ghosts.h"
#include "symb/include/colorVector.h"
#include "symb/include/diaprins.h"
#include "symb/include/prep_ampl.h"
#include "symb/include/draw_ampl.h"
#include "symb/include/process.h"
#include "symb/include/r_code_ampl.h"


#define DIAGRPTAR_NAME  scat("%stmp%cadiagram.tar",pathtouser,f_slash)

static void 
setMomenta (vampl * va)
{
  int i, j;
  int count = va->outno;

  for (i = 0; i < va->size; i++)
    for (j = 0; j < va->valence[i]; j++)
      {
	edgeinvert *v = &va->vertlist[i][j];

	if (v->link.vno == nullvert)
	  {
	    v->moment = v->link.edno + 1;
	    if (v->prop & IN_PRTCL)
	      v->moment *= -1;
	  }
	else if (i <= v->link.vno)
	  v->moment = ++count;
	else
	  v->moment = -va->vertlist[v->link.vno][v->link.edno].moment;
      }

}

static void 
setLorIndices (vampl * va, hlpcsptr ghosts)
{
  int i, j;
  int count = 0;


  for (i = 0; i < va->outno; i++)
    {
      edgeinvert *v = &(va->vertlist[va->outer[i].vno][va->outer[i].edno]);
      if (prtclbase[v->partcl - 1].spin == 2)
	v->lorentz = ++count;
      else
	v->lorentz = 0;
    }

  for (i = 0; i < va->size; i++)
    for (j = 0; j < va->valence[i]; j++)
      {
	edgeinvert *v = &va->vertlist[i][j];

	if (v->link.vno != nullvert)
	  {
	    if (prtclbase[v->partcl - 1].spin == 2)
	      {
		if (i < v->link.vno)
		  {
		    hlpcsptr g = ghosts;
		    v->lorentz = ++count;
		    while (g)
		      {
			if (g->hlpcs[i][j] == tbosonmark)
			  {
			    v->lorentz = ++count;
			    break;
			  }
			g = g->next;
		      }
		  }
		else
		  v->lorentz = va->vertlist[v->link.vno][v->link.edno].lorentz;
	      }
	    else
	      v->lorentz = 0;
	  }
      }
}

static void 
generateAmplitudeDiagrams (void)
{
  FILE *diagrp = fopen (DIAGRP_NAME, "rb");
  FILE *diagrpTar = fopen (DIAGRPTAR_NAME, "wb");

  vamplExt adiagTar;
  int nsub = 1;

  while (!feof (diagrp))
    {
      ampllist ampl_, ampl;

      ampl = labeledDiagrams (diagrp);
      ampl_ = ampl;
      while (ampl_)
	{
	  vampl vdiag;
	  permlist p;

	  mkverts (ampl_->dgrm, &vdiag);
	  p = ampl_->gen;
	  while (p)
	    {
	      int i;
	      adiagTar.Ampl = vdiag;
	      adiagTar.status = 0;
	      adiagTar.nsub = nsub;
	      for (i = 0; i < nout; i++)
		{
		  int ii = nin + p->perm[i] - 1;
		  int vno = vdiag.outer[nin + i].vno;
		  int edno = vdiag.outer[nin + i].edno;

		  adiagTar.Ampl.outer[ii] = vdiag.outer[nin + i];
		  adiagTar.Ampl.vertlist[vno][edno].nextvert.edno = ii + 1;
		  adiagTar.Ampl.vertlist[vno][edno].link.edno = ii;
		}
	      p = p->next;
	      {
		hlpcsptr ghosts;

		ghostsForAmplitude (&(adiagTar.Ampl), &ghosts);

		if (ghosts)
		  {
		    setMomenta (&(adiagTar.Ampl));
		    setLorIndices (&(adiagTar.Ampl), ghosts);
		    fwrite (&adiagTar, sizeof (adiagTar), 1, diagrpTar);
		  }
		eraseghosts (ghosts);
	      }
	    }
	  ampl_ = ampl_->next;
	}
      if (ampl)
	{
	  clearDiagrams (ampl);
	  nsub++;
	}
    }

  fclose (diagrp);
  fclose (diagrpTar);

}

/*====================================================================*/

static vamplExt *
readSubproc (FILE * fdiagr)
{
  vamplExt buff;
  int fpos;
  int nsub0;

  vamplExt *ans = NULL, *nextD;

  fread (&buff, sizeof (buff), 1, fdiagr);
  nsub0 = buff.nsub;

  do
    {
      fpos = ftell (fdiagr);
      nextD = malloc (sizeof (*nextD));
      *nextD = buff;
      nextD->next = ans;
      ans = nextD;
    }
  while (1 == fread (&buff, sizeof (buff), 1, fdiagr) && buff.nsub == nsub0);

  if (!feof (fdiagr))
    fseek (fdiagr, fpos, SEEK_SET);
  revers ((void **) &ans);
  return ans;
}


static void 
processCycle (void (*whatToDo) (int nsub, vamplExt * ans))
{
  FILE *fdiagr = fopen (DIAGRPTAR_NAME, "rb");
  int nsub = 0;
  vamplExt *ans, *ans1;

  while (!feof (fdiagr))
    {
      nsub++;
      ans = readSubproc (fdiagr);

      (*whatToDo) (nsub, ans);

      while (ans)
	{
	  ans1 = ans;
	  ans = ans->next;
	  free (ans1);
	}
    }

  fclose (fdiagr);
}

static void 
colorTest (int nsub, vamplExt * ans)
{
  int nvect = 0;
  rat *c_vectors = NULL;
  generateColorVectors (ans, &nvect, &c_vectors);
  free (c_vectors);
}

/*========================================================*/

static int 
makeSubMenu (char *header, char **menuStr, long **pos, long **ntot)
{
  vamplExt adiagTar;
  FILE *diagrpTar = fopen (DIAGRPTAR_NAME, "rb");
  int nsub0 = 0;
  int i;
  int quanta;
  int first;
  int n_del = 0, n_calc = 0, n_rest = 0;
  long fpos = 0;
  char buff[100];
  int l_ord, l_s, l_n;

  fseek (diagrpTar, -sizeof (adiagTar), SEEK_END);
  fread (&adiagTar, sizeof (adiagTar), 1, diagrpTar);



  *pos = m_alloc (sizeof (long) * adiagTar.nsub);
  *ntot = m_alloc (sizeof (long) * adiagTar.nsub);

  sprintf (buff, "%d", adiagTar.nsub);
  l_ord = strlen (buff);
  l_n = ftell (diagrpTar) / sizeof (adiagTar);
  sprintf (buff, "%d", l_n);
  l_n = strlen (buff);
  if (l_n < 4)
    l_n = 4;
  l_s = 4 * (nin + nout);

  quanta = (l_ord + 1) + (l_s + 1) + 3 * (l_n + 1) - 1;

  *menuStr = m_alloc (2 + quanta * adiagTar.nsub);
  (*menuStr)[0] = quanta;
  (*menuStr)[1] = 0;

  sprintf (header, "%*s|%-*s|%*s|%*s|%*s",
	   l_ord, "N", l_s, "Process", l_n, "Del", l_n, "Calc", l_n, "Rest");

  fseek (diagrpTar, 0, SEEK_SET);
  while (1 == fread (&adiagTar, sizeof (adiagTar), 1, diagrpTar))
    {
      if (nsub0 != adiagTar.nsub)
	{
	  (*pos)[nsub0] = fpos;
	  if (nsub0)
	    {
	      sprintf (*menuStr + strlen (*menuStr), "|%*d|%*d|%*d",
		       l_n, n_del, l_n, n_calc, l_n, n_rest);
	      (*ntot)[nsub0 - 1] = n_del + n_calc + n_rest;
	    }
	  n_del = 0;
	  n_calc = 0;
	  n_rest = 0;

	  nsub0 = adiagTar.nsub;
	  sprintf (*menuStr + strlen (*menuStr), "%*d|", l_ord, nsub0);

	  first = 1;
	  for (i = 0; i < adiagTar.Ampl.outno; i++)
	    {
	      edgeinvert *v = &adiagTar.Ampl.vertlist[adiagTar.Ampl.outer[i].vno]
	      [adiagTar.Ampl.outer[i].edno];

	      if (v->prop & IN_PRTCL)
		{
		  if (first)
		    first = 0;
		  else
		    strcat (*menuStr, ",");

		  sprintf (*menuStr + strlen (*menuStr), "%3.3s",
			 prtclbase[prtclbase[v->partcl - 1].anti - 1].name);
		}
	    }

	  strcat (*menuStr + strlen (*menuStr), "->");
	  first = 1;
	  for (i = 0; i < adiagTar.Ampl.outno; i++)
	    {
	      edgeinvert *v = &adiagTar.Ampl.vertlist[adiagTar.Ampl.outer[i].vno]
	      [adiagTar.Ampl.outer[i].edno];

	      if (v->prop & OUT_PRTCL)
		{
		  if (first)
		    first = 0;
		  else
		    strcat (*menuStr, ",");

		  sprintf (*menuStr + strlen (*menuStr), "%3.3s", prtclbase[v->partcl - 1].name);
		}
	    }
	}
      fpos = ftell (diagrpTar);

      if (adiagTar.status == -1)
	n_del++;
      if (adiagTar.status == 1)
	n_calc++;
      if (adiagTar.status == 0)
	n_rest++;

    }
  sprintf (*menuStr + strlen (*menuStr), "|%*d|%*d|%*d", l_n, n_del, l_n, n_calc, l_n, n_rest);
  (*ntot)[nsub0 - 1] = n_del + n_calc + n_rest;

  fclose (diagrpTar);
  return nsub0;
}


static long firstDiagramPos;
static long nDiagrams;
static FILE *diagrpTar;

static void 
my_pict (int n, int x, int y)
{
  int cHeight = tg_textheight ("H");
  int cWigth = tg_textwidth ("H");

  vamplExt buff;

  fseek (diagrpTar, (n - 1) * sizeof (buff) + firstDiagramPos, SEEK_SET);

  fread (&buff, sizeof (buff), 1, diagrpTar);

  drawAmpitudeDiagram (&(buff.Ampl), x, y);

  tg_settextjustify (LeftText, TopText);

  switch (buff.status)
    {
    case -1:
      scrcolor (Red, White);
      tg_outtextxy (x + cWigth, y + amplitudeFrameY (nin, nout) + cHeight / 2, "DEL");
      break;
    case 1:
      scrcolor (Blue, White);
      tg_outtextxy (x, y, "CALC");
      break;
    }
  scrcolor (Black, White);
}

static int 
commands (int n, char key)
{
  int l;
  vamplExt buff;
  int *map;
  int shift;
  switch (key)
    {
    case 'L':
      return 0 /*nothing to redraw */ ;

    case 'D':
    case 'R':
      map = m_alloc (nDiagrams * sizeof (int));
      fseek (diagrpTar, firstDiagramPos, SEEK_SET);
      for (l = 0; l < nDiagrams; l++)
	{
	  fread (&buff, sizeof (buff), 1, diagrpTar);
	  map[l] = buff.status;
	  if (key == 'D')
	    {
	      if (map[l] == 0)
		map[l] = -1;
	    }
	  else
	    {
	      if (map[l] == -1)
		map[l] = 0;
	    }
	}

      shift = (char *) &buff.status - (char *) &buff;

      for (l = 0; l < nDiagrams; l++)
	{
	  fseek (diagrpTar, firstDiagramPos + l * sizeof (buff) + shift, SEEK_SET);
	  fwrite (map + l, sizeof (int), 1, diagrpTar);
	}
      free (map);

      return 2 /* redrawScreen */ ;

    case 'O':
      fseek (diagrpTar, firstDiagramPos + (n - 1) * sizeof (buff), SEEK_SET);
      fread (&buff, sizeof (buff), 1, diagrpTar);
      if (buff.status == -1)
	buff.status = 0;
      else if (buff.status == 0)
	buff.status = -1;

      fseek (diagrpTar, firstDiagramPos + (n - 1) * sizeof (buff), SEEK_SET);
      fwrite (&buff, sizeof (buff), 1, diagrpTar);

      return 1;

    case 'G':
      {
	hlpcsptr ghosts, ghosts_;
	vampl g_ampl;
	FILE *txt = fopen ("view.tmp", "w");
	fseek (diagrpTar, firstDiagramPos + (n - 1) * sizeof (buff), SEEK_SET);

	fread (&buff, sizeof (buff), 1, diagrpTar);

	ghostsForAmplitude (&(buff.Ampl), &ghosts);


	ghosts_ = ghosts;
	while (ghosts_)
	  {
	    coloringAmpl (&(buff.Ampl), ghosts_, &g_ampl);
	    writeAmDiagram (&g_ampl, 1, ' ', txt);
	    ghosts_ = ghosts_->next;
	  }
	eraseghosts (ghosts);
	fclose (txt);

	txt = fopen ("view.tmp", "r");
	showtext (1, 1, 80, 1, "Ghosts", txt);
	fclose (txt);
	unlink ("view.tmp");
	return 0;
      }
    default:
      return 0;
    }
}


static void 
showOneSubproc (int edit)
{
  char comLine[80];
  int cHeight = tg_textheight ("H");


  diagrpTar = fopen (DIAGRPTAR_NAME, "r+b");

  if (edit)
    strcpy (comLine, "Delete,On/off,Restore,Ghosts,Latex");
  else
    strcpy (comLine, "Latex");


  pictures (nDiagrams, amplitudeFrameX (nin, nout),
	    amplitudeFrameY (nin, nout) + 3 * cHeight / 2, my_pict, comLine, commands, "");
  fclose (diagrpTar);
}


static void 
f7_key_prog (int x)
{
  static char delstr[5] = "}D{";
  inkeyString = delstr;
}

static void 
f8_key_prog (int x)
{
  static char delstr[5] = "}R{";
  inkeyString = delstr;
}



static void 
viewAmplDiag (int edit)
{
  char *menuStr;
  void *pscr = NULL;
  int k = 1;
  long *fpos;
  long *ntot;
  char header[100];
  int nsub = makeSubMenu (header, &menuStr, &fpos, &ntot);

  {
    if (edit)
      {
	f3_key[4] = f7_key_prog;
	f3_key[5] = f8_key_prog;
      }
    do
      {
	if (nsub > 1)
	  menu1 (10, 11, header, menuStr, NULL, &pscr, &k);
	if (k)
	  {
	    firstDiagramPos = fpos[k - 1];
	    nDiagrams = ntot[k - 1];
	    showOneSubproc (edit);
	    if (edit)
	      {
		free (menuStr);
		free (fpos);
		free (ntot);
		makeSubMenu (header, &menuStr, &fpos, &ntot);
	      }
	  }
	if (nsub == 1)
	  k = 0;
      }
    while (k);
    if (edit)
      {
	f3_key[4] = NULL;
	f3_key[5] = NULL;
      }
    if (nsub > 1)
      put_text (&pscr);
  }
  free (menuStr);
  free (fpos);
  free (ntot);
}

/*====================================================================*/

static void 
f4_key_prog_a (int x)
{
  viewAmplDiag (0);
}


static void 
amplitudeDiagramStat (int *nsub, int *ntot, int *ndel, int *ncalc)
{
  vamplExt adiagTar;
  FILE *diagrpTar = fopen (DIAGRPTAR_NAME, "rb");
  int nsub0 = 0;

  *nsub = 0;
  *ntot = 0;
  *ndel = 0;
  *ncalc = 0;

  while (1 == fread (&adiagTar, sizeof (adiagTar), 1, diagrpTar))
    {
      if (nsub0 != adiagTar.nsub)
	{
	  (*nsub)++;
	  nsub0 = adiagTar.nsub;
	}
      (*ntot)++;
      if (adiagTar.status == -1)
	(*ndel)++;
      if (adiagTar.status == 1)
	(*ncalc)++;
    }
  fclose (diagrpTar);
}

static void 
amplitudeDiagramInfo (int nsub, int ntot, int ndel, int ncalc)
{
  scrcolor (FGmain, BGmain);
  clrbox (1, 5, 55, 8);
  scrcolor (Red, BGmain);

  goto_xy (15, 5);
  print (" Amplitude diagrams \n");
  scrcolor (FGmain, BGmain);
  print ("      diagrams in      subprocesses  are constructed.\n");
  print ("      diagrams  are deleted.\n");
  print ("      diagrams  are calculated.");
  scrcolor (Blue, BGmain);
  goto_xy (1, 6);
  print ("%d", ntot);
  goto_xy (20, 6);
  print ("%d", nsub);
  goto_xy (1, 7);
  print ("%d", ndel);
  goto_xy (1, 8);
  print ("%d", ncalc);
  scrcolor (FGmain, BGmain);
}

/*===================================================================*/

void 
Amplitudes (void)
{
  int nsub, ntot, ndel, ncalc;
  int k11 = 0, k12 = 0, k13 = 0;
  void *pscr11 = NULL, *pscr12 = NULL, *pscr13 = NULL;
  void *pscr_save;
  void (*f4_key_prog_current) (int);
  f4_key_prog_current = f3_key[1];

  f3_key[1] = f4_key_prog_a;

  get_text (1, 1, maxCol (), maxRow (), &pscr_save);
  generateAmplitudeDiagrams ();
  amplitudeDiagramStat (&nsub, &ntot, &ndel, &ncalc);
  amplitudeDiagramInfo (nsub, ntot, ndel, ncalc);

  do
    {
      if (ntot > ndel + ncalc)
	do
	  {
	    menu1 (56, 4, "", "\026"
		   " Amplitude diagrams   "
		   " Symbolic calculations"
		   " REDUCE program       ", NULL, &pscr11, &k11);
	    switch (k11)
	      {
	      case 1:
		viewAmplDiag (1);
		amplitudeDiagramStat (&nsub, &ntot, &ndel, &ncalc);
		break;
	      case 2:
		if (ntot == ndel + ncalc)
		  messanykey (10, 10,"There are no diagrams for calculation");
		else
		  {
		    processCycle ( /*symbolicAmplitude */ colorTest);
		    amplitudeDiagramStat (&nsub, &ntot, &ndel, &ncalc);
		  }
		break;
	      case 3:
		processCycle (makeReduceAmpl);
		break;
	      }
	    amplitudeDiagramInfo (nsub, ntot, ndel, ncalc);
	  }
	while (k11);
      else
	do
	  {
	    amplitudeDiagramInfo (nsub, ntot, ndel, ncalc);
	    menu1 (56, 4, "", "\026"
		   " Amplitude diagrams   "
		   " Write  results       "
		   " Numerical interpreter"
		   " C-compiler           ", NULL, &pscr12, &k12);
	    switch (k12)
	      {
	      case 1:
		viewAmplDiag (1);
		amplitudeDiagramStat (&nsub, &ntot, &ndel, &ncalc);
		put_text (&pscr12);
		k12 = 0;
		break;
	      case 2:
		menu1 (56, 6, "", "\026"
		       " REDUCE code          "
		       " MATHEMATICA code     "
		       " C code(for num.calc.)", NULL, &pscr13, &k13);
		switch (k13)
		  {
		  case 0:
		    break;
		  case 1:
		  case 2:
		  case 4:
		    break;
		  }
		if (k13)
		  put_text (&pscr13);
		break;
	      case 3:
		messanykey (10, 10, "Not implemented yet");
		break;
	      case 4:
		messanykey (10, 10, "Not implemented yet");
		break;
	      }
	  }
	while (k12);

      if (mess_y_n (10, 10, "Would you like to complete\n"
		    "the amplitude session"))
	{
	  put_text (&pscr_save);
	  scrcolor (FGmain, BGmain);
	  f3_key[1] = f4_key_prog_current;
	  return;
	}
    }
  while (1);
}
