/*
* Copyright (C) 1997, Alexander Pukhov
* Copyright (C) 2001-2007, CompHEP Collaboration
*------------------------------------------------------
* $Id: s_comphep.c,v 1.21 2003/11/02 00:22:40 sherstnv Exp $
*
* $Log: s_comphep.c,v $
* Revision 1.21  2003/11/02 00:22:40  sherstnv
* "LOCK mechanism" is restored
*
* Revision 1.20  2003/10/01 14:07:55  sherstnv
* Bug has been fixed in working of CompHEP with SUSY models
* if cernlib is not found.
*
* Revision 1.19  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.18  2003/06/27 12:46:05  sherstnv
* Final and working version ov symb_batch.pl script.
* All necessary changes have been done in s_comphep.c and Makefiles
*
* Revision 1.17  2003/06/26 15:51:43  sherstnv
* symp_batch.pl script is customized to new CompHEP options/new
* n_comphep creation schime.
*
* Revision 1.16  2003/06/25 18:46:42  kryukov
* *** empty log message ***
*
* Revision 1.15  2003/06/15 15:47:43  kryukov
* 1) c-compile position automatically invoke c-code generation
* 2) A little bit improve sompilation of n_comphep
*
* Revision 1.14  2003/04/22 09:01:20  kryukov
* Apply indent to improve readability of files
*
* Revision 1.13  2003/04/21 20:09:48  kryukov
* Misprints and English improve. Special thanks M.D.
*
* Revision 1.12  2003/04/21 16:10:40  kryukov
* New compilation scheme for n_comphep
*
* Revision 1.11  2003/04/21 11:11:19  kryukov
* 1) Reshufle write result menu
* 2) Optimize n_comphep compilation
*
* Revision 1.10  2003/04/13 13:15:45  kryukov
* Insert Id tag
*
* Revision 1.9  2003/04/09 13:17:10  kryukov
* Use xterm to output of make during n_comphep buil.
*
* Revision 1.8  2003/04/02 20:58:35  sherstnv
* *** empty log message ***
*
* Revision 1.5  2003/03/01 09:21:52  sherstnv
* #model bug: structure function calls are moved from f*.c files to sqme.c file
* and small reorganizing of c-structures in header files
*
* Revision 1.4  2003/01/25 17:21:20  kryukov
* no message
*/
#include <unistd.h>

#include "chep_crt/include/chep_crt.h"
#include "service2/include/tptcmac.h"
#include "service2/include/os.h"
#include "service2/include/read_func.h"
#include "service2/include/syst2.h"
#include "service2/include/s_files.h"
#include "service2/include/lbl.h"

#include "physics.h"
#include "screen.h"
#include "constr.h"
#include "read_mdl.h"
#include "sos.h"
#include "process.h"
#include "squar.h"
#include "r_code.h"
#include "c_out.h"
#include "red_out.h"
#include "math_out.h"
#include "form_out.h"
#include "symbolic.h"
#include "m_utils.h"
#include "ini_ses.h"
#include "amplitudes.h"

static int errorcode = 0;
static int c_make (char *prefix, char *suffix, int n);

