/*
* Copyright (C) 2001-2008, CompHEP Collaboration
* Copyright (C) 1997, Alexander Pukhov
* ------------------------------------------------------
* $Id: process.c,v 1.18 2004/05/10 12:48:26 kryukov Exp $
*
* $Log: process.c,v $
* Revision 1.18  2004/05/10 12:48:26  kryukov
* This version is equal to 4.4.1
*
* Revision 1.16.2.1  2004/04/30 15:08:36  sherstnv
* Old changes, included detween v_4_4_0 and tarball (comphep-4.4.0.tgz)
* from the CompHEP homepage.
*
* Revision 1.17  2003/11/19 12:54:40  kryukov
* Some misprints. Special thanks Prof. Higgins.
*
* Revision 1.16  2003/11/08 19:46:05  kryukov
* To bring into according the usage of messanykey and warnanykey functions.
*
* Revision 1.15  2003/11/07 12:22:13  sherstnv
* Non-critical bug has been fixed.
*
* Revision 1.14  2003/11/06 23:55:18  sherstnv
* Some bugs have been removed
*
* Revision 1.13  2003/11/06 10:55:59  sherstnv
* New switch between model particles and composite particle appears.
*
* Revision 1.12  2003/11/04 21:48:11  sherstnv
* Bug ia fixed: in decay menu if decayed particle is a composite one
* and user press ESC after he view content of the particle, decayec particle
* appears on not right string in the interface.
*
* Revision 1.11  2003/11/01 21:44:55  kryukov
* Copyright record
*
* Revision 1.10  2003/11/01 21:34:55  kryukov
* Change message about switch to beam table.
*
* Revision 1.9  2003/10/26 15:05:50  sherstnv
* Bugs are fixed in decay menu:
* Proper processing of the menu strings when the ESC is entered.
*
* Revision 1.8  2003/09/22 11:34:09  sherstnv
* Process entering divides to 2 stages:
* 1) At first, we enter beams (name, mass, content, str,fun)
* 2) after that - final state.
*
* Revision 1.7  2003/06/25 18:46:41  kryukov
* *** empty log message ***
*
* Revision 1.6  2003/06/15 12:13:31  sherstnv
* New schime of excluding/keeping diagrams during their construction
* is realized. Extra conditions are included:
* ! - "not equaled"
* = - "equaled"
* < - "less than"
* All necessary help files is corrected.
*
* Revision 1.5  2003/04/22 09:01:20  kryukov
* Apply indent to improve readability of files
*
* Revision 1.4  2003/04/21 21:01:03  kryukov
* Improve the shape of particle list.
*
*/
#include <math.h>

#include "service2/include/chep_limits.h"
#include "service2/include/tptcmac.h"
#include "service2/include/s_files.h"
#include "service2/include/syst.h"
#include "chep_crt/include/chep_crt.h"

#include "sos.h"
#include "screen.h"
#include "read_mdl.h"
#include "beams.h"
#include "physics.h"
#include "m_utils.h"
#include "process_core.h"
#include "process.h"

hadron hadrons[MAXINOUT];
static int hadrons_are_initialized = 0;


char **
stritems (char *format, char *s)
{
  int i, space = 1, item = 0, l = strlen (s);
  char **res = NULL;

  for (i = 0; i < l; i++)
    if (!strchr (format, s[i]))
      {
        if (space)
          {
            space = 0;
            item++;
          }
      }
    else
      space = 1;

  res = malloc ((item + 1) * sizeof (char *));
  res[item] = NULL;

  item = 0;
  space = 1;
  for (i = 0; i < l; i++)
    if (!strchr (format, s[i]))
      {
        if (space)
          {
            space = 0;
            res[item++] = s + i;
          }
      }
    else
      space = 1;

  return res;
}

/* static char* errTxt = NULL; */

int
input (int y0, char *directive, char *text, int cur, int lim)
{
  int err;

/* Old scheme for error visualization.
  if (errTxt)
    {
      goto_xy (1, y0 + 1);
      scrcolor (FGmain, BGmain);
      clr_eol ();
      print ("%s", "Error: ");
      scrcolor (Red, BGmain);
      print ("%s", errTxt);
      scrcolor (FGmain, BGmain);
      be_be ();
      errTxt = NULL;
    }
*/
  goto_xy (1, y0);
  scrcolor (FGmain, BGmain);
  print ("%s", directive);
  err = str_redact (text, cur, lim);
  return err;
}


