/*
* Copyright (C) 1997, Alexander Pukhov 
* Copyright (C) 2001-2008, CompHEP COllaboration
*------------------------------------------------------
* $Id: cut.c,v 1.6 2003/11/08 19:46:05 kryukov Exp $
*
* $Log: cut.c,v $
* Revision 1.6  2003/11/08 19:46:05  kryukov
* To bring into according the usage of messanykey and warnanykey functions.
*
* Revision 1.5  2003/06/25 18:46:41  kryukov
* *** empty log message ***
*
* Revision 1.4  2003/04/22 09:01:18  kryukov
* Apply indent to improve readability of files
*
* Revision 1.3  2003/04/20 08:54:39  kryukov
* Remove some misprints
*
*/
#include <math.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>

#include "service2/include/chep_limits.h"
#include "service2/include/parser.h"
#include "service2/include/read_func.h"
#include "service2/include/syst.h"
#include "chep_crt/include/crt_util.h"
#include "out_ext.h"

#include "rd_num.h"
#include "const.h"
#include "phys_val.h"
#include "cut.h"

invcut_ invcut_1[60];

table cutTab =
{"*** Table ***", " Cuts  ",
 "  Parameter  |> Min bound <|> Max bound <|", NULL};

int cutnumber;

static void 
cutInit (void)
{
  invcut_1[0].key = 0;
  cutnumber = 0;
}


static int 
addcut (char key, char *lv, int minonw, int maxonw, double cvminw, double cvmaxw)
{
  int ncut;

  for (ncut = 0; invcut_1[ncut].key; ncut++)
    {
      if (key == invcut_1[ncut].key && !strcmp (lv, invcut_1[ncut].lvinvc))
        {
          if (minonw && (!invcut_1[ncut].minon || cvminw > invcut_1[ncut].cvmin))
            {
              invcut_1[ncut].minon = 1;
              invcut_1[ncut].cvmin = cvminw;
            }
          if (maxonw && (!invcut_1[ncut].maxon || cvmaxw < invcut_1[ncut].cvmax))
            {
              invcut_1[ncut].maxon = 1;
              invcut_1[ncut].cvmax = cvmaxw;
            }
          return 0;
        }
    }
  if (ncut >= 59)
    return 2;

  invcut_1[ncut].key = key;
  strcpy (invcut_1[ncut].lvinvc, lv);
  invcut_1[ncut].minon = minonw;
  invcut_1[ncut].maxon = maxonw;
  invcut_1[ncut].cvmin = cvminw;
  invcut_1[ncut].cvmax = cvmaxw;
  invcut_1[ncut + 1].key = 0;
  return 0;
}


int WriteCuts (FILE * nchan) {
  fprintf (nchan, "\n");
  writetable0 (&cutTab, nchan);
  return 0;
}


int ReadCuts (FILE * nchan) {
  fscanf (nchan, "\n");
  return readtable0 (&cutTab, nchan);
}

int get_cutn (void) {
  return cutnumber;
}


int fillCutArray (void) {
  linelist ln = cutTab.strings;
  int lineNum = 0;
  int minOn;
  int maxOn;
  char keyChar;
  midstr cutStr;
  midstr minStr;
  midstr maxStr;
  shortstr fieldName;

  cutInit ();
  while (ln != NULL)
    {
      double min_ = 0.0;
      double max_ = 0.0;
      vshortstr lv;
      int i, k;

      cutnumber++;
      cutStr[0] = 0;
      minStr[0] = 0;
      maxStr[0] = 0;
      lineNum++;
      sscanf (ln->line, "%[^|]%*c%[^|]%*c%[^|]", cutStr, minStr, maxStr);

/*================ MIN bound ============*/
      strcpy (fieldName, "Wrong field 'Min. bound'");
      i = 0;
      while (minStr[i] == ' ')
        i++;
      minOn = (minStr[i] != 0);
      if (minOn && calcExpression (minStr, rd_num, &min_))
        goto errorExit;

/*============ Parameter ===========*/
      strcpy (fieldName, "Wrong field 'Parameter'");
      if (!checkPhysVal (cutStr, &keyChar, lv))
        goto errorExit;

/*================== MAX bound ==========*/
      strcpy (fieldName, "Wrong field 'Max bound'");
      i = 0;
      while (maxStr[i] == ' ')
        i++;
      maxOn = (maxStr[i] != 0);
      if (maxOn && calcExpression (maxStr, rd_num, &max_))
        goto errorExit;

/* =========== fill array ========== */

      if (keyChar != 'U')
        SORTARR (lv, strlen (lv));
      if (keyChar == 'A')
        {
          int tmpOn = minOn;
          double min = max_;
          double max = min_;
          keyChar = 'C';
          minOn = maxOn;
          maxOn = tmpOn;
          if (minOn)
            min_ = cos (min * (M_PI) / 180);
          if (maxOn)
            max_ = cos (max * (M_PI) / 180);
        }
      if (keyChar == 'M')
        {
          keyChar = 'S';
          if (minOn)
            min_ = min_ * fabs (min_);
          if (maxOn)
            max_ = max_ * fabs (max_);
        }
      if ((keyChar == 'S'))
        coninv_ (lv);

      if (minOn || maxOn)
        {
          k = addcut (keyChar, lv, minOn, maxOn, min_, max_);
          if (k == 2)
            {
              strcpy (fieldName, "Too many cuts ");
              goto errorExit;
            }
        }
      ln = ln->next;
    }
  return 0;

errorExit:
  sprintf (errorText, " Error in Cut table line %d .\n%s.", lineNum, fieldName);
  warnanykey (2, 10, errorText);
  return 1;
}


int rancor_ (double *vmin, double *vmax, double shift, double fmult, int nn) {
  static double vnew;

  if (nn == 0)
    return 0;

  if (invcut_1[nn - 1].minon)
    {
      vnew = (invcut_1[nn - 1].cvmin - shift) * fmult;
      if (fmult > 0.)
        *vmin = MAX (*vmin, vnew);
      else
        *vmax = MIN (*vmax, vnew);
    }
  if (invcut_1[nn - 1].maxon)
    {
      vnew = (invcut_1[nn - 1].cvmax - shift) * fmult;
      if (fmult > 0.)
        *vmax = MIN (*vmax, vnew);
      else
        *vmin = MAX (*vmin, vnew);

    }
  return 0;
}


double calcCutFactor (void) {
  int i;
  double val;

  for (i = 0; invcut_1[i].key; i++)
    {
      val = calcPhysVal (invcut_1[i].key, invcut_1[i].lvinvc, "");
      if (invcut_1[i].minon && (val < invcut_1[i].cvmin))
        return 0;
      if (invcut_1[i].maxon && (val > invcut_1[i].cvmax))
        return 0;
    }
  return 1;
}


int printDetailsOfCutFactor (void){
  int i;
  double val;

  for (i = 0; invcut_1[i].key; i++)
    {
      val = calcPhysVal (invcut_1[i].key, invcut_1[i].lvinvc, "");
      if (invcut_1[i].minon)
        {
          fprintf (stderr, "%c: min = %f, val = %f\n", invcut_1[i].key, invcut_1[i].cvmin, val);
        }
      if (invcut_1[i].maxon)
        {
          fprintf (stderr, "%c: max = %f, val = %f\n", invcut_1[i].key, invcut_1[i].cvmax, val);
        }
    }
  return 0;
}