int main (int argc, char **argv) {
  int n;
  int exitlevel;
  long end = -1;
  FILE * LOCK;
  FILE * fverion;
  longstr _pathtocomphep;
/*===================================
if (exitlevel == odd) { don't write chep_label, 
                        the same as a exitlevel--}
0 - Fisrt start
2 - Feynman diagrams menu
4 - Feynman diagrams calculation                        
6 - Squared diagrams menu
8 - Squared diagrams calculation
==========================================================*/
/* 0-Start; 1-Restart; 2-Heap Error,3-Edit Model,4-UserBreak */

  void *pscr1 = NULL;
  void *pscr2 = NULL;
  void *pscr3 = NULL;
  void *pscr4 = NULL;
  void *pscr5 = NULL;
  int k1 = 1, k2 = 1, k3 = 1, k4 = 1, k5 = 1;
  int ProcessChoice = 2;
  int c_prog_ok = 0;
  int diagshow = 0;
  int firstdiag = 1;
  int lastdiag = 100000000;
  char * p;
  shortstr theversion;
  midstr pathtoversionfile;
/* menu variables */

  p = getenv ("COMPHEP");
  if (!p) {
    finish ("Environment variable COMPHEP is not defined.\n");
  }
  strcpy (_pathtocomphep, p);
  strcpy (_pathtouser, defaultPath);

  for (n = 1; n < argc; n++) {
    if (strcmp (argv[n], "-blind") == 0) {
      blind = 1;
      inkeyString = argv[n + 1];
      n++;
    }

    if (strcmp (argv[n], "-diagfirst") == 0) {
      int tmp;
      int err = sscanf (argv[n + 1], "%d", &tmp);
      if (1 == err) firstdiag = tmp;
      n++;
    }

    if (strcmp (argv[n], "-diaglast") == 0) {
      int tmp;
      int err = sscanf (argv[n + 1], "%d", &tmp);
      if (1 == err) lastdiag = tmp;
      n++;
    }

    if (strcmp (argv[n], "-diagshow") == 0) {
      diagshow = 1;
    }

    if (strcmp (argv[n], "-status") == 0) {
      int ncalc = 0;
      int ndel = 0;
      int nrest = 0;
      int ntot = 0;
      long nrecord;
      shortstr txt;
      int nncalc, nndel, nnrest;
      FILE * menuqtmp = fopen (MENUQ_NAME, "rb");
      int subproc = restoreent_dump();
      for (nsub = 1; nsub <= subproc; nsub++)
        {
          rd_menu (menuqtmp, 2, nsub, txt, &nndel, &nncalc, &nnrest, &nrecord);
          ncalc += nncalc;
          ndel += nndel;
          nrest += nnrest;
          ntot += nndel + nncalc + nnrest;
        }
      fclose(menuqtmp);
      fprintf(stdout, "Status: calculated %i diagrams from %i (deleted %i)\n", ncalc, ntot - ndel, ndel);
      exit(0);
    }
  }

  LOCK = fopen ("LOCK", "a");
  if (LOCK != NULL) end = ftell (LOCK);
  if (end == 0) {
    fprintf (LOCK, "CompHEP is already started here, process number %i\n", getpid ());
    fflush (LOCK);
    fclose (LOCK);
  } else {
     fprintf (stderr, "\nError: CompHEP program was already launched and not finished normaly.\n");
     fprintf (stderr, "         Remove the LOCK file to start the CompHEP anyway.\n");
//     exit (100);
  }

  sprintf (pathtouser, "%s%c", _pathtouser, d_slash);
  sprintf (pathtocomphep, "%s%c", _pathtocomphep, d_slash);
  sprintf (pathtohelp, "%shelp%c", pathtocomphep, f_slash);
  outputDir = "results/";

  sprintf (pathtoversionfile, "%sversion", pathtocomphep);
  fverion = fopen(pathtoversionfile, "r");
  if (fverion != NULL) {
    fscanf (fverion, "%s", theversion);
  } else {
    strcpy (theversion, "unknown");
  }
  setversion (theversion);

  strcpy (theversion, getname ());
  start1 (theversion, scat ("%s%s", pathtocomphep, "icon"), "comphep.ini;../comphep.ini;[-]comphep.ini");

  fillModelMenu ();

  f3_key [0] = f3_key_prog;
  f3_mess[0] = "Model";
  f3_key [1] = f4_key_prog;
  f3_mess[1] = "Diagrams";
  f3_key [2] = f5_key_prog;
  f3_mess[2] = "Switches";
  f3_key [3] = f6_key_prog;
  f3_mess[3] = "Results";
  f3_mess[4] = "Del";
  f3_mess[5] = "UnDel";
  f3_key [6] = f9_key_prog;
  f3_mess[6] = "Quit";

  restoreent (&exitlevel);
  if (!exitlevel & 1)
    cheplabel ();
  exitlevel = 2 * (exitlevel / 2);
  if (exitlevel >= 2) {
    int num = getModelNumberSymb();
    readModelFiles (num, "models");
    loadModel (FALSE);
    modelinfo ();
    processinfo ();
    diagramsinfo ();
    k1 = num;
  }

  if (exitlevel >= 6) {
    sq_diagramsinfo ();
  }

  switch (exitlevel)
    {
    case 2:
      goto label_41;
    case 4:
      goto label_41;
    case 6:
      goto label_50;
    case 8:
      goto restart2;
    }

label_20:                    /* Menu2 :ModelMenu */
  f3_key[0] = NULL;          /* models */
  f3_key[1] = NULL;          /* diagrams */
  menulevel = 0;
  menuhelp ();
  for (;;) {
    k1 = getModelNumberSymb();
    menu1 (52, 4, "", modelmenu, "s_1", &pscr1, &k1);
    setModelNumberSymb (k1);
    if (k1 == 0) {
      if (mess_y_n (56, 4, "Quit session")) {       /* Exit */
        saveent (menulevel);
        goto exi;
      }
    } else if (k1 > maxmodel) {
        clrbox (1, 4, 55, 18);
        if (makenewmodel ())
          modelinfo ();
        menuhelp ();
      } else if (k1 > 0) {
          readModelFiles (k1, "models");
          put_text (&pscr1);
          goto label_30;
        }
  }

label_30:                       /*  Menu3:Enter Process  */
  f3_key[0] = NULL;
  f3_key[1] = NULL;


  menulevel = 0;
  modelinfo ();
  k2 = 2;
/* preload, for proper working of beams table edit and 
           check of ability to work in CompHEP in SUSY models*/
  if(!loadModel (FALSE)) goto label_20; 
  do {
    menu1 (51, 6, "", "\032"
           " Enter Decay Process      "
           " Enter Scattering Process "
           " Edit Beams Table         "
           " Edit Str. Functions Table"
           " Edit Model               "
           " Delete Model             ", "s_2_*", &pscr2, &k2);
    switch (k2)
      {
      case 0:                      /*  'Esc'  */
        goto_xy (1, 1);
        clr_eol ();
        goto label_20;

      case 1:
        ProcessChoice = 1;
        break;
      case 2:
        ProcessChoice = 2;
        break;
      case 3:
        editBeams ();
        break;
      case 4:
        editStrFuns ();
        break;
      case 5:
        editModel (1);
        break;
      case 6:                      /*  Delete  */
        if (deletemodel (getModelNumberSymb())) {
          goto_xy (1, 1);
          clr_eol ();
          setModelNumberSymb(1);
          fillModelMenu ();
          goto label_20;
        } else {
          int num = getModelNumberSymb();
          readModelFiles (num, "models");
        }
      }
  } while (k2 > 2);

  loadModel (FALSE);


  f3_key[0] = NULL;
  f3_key[1] = NULL;
  menulevel = 0;

label_32:
  errorcode = enter_process (ProcessChoice);  /*  Enter process  */

  if (errorcode != 0)            /*  'Esc' pressed  */
    {
      menuhelp ();
      goto label_30;
    }

  errorcode = construct ();     /*  unSquared diagrams  */
  if (errorcode) {
    if (blind) {
      batch_error ("Processes of this type are absent", 1);
    } else {
      clrbox (1, 19, 80, 24);
      goto label_32;	  /*  processes are absent  */
    }
  } else {
    if (!blind) {
      if (!viewresults (1))
        goto label_32;
    }
    clr_scr (FGmain, BGmain);
    modelinfo ();
    processinfo ();
    diagramsinfo ();
    goto label_41;
  }

label_40:                       /*  Menu4: Squaring,... */
  clr_scr (FGmain, BGmain);
  modelinfo ();
  processinfo ();
  diagramsinfo ();
  
label_41:
  f3_key[0] = f3_key_prog;
  f3_key[1] = NULL;
  menulevel = 2;
  k3 = 1;
  if (diagshow) {
    do
    {
      menu1 (56, 4, "",
             "\026"                    /* Number of columns */
             " View diagrams        ",
             "s_squa_*", &pscr3, &k3);
      switch (k3)
        {
        case 0:         /*  Esc  */
          warnanykey (12, 12, "Other menus are unavailable!");
        case 1:         /*  unSquared process menu   */
          viewfeyndiag (1);
          break;
        }
    }
    while (k3 != 2);
  } else { 
    do
    {
      menu1 (56, 4, "",
             "\026"                    /* Number of columns */
             " View diagrams        "
             " Square diagrams      ",
             "s_squa_*", &pscr3, &k3);
      switch (k3)
        {
        case 0:         /*  Esc  */
          clrbox (1, 2, 55, 11);
          menuhelp ();
          goto label_32;
        case 1:         /*  unSquared process menu   */
          viewfeyndiag (1);
          break;
        }
    }
    while (k3 != 2);
  }

/*  diagrams  */
  if (!squaring ())
    goto label_40;              /*  process are absent  */

  clear_tmp ();

  saveent (menulevel);
  restoreent (&exitlevel);

label_50:                       /*  Menu5: View squared diagrams.....   */

  f3_key[0] = f3_key_prog;
  f3_key[1] = f4_key_prog;

  menulevel = 6;
  clr_scr (FGmain, BGmain);
  modelinfo ();
  processinfo ();
  diagramsinfo ();
  sq_diagramsinfo ();           /*   ????????   */

  k4 = 1;
  for (;;)
    {
      if (!continuetest ())
        {
          menu1 (56, 4, "", "\026"
                 " View squared diagrams"
                 " Symbolic calculations"
                 " REDUCE program       "
                 " Make n_comphep       "
/*                 " FORM program         "   */    /* Modyfied by Bunichev */
                 ,"s_calc_*", &pscr4, &k4);
          switch (k4)
            {
            case 0:
              if (mess_y_n (50, 3, "Return to previous menu?"))
                {
                  goto label_40;
                }
              break;

            case 1:
              viewsqdiagr ();
              put_text (&pscr4);
              break;

            case 2:             /*  Compute all diagrams   */
            restart2:
              f3_key[0] = f3_key_prog;
              f3_key[1] = f4_key_prog;

              menulevel = 6;
              calcallproc (firstdiag, lastdiag);
              sq_diagramsinfo ();
              put_text (&pscr4);
              c_prog_ok = 0;
              break;
            case 3:
              mk_reduceprograms ();
              break;
            case 4:
              saveent (menulevel);
              finish ("\nEnd of CompHEP symbolical session.\n");
              return 24;
            case 5:
/*
              mk_formprograms();
              run_formprograms();
*/
              break;
            }
        }
      else
        {
          saveent (6);

        label_60:               /*  Menu5: View squared diagrams.....   */
          menu1 (56, 4, "", "\026"
                 " View squared diagrams"
                 " Write  results       "
                 " C-compiler           "
                 " Enter new process    "
                 ,"s_out_*", &pscr4, &k4);
          switch (k4)
            {
            case 0:
              if (mess_y_n (50, 3, "Return to previous menu?"))
                {
                  system ("make -s -C results clean");
                  goto label_40;
                }
              break;

            case 1:
              viewsqdiagr ();
              put_text (&pscr4);
              break;
            case 2:
              k5 = 1;
              menu1 (56, 6, "", "\026"
                     " C code               "
                     " FORM code            "
                     " REDUCE code          "
                     " MATHEMATICA code     ", NULL, &pscr5, &k5);

              switch (k5)
                {
                case 1: /*  c_code  */
                  c_prog ();
                  {
		    int n_diag = get_diagnumber ();
                    c_make ("f", ".c", n_diag);
                  }
		  c_prog_ok=1;
                  break;
                case 2:
                  makeFormOutput ();
                  break;
                case 3:
                  makeReduceOutput ();
                  break;
                case 4:
                  makeMathOutput ();
                  break;
                }               /* switch(k5) */
              put_text (&pscr5);
              break;

            case 3:
              {
                int n_sub, n_diag, t1, t2, t3, err;
                char command[STRSIZ];
                char *n_chep;
                searchrec s;

                if (!c_prog_ok) {
                  c_prog();
                  c_prog_ok=1;
                }
                diag_stat (2, &n_sub, &t1, &t2, &t3);
                n_diag = get_diagnumber ();

                n_chep = scat ("%sresults%c%s", pathtouser, f_slash, "n_comphep.exe");
                if (find_first (n_chep, &s, 0)) {
                  c_make ("f", ".c", n_diag);
                  if(!blind) {
                    int err1 = system ("bash -c 'make -C results all >&make_gui.log'");
                    int err2 = system ("bash -c 'make -C results makemodeltmp 1>>make_gui.log 2>>make_gui.log'");
                    err = err1 + err2;
                  } else {
                    int err1 = system ("bash -e make -C results blind >& symb_batch.log");
                    int err2 = system ("bash -e make -C results makemodeltmp 1>>symb_batch.log 2>>symb_batch.log'");
                    err = err1 + err2;
                  }
                } else {
                  fprintf (stdout, "Old n_comphep is deleted!");
                  system("touch results/ffile_0");
                  if(blind) {
		    err = system ("bash -c 'make -C results blindlink 1>>symb_batch.log 2>>symb_batch.log'");
                  } else {
		    err = system ("bash -c 'make -C results link 1>>make_gui.log 2>>make_gui.log'");
                  }
		}

                if (err != 0) {
                  if (blind) {
		    fprintf (stderr, "\nError during link of n_comphep! See symb_batch.log\n");
                    batch_error ("make error", 1);
		  } else {
		    fprintf (stderr, "\nError during link of n_comphep! See make_gui.log\n");
		  }
                  goto label_60;
                }
                {
                  midstr procname;
                  get_first_subprocname (procname);
                }
                i_w_sess_ ();
                if (!blind) {
                  sprintf (command, "%s/launch_n_comphep c &", _pathtocomphep);
                  system (command);
		}
              }
              break;
            case 4:
              put_text (&pscr4);
              put_text (&pscr3);
              clrbox (1, 2, 55, 11);
              menuhelp ();
              goto label_30;

            }                   /*case */
        }

    }

exi:
  finish ("End of CompHEP symbolical session.");
  return 0;
}

static int c_make (char *prefix, char *suffix, int n) {
  int i, j, max;
  int de, ost;
  int base = 100, num = 0;
  char filename[100], source_files[100 * STRSIZ];
  char ffile[STRSIZ];
  FILE *fi;

  ost = n % base;
  if (!ost)
    de = n / base;
  else
    de = 1 + n / base;

  for (j = 0; j < de; j++) {
    sprintf (ffile, "results/ffile_%d", j);
    strcpy (source_files, "");
    max = base;
    if (j == de - 1 && ost) {
      max = ost;
    }
    for (i = 0; i < max; i++) {
      num++;
      sprintf (filename, "%s%i%s ", prefix, num, suffix);
      strcat (source_files, filename);
    }

    fi = fopen (ffile, "w");
    if (!fi) {
      fprintf (stderr, "***** c_make: Cannot open ffile=%s. ABORT\n", ffile);
      exit (99);
    }
    fprintf (fi, "%s", source_files);
    fclose (fi);
  }

  return 0;
}