static void
addlim (whohow p_list, int j, int k, int type)
{
  int i;

  if (prtclbase[j - 1].anti < j)
    j = prtclbase[j - 1].anti;
  for (i = 0; i < whohowMAX - 1; i++)
    {
      if (p_list[i].who == j && type == 1)
        return;
      if (p_list[i].who == 0)
        {
          p_list[i].who = j;
          p_list[i].how = k;
          p_list[i].type = type;
          p_list[i + 1].who = 0;
          return;
        }
    }
}

/*
Version used in comphep-4.4.3: No editting of composite particles during process entering
int
enter_hadron (int *y, char *nme, int num)
{
  int i;
  int j;
  char **items = NULL;
  shortstr errTxt;

// If particle is a model one, hadron is formed by this particle
  j = locateinbase (nme);
  if (j && !pseudop (j))
    {
      strcpy (hadrons[num].name, nme);
      strcpy (hadrons[num].strfun,"OFF");
      hadrons[num].parton[0] = j;
      hadrons[num].how = 1;
      return 0;
    }

// if particle has been appeared already, the new hadron is formed by previous one
  for (i = 0; i < num; i++)
    if (!strcmp (hadrons[i].name, nme))
      {
	strcpy (hadrons[num].name, nme);
	strcpy (hadrons[num].strfun, hadrons[i].strfun);
	hadrons[num].how = hadrons[i].how;
	for (j = 0; j < hadrons[num].how; j++)
	  {
	    hadrons[num].parton[j] = hadrons[i].parton[j];
	  }
	return 0;
      }

  if (strlen (nme) == 0 || strlen (nme) > 10)
    {
      fprintf (stderr, "CompHEP: internal error %i. Please, inform authors.", 2);
      exit (11);
    }

// if composite particles DB contains the particle with name the hadron is formed by this cparticle 
  j = In_composite_particle_base (nme);
  if (0 > j)
    {
       sprintf (errTxt,"%s is not a composite particle or particle in the model", nme);
       warnanykey (12, 11, errTxt);
       if (blind)
	 {
	   sprintf (errTxt, "composite particles: specify particle compositeness: %s", nme);
	   batch_error (errTxt, 1);
	 }
       return 1;
    }
  else
    {
      items = stritems (" ,", cpartbase[j].cpart);
      for (i = 0, hadrons[num].how = 0; items[i]; i++)
	{
	  shortstr pname;
	  sscanf (items[i], "%[^ ,]", pname);
	  j = locateinbase (pname);
	  if (!j || pseudop (j))
	    {
	      if (blind)
		{
		  sprintf (errTxt, "Unknown constituent %s in composite particle %s", pname, nme);
		  batch_error (errTxt, 1);
		}
	      warnanykey (12, 12, "Unknown model particle");
	      return 1;
	    }
	  hadrons[num].parton[hadrons[num].how++] = j;
	}
      strcpy (hadrons[num].name, nme);
      strcpy (hadrons[num].strfun,"OFF");
    }
  return 0;
}
*/

int
enter_hadron (int *y, char *nme, int num)
{
  int i;
  int j = 0;
  char **items;
  shortstr errTxt;

// If the particle is a model one, the hadron is formed by this particle only
  j = locateinbase (nme);
  if (j && !pseudop (j)) {
    strcpy (hadrons[num].name, nme);
    strcpy (hadrons[num].strfun,"OFF");
    hadrons[num].parton[0] = j;
    hadrons[num].how = 1;
    return 0;
  }

// if the particle counsides with previons one, the new hadron is formed by the previous hadron
  for (i = 0; i < num; i++) {
    if (!strcmp (hadrons[i].name, nme)) {
      strcpy (hadrons[num].name, nme);
      strcpy (hadrons[num].strfun, hadrons[i].strfun);
      hadrons[num].how = hadrons[i].how;
      for (j = 0; j < hadrons[num].how; j++) {
        hadrons[num].parton[j] = hadrons[i].parton[j];
      }
      return 0;
    }
  }

  if (0 == strlen (nme) || strlen (nme) > 10) {
    fprintf (stderr, "CompHEP: internal error %i. Please, inform authors.", 2);
    return -1;
  }

// if composite particles DB contains the particle with name the hadron is formed by this cparticle
  if (0 > In_composite_particle_base (nme)) {
    int stop = 1;
    do {
      sprintf (errTxt, "The model does not contain the composite particle %s\n"
                       "Do you want to introduce new particle?", nme);
      if (mess_y_n (12, 11, errTxt)) {
        int n_model;
        do {
          if (blind) {
            sprintf (errTxt, "Unknown composite particle %s", nme);
             batch_error (errTxt, 1);
          }
          edittable (1, 1, &modelTab[4], 1, "s_mdl_5", 0);
          n_model = getModelNumberSymb();
          writeModelFiles (n_model, "models");
          if (loadModel (TRUE)) stop = 0;
        } while (stop);
      } else {
        stop = 0;
      }
    } while (stop);
  }

  j = In_composite_particle_base (nme);
  items = stritems (" ,", cpartbase[j].cpart);
  for (i = 0, hadrons[num].how = 0; items[i]; i++) {
    shortstr pname;
    sscanf (items[i], "%[^ ,]", pname);
    j = locateinbase (pname);
    if (!j || pseudop (j)) {
      if (blind) {
        sprintf (errTxt, "Unknown constituent %s in composite particle %s", pname, nme);
        batch_error (errTxt, 1);
      }
      warnanykey (12, 12, "Unknown model particle");
      return 1;
    }
    hadrons[num].parton[hadrons[num].how++] = j;
  }
  strcpy (hadrons[num].name, nme);
  strcpy (hadrons[num].strfun,"OFF");

  return 0;
}

static int nTotP;
static int nFirstP;

void
prtcllist (int key, int switch_list)
{
  int i, j, pnum;
  int tabMax, tabSz;

  shortstr buf1, buf2, buf3, buf4, hlp, p1, p2, fullname;
  longstr str;
  linelist ln;

  tabMax = ycons - 7;
  if (-1 == key)
    {
      key = 0;
      for (i = 2; i < 24; i++)
       {
         goto_xy (1, i);
         clr_eol ();
       }
    }

  if (key == 0)
    {
      scrcolor (FGmain, BGmain);
      for (i = 2; i <= 18; i++)
        {
          goto_xy (1, i);
          clr_eol ();
        }
      switch (switch_list)  /* switch_list = 1(in beam menu), 2(in decay menu), 0(other cases)*/
        {
          case 1:
            {
              goto_xy (10, 3);
              scrcolor (Blue, BGmain);
              print ("List of (anti)particles (switch to the beam list by F3)");
              break;
            }
          case 2:
            {
              goto_xy (5, 3);
              scrcolor (Blue, BGmain);
              print ("List of (anti)particles (switch to the composite particle list by F3)");
              break;
            }
          case 0:
            {
              goto_xy (24, 3);
              scrcolor (Blue, BGmain);
              print ("List of (anti)particles");
              break;
            }
         }
      nTotP = 0;
      nFirstP = 1;
    }
  else
    {
      if (nTotP <= 3 * tabMax)
        return;
      switch (key)
        {
        case KB_DOWN:
          nFirstP += 3;
          break;
        case KB_UP:
          nFirstP -= 3;
          break;
        case KB_PAGED:
          nFirstP += 3 * tabMax;
          break;
        case KB_PAGEU:
          nFirstP -= 3 * tabMax;
          break;
        }
      if (nFirstP < 1)
        nFirstP = 1;
      if (nTotP - nFirstP + 3 < 3 * tabMax)
        nFirstP = 1 + 3 * ((nTotP + 2) / 3) - 3 * tabMax;
      clrbox (1, 4, 79, 5 + tabMax);
    }
  goto_xy (3, 5);
  i = 0;
  ln = prtcls_tab.strings;
  scrcolor (FGmain, BGmain);
  while (ln != NULL)
    {
      sscanf (ln->line,
              "%[^|]%*c%[^|]%*c%[^|]%*c%[^|]%*c%[^|]%*c%[^|]%*c%[^|]%*c%[^|]",
              fullname, p1, p2, buf1, buf2, buf3, buf4, hlp);
      trim (p1);
      trim (p2);
      trim (fullname);
      pnum = locateinbase (p1);
      trim (hlp);
      if (prtclbase[pnum - 1].top != NULL && strcmp (hlp, "*") != 0)
        {
          i++;
          if (i >= nFirstP && (i - nFirstP) / 3 < tabMax)
            {
              switch (strlen (p1))
                {
                case 1:
                  sprintf (str, "%s(%s)     %s", p1, p2, fullname);
                  break;
                case 2:
                  sprintf (str, "%s(%s)   %s", p1, p2, fullname);
                  break;
                case 3:
                  sprintf (str, "%s(%s) %s", p1, p2, fullname);
                  break;
                default:
                  fprintf (stderr,
                           "***** prtcllist: Too long name p1=%s. ABORT\n",
                           p1);
                  exit (99);
                }
              print ("%s", str);
              str[0] = '\0';
              j = i % 3;
              if (j == 0)
                goto_xy (3, where_y () + 1);
              else
                goto_xy (3 + 26 * j, where_y ());
            }
        }
      ln = ln->next;
    }
  nTotP = i;
  tabSz = MIN ((nTotP + 2) / 3, tabMax);
  chepbox (1, 4, 79, 5 + tabSz);

  if (nFirstP > 1)
    {
      goto_xy (72, 4);
      print ("PgUp");
    }
  if (nFirstP + 3 * tabSz <= nTotP)
    {
      goto_xy (72, 5 + tabMax);
      print ("PgDn");
    }
  scrcolor (FGmain, BGmain);
}


static int nTotCP;
static int nFirstCP;

void
composite_prtcllist (int key)
{
  int i;
  int tabMax, tabSz;

  tabMax = ycons - 7;
  if (-1 == key)
    {
      key = 0;
      for (i = 2; i < 24; i++)
       {
         goto_xy (1, i);
         clr_eol ();
       }
    }

  if (key == 0)
    {
      scrcolor (FGmain, BGmain);
      for (i = 2; i <= 18; i++)
        {
          goto_xy (1, i);
          clr_eol ();
        }
      goto_xy (10, 3);
      scrcolor (Blue, BGmain);
      print ("List of composite particles (switch to the particle list by F3)");
      nTotCP = 0;
      nFirstCP = 0;
    }
  else
    {
      if (nTotCP <= tabMax)
        return;
      switch (key)
        {
        case KB_DOWN:
          nFirstCP++;
          break;
        case KB_UP:
          nFirstCP--;
          break;
        case KB_PAGED:
          nFirstCP += tabMax;
          break;
        case KB_PAGEU:
          nFirstCP -= tabMax;
          break;
        }
      if (nFirstCP < 0)
        nFirstCP = 0;
      if (nTotCP - nFirstCP < tabMax)
        nFirstCP = nTotCP - tabMax;
      clrbox (1, 4, 79, 5 + tabMax);
    }
  goto_xy (3, 5);
  scrcolor (FGmain, BGmain);
  for (i = 0; i < n_cpart; i++)
    {
      if (i >= nFirstCP && (i - nFirstCP) < tabMax)
        {
          print ( "Name: %s (%s)", cpartbase[i].name, cpartbase[i].cpart);
          goto_xy (3, where_y () + 1);
        }
    }
  nTotCP = n_cpart;
  tabSz = MIN (nTotCP + 2, tabMax);
  chepbox (1, 4, 79, 5 + tabSz);

  if (nFirstCP > 0)
    {
      goto_xy (72, 4);
      print ("PgUp");
    }
  if (nFirstCP + tabSz <= nTotCP)
    {
      goto_xy (72, 5 + tabMax);
      print ("PgDn");
    }
  scrcolor (FGmain, BGmain);
}


int
exclude_diagrams (int *y0)
{
  int i;
  int jj, j;
  int k, ntot;
  int redres;
  int type = 1;
  char **items;
  char *n;
  shortstr frgm;
  shortstr errTxt;

  if (*y0 < maxRow ())
    (*y0)++;
   redres = 0;

again:
   prtcllist (redres,0);
   if (!blind) {
    shortstr tmpexcl_str;
    strcpy (tmpexcl_str, getExclprtlist ());
    redres = input (*y0, "Exclude diagrams with ", tmpexcl_str, 1, 70);
    setExclprtlist (tmpexcl_str);
  } else {
    redres = KB_ENTER;
    redres = inkey();
  }
  switch (redres)
    {
      case KB_PAGED:
      case KB_PAGEU:
      case KB_UP:
      case KB_DOWN:
      case KB_F2:
      case KB_F3:
        goto again;
      case KB_F1:
        show_help ("s_ent_4");
        redres = 0;
        goto again;
      case KB_ESC:
        clrbox (1, 2, maxCol (), 24);
        (*y0) = (*y0) - 2;
        return 0;
    }

  nilprtcl (exclude_list);
  ntot = 0;
  items = stritems (",", getExclprtlist ());
  for (i = 0; items[i]; i++)
    {
      sscanf (items[i], "%[^,]", frgm);     /*  read of condition for excluding */

/* type opredelyaet tip usloviya dlya excuding/keeping
  type= 2 -> vse exclude/keep;
  type= 1 -> znak ">";
  type=-1 -> znak "ne ravno";
  type=-2 -> znak "=";
  type=-3 -> znak "<";
*/
      n = strchr (frgm, '!');
      if (n)
        type = -1;
      else
        {
          n = strchr (frgm, '=');
          if (n)
            type = -2;
          else
            {
              n = strchr (frgm, '<');
              if (n)
                type = -3;
              else
                {
                  n = strchr (frgm, '>');
                  if (n)
                    type = 1;
                  else
                    type = 2;
                }
            }
        }

      if (n)
        {
          n[0] = 0;
          k = 0;
          sscanf (n + 1, "%d", &k);
          if (k < 0)
            {
              warnanykey (12, 12, "Wrong number");
              if (blind)
                {
                  sprintf (errTxt, "Diagram excluding: wrong number %i", k);
                  batch_error (errTxt, 1);
                }
              goto again;
            }
        }
      else
        k = 1;
      trim (frgm);

      j = locateinbase (frgm);
      jj = pseudop (j);
      if (!j || jj)
        {
          warnanykey (12, 12, "Unknown model particle");
          if (blind)
            {
              sprintf (errTxt, "Unknown model particle %s in the excluding list", frgm);
              batch_error (errTxt, 1);
            }
          goto again;
        }
      ntot++;
      if (ntot >= whohowMAX)
        {
          warnanykey (12, 12, "Too many items");
          if (blind)
            {
              batch_error ("Too many particles in the excluding list", 1);
            }
          goto again;
        }
      addlim (exclude_list, j, k, type);
    }
  free (items);
  return 1;
}


int
keep_diagrams (int *y0)
{
  int i;
  int jj, j;
  int k, ntot;
  int redres;
  int type = 1;
  char *n;
  char **items;
  shortstr errTxt;
  shortstr frgm;

  if (*y0 < maxRow ())
    (*y0)++;
   redres = 0;

again:
  prtcllist (redres,0);
  if (!blind) {
    shortstr tmpkeep_str;
    strcpy (tmpkeep_str, getKeepprtlist ());
    redres = input (*y0, "Keep diagrams with ", tmpkeep_str, 1, 70);
    setKeepprtlist (tmpkeep_str);
  } else {
    redres = KB_ENTER;
    redres = inkey();
  }
  switch (redres)
    {
      case KB_PAGED:
      case KB_PAGEU:
      case KB_UP:
      case KB_DOWN:
      case KB_F2:
      case KB_F3:
        goto again;
      case KB_F1:
        show_help ("s_ent_5");
        redres = 0;
        goto again;
      case KB_ESC:
        clrbox (1, 2, maxCol (), 24);
        (*y0) = (*y0) - 2;
        return 0;
    }

  nilprtcl (keep_list);
  ntot = 0;
  items = stritems (",", getKeepprtlist ());
  for (i = 0; items[i]; i++)
    {
      sscanf (items[i], "%[^,]", frgm);     /*  read of condition for keeping */
      n = strchr (frgm, '!');
      if (n)
        type = -1;
      else
        {
          n = strchr (frgm, '=');
          if (n)
            type = -2;
          else
            {
              n = strchr (frgm, '<');
              if (n)
                type = -3;
              else
                {
                  n = strchr (frgm, '>');
                  if (n)
                    type = 1;
                  else
                    type = 2;
                }
            }
        }

      if (n)
        {
          n[0] = 0;
          k = 0;
          sscanf (n + 1, "%d", &k);
          if (k < 0)
            {
              warnanykey (12, 12, "wrong number");
              if (blind)
                {
                  sprintf (errTxt, "Diagram keeping: wrong number: %i", k);
                  batch_error (errTxt, 1);
                }
              goto again;
            }
        }
      else
        k = 1;
      trim (frgm);

      j = locateinbase (frgm);
      jj = pseudop (j);
      if (!j || jj)
        {
          warnanykey (12, 12, "Unknown model particle");
          if (blind)
            {
              sprintf (errTxt, "Unknown model particle %s in keep list", frgm);
              batch_error (errTxt, 1);
            }
          goto again;
        }
      ntot++;
      if (ntot >= whohowMAX)
        {
          warnanykey (12, 12,  "Too many items");
          if (blind)
            {
              batch_error ("Too many particles in the keep list", 1);
            }
          goto again;
        }
      addlim (keep_list, j, k, type);
    }
  free (items);
  return 1;
}


static int
enter_decay_particle (void)
{
  int i, y0;
  int redres;
  int screen_choice;
  double m, m0;
  shortstr scrch;
  shortstr name;
  shortstr errTxt;

  y0 = ycons;
  if (!hadrons_are_initialized)
    {
      hadrons_are_initialized = 1;
      for (i = 0; i < MAXINOUT; i++)
        hadrons[i].name[0] = 0;
    }
  y0 = ycons;
  redres = -1;
  screen_choice = 1;

  strcpy (scrch, beam[0].h.name);
  /* artificial change of the default name e -> Z */
  if (0 == strcmp(scrch, "e")) strcpy (scrch, "Z");
again:
  if (1 == screen_choice) prtcllist (redres,2);
  else                    composite_prtcllist (redres);
  
  if (!blind) {
    redres = input (y0, "Enter decayed particle: ", scrch, 1, 70);
  } else {
    redres = KB_ENTER;
    redres = inkey();
  }
  switch (redres)
    {
    case KB_PAGED:
    case KB_PAGEU:
    case KB_UP:
    case KB_DOWN:
    case KB_F2:
      goto again;
    case KB_F3:
      screen_choice*=-1;
      redres = 0;
      goto again;
    case KB_F1:
      show_help ("s_ent_1");
      redres = 0;
      goto again;
    case KB_ESC:
      clrbox (1, 2, maxCol (), 24);
      return 0;
    }

  trim (scrch);

/* Check of the final particles (from the final state string)*/
  sscanf (scrch, "%[^, ]", name);
  if (strlen (name) > 6)
    {
      warnanykey (12, 12,  "Too long name");
      if (blind)
        {
          sprintf (errTxt, "Initial state: too long particle name %s", name);
          batch_error (errTxt, 1);
        }
      goto again;
    }
  if (strlen (name) == 3
      && name[1] == '*'
      && (name[2] == 'X' || name[2] == 'x') && isdigit (name[0]))
    {
/* X-particles... */
      
      int locn_x = getnx () + name[0] - '0';
      int locnout = getnout () + name[0] - '0';
      setnout (locnout);
      setnx (locn_x);
    }
  else
    {
/* Ordinary particles */
      if (enter_hadron (&y0, name, 0)) {
        warnanykey (12, 12, "Error in final state");
        goto again;
      }
    }

  copy_hadrons (&(beam[0].h), hadrons[0]);
  copy_hadrons (&(beam[1].h), hadrons[0]);
  m0 = prtclbase[hadrons[0].parton[0] - 1].mass;
  for (i = 1; i < hadrons[0].how; i++)
    {
      m = prtclbase[hadrons[0].parton[i] - 1].mass;
      if (m < m0)
        m0 = m;
    }
  beam[0].energy = m0;

  return y0++;
}


static int
enter_final_state (int *y0)
{
  int i, y00;
  int redres;
  int curh;
  int screen_choice;
  double inMass, outMass, m, m0;
  double e[2], p[2];
  shortstr name;
  shortstr instatech;
  shortstr errTxt;
  int locn_x;
  int locnout;

  char **items = NULL;

  scrcolor (FGmain, BGmain);
  for (i = *y0 + 1; i < 25; i++)
    {
      goto_xy (1, i);
      clr_eol ();
    }
  scrcolor (Red, BGmain);
  y00 = *y0;
  if (*y0 < maxRow ())
    {
      (*y0)++;
      y00++;
    }

  if (!hadrons_are_initialized)
    {
      hadrons_are_initialized = 1;
      for (i = 0; i < MAXINOUT; i++)
        {
          hadrons[i].name[0] = 0;
          hadrons[i].strfun[0] = 0;
        }
    }
  screen_choice = 1;
  redres = 0;
  
again:
  if (1 == screen_choice) prtcllist (redres,2);
  else                    composite_prtcllist (redres);

  if (2 == getnin ())
    sprintf (instatech, "Enter Final State: %s,%s -> ", beam[0].h.name, beam[1].h.name);
  else
    sprintf (instatech, "Enter  Final State: %s -> ", beam[0].h.name);

  if (!blind) {
    shortstr tmpfinalstatech;
    strcpy (tmpfinalstatech, getFinalstatech ());
    redres = input (y00, instatech, tmpfinalstatech, 1, 70);
    setFinalstatech (tmpfinalstatech);
  } else {
    redres = KB_ENTER;
    redres = inkey();
  }
  switch (redres)
    {
    case KB_PAGED:
    case KB_PAGEU:
    case KB_UP:
    case KB_F2:
    case KB_DOWN:
      goto again;
    case KB_F1:
      show_help ("s_ent_1");
      goto again;
    case KB_F3:
      screen_choice*=-1;
      redres = 0;
      goto again;
    case KB_ESC:
      clrbox (1, 2, maxCol (), 24);
      (*y0) = (*y0) - 2;
      return 0;
    }

  if (!items)
    free (items);
  items = stritems (" ,", getFinalstatech ());

  if (2 == getnin ())
    {
      curh = 2;
    }
  else
    {
      curh     = 1;
      setsqrtS (0.0);
      setRapidity (0.0);
    }

/* Check of the final particles (from the final state string)*/
  locn_x = 0;
  locnout = 0;
  setnout (locnout);
  setnx (locn_x);
  for (i = 0; items[i]; i++)
    {
      sscanf (items[i], "%[^, ]", name);
      if (strlen (name) > 7)
        {
          warnanykey (12, 12, "Too long name");
          if (blind)
            {
              sprintf (errTxt, "Final state: too long particle name %s", name);
              batch_error (errTxt, 1);
            }
          goto again;
        }

      if (strlen (name) == 3
          && name[1] == '*'
          && (name[2] == 'X' || name[2] == 'x') && isdigit (name[0]))
        {
/* X-particles... */
        locn_x += name[0] - '0';
        locnout += name[0] - '0';
        setnout (locnout);
        setnx (locn_x);
        }
      else
        {
/* Ordinary particles */
          if (curh == MAXINOUT - 1)
            {
              warnanykey (12, 12, "Too many particles in the process");
              if (blind)
                {
                  sprintf (errTxt, "Final state: too many particles in the process");
                  batch_error (errTxt, 1);
                }
              goto again;
            }
          if (enter_hadron (y0, name, curh))
            {
              warnanykey (12, 12, "Error in final state");
              (*y0) = y00;
              goto again;
            }
          locnout++;
          setnout (locnout);
          curh++;
        }
    }
  free (items);

  for (i = 0; i < getnin (); i++)
    {
      copy_hadrons (&(hadrons[i]), beam[i].h);
      e[i] = beam[i].energy;
      p[i] = sqrt (e[i] * e[i] - hadrons[i].mass * hadrons[i].mass);
    }

  if (getnout () < 2)
    {
      warnanykey (12, 12, "The number of outgoing particles has to be greater than 1");
      if (blind)
        {
          sprintf (errTxt, "Final state: the number of outgoing particles has to be greater than 1");
          batch_error (errTxt, 1);
        }
      (*y0) = y00;
      goto again;
    }

  for (curh = 0, inMass = 0, outMass = 0; curh < getntot () - getnx (); curh++)
    {
      m0 = prtclbase[hadrons[curh].parton[0] - 1].mass;
      for (i = 1; i < hadrons[curh].how; i++)
        {
          m = prtclbase[hadrons[curh].parton[i] - 1].mass;
          if (m < m0)
            m0 = m;
        }
      if (curh < getnin ())
        inMass += m0;
      else
        outMass += m0;
    }

  if (2 == getnin())
    {
      double locrapidity;
      double locsqrts = sqrt ((e[0] + e[1]) * (e[0] + e[1]) - (p[0] - p[1]) * (p[0] - p[1]));
      setsqrtS (locsqrts);
      if (locsqrts < 0.0)
        {
          locsqrts = hadrons[0].mass + hadrons[1].mass;
          setsqrtS (locsqrts);
        }
      locrapidity = atanh ((p[0] - p[1]) / (e[0] + e[1]));
      setRapidity (locrapidity);
      if (locsqrts <= inMass || locsqrts <= outMass)
        {
          warnanykey (12, 12, "Energy is not enough");
          if (blind)
            {
              sprintf (errTxt, "Final state: Energy is not enough");
              batch_error (errTxt, 1);
            }
          (*y0) = y00;
          goto again;
        }
    }
  else
    {
      if (inMass <= outMass)
        {
          warnanykey (12, 12, "This decay mode is forbidden");
          if (blind)
            {
              sprintf (errTxt, "Final state: this decay mode is forbidden");
              batch_error (errTxt, 1);
            }
          (*y0) = y00;
          goto again;
        }
    }
  return 1;
}


static int
enter_scattering_process (void)
{
  shortstr tmps;
  int y0 = ycons - 1;

  setnin (2);

again:
  if (!enter_final_state (&y0))
    return 1;

  if (!exclude_diagrams (&y0))
    {
      y0 = ycons - 1;
      goto again;
    }

  if (!keep_diagrams (&y0))
    {
      y0 = ycons - 1;
      goto again;
    }

  sprintf (tmps, "%s,%s -> %s", hadrons[0].name, hadrons[1].name, getFinalstatech ());
  setProcessch (tmps);
  return 0;
}


static int
enter_decay_process (void)
{
  shortstr tmps;
  int y0;

  setnin (1);

again0:
  y0 = enter_decay_particle();
  if (!y0)
    return 1;

again1:
  if (!enter_final_state (&y0))
    goto again0;                /*  'Esc' pressed  */

  if (!exclude_diagrams (&y0))
    {
      y0 = ycons;
      goto again1;              /*  'Esc' pressed  */
    }

  if (!keep_diagrams (&y0))
    {
      y0 = ycons;
      goto again1;              /*  'Esc' pressed  */
    }

  sprintf (tmps, "%s -> %s", hadrons[0].name, getFinalstatech ());
  setProcessch (tmps);
  return 0;
}


int
enter_process (int ProcessChoice)
{
  int res = 1;

  if (1 == ProcessChoice)
    {
      res = enter_decay_process ();
    }
  else if (2 == ProcessChoice)
    {
    again:
      res = enter_beams ();
      if (0 != res)
        {
          menuhelp ();
          return res;           /*  'Esc' pressed  */
        }
      res = enter_scattering_process ();
      if (0 != res)
        {
          menuhelp ();
          goto again;           /*  'Esc' pressed  */
        }
    }
  return res;
}
