/*
* Copyright (C) 1997, Alexander Pukhov 
* with changes by V.Ilyin for #-models, 6 Sept 2000
* Copyright (C) 2001-2007, CompHEP Collaboration
* ------------------------------------------------------
* $Id: sf_pdf.c,v 1.9 2003/07/01 14:29:38 kryukov Exp $
*
* $Log: sf_pdf.c,v $
* Revision 1.9  2003/07/01 14:29:38  kryukov
* Now list of pdf's display from 1 line
*
* Revision 1.8  2003/07/01 13:53:09  sherstnv
* QCD Lambda is taken from cteq** file now
* The strfun dir contains *.tbl - original cteq
* and *.pdf - our format of cteq.
*
* Revision 1.7  2003/06/25 18:46:41  kryukov
* *** empty log message ***
*
* Revision 1.6  2003/04/22 09:01:19  kryukov
* Apply indent to improve readability of files
*
* Revision 1.5  2003/04/19 18:32:30  kryukov
* Change format menu function. Now it must return int value (position of selection)
*
*/

#include <stdio.h>
#include <string.h>
#include "service2/include/os.h"
#include "service2/include/files.h"
#include "chep_crt/include/chep_crt.h"
#include "out_ext.h"

#include "num/include/tag_reader.h"
#include "num/include/tag_parser.h"
#include "num/include/subproc.h"
#include "num/include/strfun.h"
#include "num/include/pdf.h"
#include "num/include/sf_pdf.h"

static shortstr pdfName[2] = {"PDF:OFF", "PDF:OFF"};
static shortstr pdfBeam[2] = {"parton", "parton"};

static pdfStr pdfData[9];       /*  #-mdl */

int CERNpdf_number (char *pdf, char *ver, int *PDFid, int *PDFgroup) {
  if (!strcmp (pdf, "CTEQ") ||
    !strcmp (pdf, "Cteq") ||
    !strcmp (pdf, "cteq")) {
    if (!strcmp (ver, "4m") || !strcmp (ver, "4M")){
      *PDFid = 34;
      *PDFgroup = 4;
      return 0;
    }
    if (!strcmp (ver, "4l") || !strcmp (ver, "4L")){
      *PDFid = 32;
      *PDFgroup = 4;
      return 0;
    }
    if (!strcmp (ver, "5m1") || !strcmp (ver, "5M1")){
      *PDFid = 53;
      *PDFgroup = 4;
      return 0;
    }
    if (!strcmp (ver, "5m") || !strcmp (ver, "5M")){
      *PDFid = 48;
      *PDFgroup = 4;
      return 0;
    }
    if (!strcmp (ver, "5l") || !strcmp (ver, "5L")){
      *PDFid = 46;
      *PDFgroup = 4;
      return 0;
    }
    if (!strcmp (ver, "6d") || !strcmp (ver, "6D")){
      *PDFid = 56;
      *PDFgroup = 4;
      return 0;
    }
    if (!strcmp (ver, "6l") || !strcmp (ver, "6L")){
      *PDFid = 55;
      *PDFgroup = 4;
      return 0;
    }
    if (!strcmp (ver, "6m") || !strcmp (ver, "6M")) {
      *PDFid = 57;
      *PDFgroup = 4;
      return 0;
    }
    if (!strcmp (ver, "6l1") || !strcmp (ver, "6L1")) {
      *PDFid = 58;
      *PDFgroup = 4;
      return 0;
    }
  }
  return 1;
}

int p_pdf (char *p_name) {
  int val = 0;
  pdfList * list = NULL;
  comphepPdfList (p_name, &list);
  if (list) {
    delPdfList (list);
    val = 1;
  }
  return val;
}

void info_pdf (int i, Str_fun_Info * info) {
  int PDFid;
  int PDFgr;
  int unknown_pdf;

  strcpy (info->pdf_name, "CTEQ");
  info->prt_mass = 0.938;
  strcpy (info->prt_name, pdfBeam[i]);
  strcpy (info->version, pdfName[i] + 4 + 4); /* remove 'PDF:' and 'cteq' */

  unknown_pdf = CERNpdf_number (info->pdf_name, info->version, &PDFid, &PDFgr);
  if (unknown_pdf) {
    fprintf (stderr, "*** Uknown PDF %s or its version %s", info->pdf_name, info->version);
    exit (1);
  }

  info->N_extra_commands = 2;
  snprintf (info->extra_commands[0], 7 + intlen (PDFid), "PDFid=%i", PDFid);
  snprintf (info->extra_commands[1], 7 + intlen (PDFgr), "PDFgr=%i", PDFgr);
  info->PDFLIBset = PDFid;
  info->PDFLIBgroup = PDFgr;
  info->LHAPDFset = 0;
  info->LHAPDFmember = 0;
}

void n_pdf (int i, char * beam, char * pdf) {
  i--;
  if (strlen(pdfName[i])) {
    strcpy (pdf, pdfName[i]);
  } else {
    strcpy (pdfBeam[i], "parton");
    strcpy (pdf, "PDF:OFF");
  }
  strcpy (beam, pdfBeam[i]);
}

int r_pdf (int i, char * name) {
  int ret_code = 0;

  if (strstr (name, "PDF:")) {
    int j;
    int sepa;
    int len = strlen(name);
    for (j = 0; j < len; ++j) {
      if ('(' == name[j]) sepa = j;
    }
    --i;
    strncpy (pdfName[i], name, sepa);   /* PDF:pdfname(beamname) --> extract pdfname*/
    strncpy (pdfBeam[i], name + sepa + 1, len - sepa - 2); /* PDF:pdfname(beamname) --> extract beamname*/
    pdfName[i][sepa] = 0;
    pdfBeam[i][len - sepa - 2] = 0;
    trim(pdfName[i]);
    trim(pdfBeam[i]);
    ret_code = 1;
  }
  return ret_code;
}


/* initialization function 
  i - beam number
  be - return value (???)
  mass - beam particle mass
  return the string number in PDF menu 
*/
int be_pdf (int i, double * be, double * mass) {
  char p_name[20];
  pdfList *list = NULL;
  pdfList *list_;
  int ret_code = 0;
  static int first[2] = {1, 1};
  int ip, xip;                  /* #-mdl */
  char *xpar;                   /* #-mdl */
  xpar = "anti-proton";         /* #-mdl */
  shortstr tmpname;

  i--;
  if (!first[i])
    freePdfData (pdfData + i);

  pinf_ (proces_1.nsub, i + 1, p_name, NULL);

  comphepPdfList (p_name, &list);
  list_ = list;
  sprintf (tmpname, "%s(%s)", pdfName[i] + 4, pdfBeam[i]);
  while (list_ && ret_code == 0) {
    if (!strcmp (list_->name, tmpname)) {
      if (i == 0 || !pdfName[0])
        for (ip = 2; ip < 9; ip++){
          xip = ip;
          if (strstr (pdfBeam[i], xpar)) {
            if (ip == 8) xip = 4;
            if (ip == 4) xip = 8;
            if (ip == 7) xip = 5;
            if (ip == 5) xip = 7;
          }
          getPdfData (list_->pathfile, list_->file, xip, pdfData + ip);   /* #-mdl */
        }
      ret_code = !getPdfData (list_->pathfile, list_->file, list_->position, pdfData + i);
    }
    list_ = list_->next;
  }
  if (list) {
    delPdfList (list);
  }

  if (ret_code) {
    first[i] = 0;
    if (pdfData[i].alpha)
      alphaMode = i + 1;
    if (pdfData[i].pow1 < 0) {
      *be = pdfData[i].pow1 + 1;
    } else {
      *be = 1.;
    }
    *mass = pdfData[i].mass;
  }

  return ret_code;
}

/* graphical interface. should be excluded! */
/* return the string number in PDF menu */
int pdf_pdf (int i) {
  int WIDTH = 30;
  int k = 0;
  vshortstr p_name;
  char * menustring = NULL;
  void *pscr = NULL;
  pdfList *list = NULL;
  pdfList *list_ = NULL;

  pinf_ (proces_1.nsub, i, p_name, NULL);
  comphepPdfList (p_name, &list_);
  if (list_) {
    list = list_;
  } else {
    return 0;
  }

  for (list_ = list; list_; list_ = list_->next) ++k;
  menustring = malloc (2 + WIDTH * k);
  menustring[0] = WIDTH;
  menustring[1] = 0;
  for (list_ = list; list_; list_ = list_->next) {
    sprintf (menustring + strlen (menustring), " PDF:%-*.*s", WIDTH - 5, WIDTH - 5, list_->name);
  }

  k = 0;
  menu1 (80 - 4 - WIDTH, 7, "", menustring, "", &pscr, &k);
  if (k) {
    int j;
    int l = k - 1;
    int sepa, len;
    for (list_ = list; l; --l) list_ = list_->next;
    len = strlen(list_->name);
    for (j = 0; j < len; ++j) {
      if ('(' == list_->name[j]) sepa = j;
    }
    --i;
    strcpy (pdfName[i], list_->name);
    sprintf (pdfName[i], "PDF:%s", list_->name);
    pdfName[i][sepa + 4] = 0;
    strcpy (pdfBeam[i], list_->name + sepa + 1);
    pdfBeam[i][len - sepa - 2] = 0;
    trim(pdfName[i]);
    trim(pdfBeam[i]);
  }

  free (menustring);
  put_text (&pscr);
  delPdfList (list);
  return k;
}

int beam_pdf (int i) {
  int key = 0;
  void *pscr = NULL;
  shortstr previous;
  char strmen[] = "*" 
                  " parton      "
                  " proton      "
                  " anti-proton ";

  strmen[0] = (strlen (strmen) -1) / 3;
  --i;
  strcpy(previous, pdfBeam[i]);
  menu1 (64, 7, "", strmen, "n_beam_*", &pscr, &key);

  if (key) {
    switch (key) {
      case 1:
        strcpy (pdfName[i], "OFF");
        strcpy (pdfBeam[i], "parton");
        break;
      case 2:
        strcpy (pdfBeam[i], "proton");
        break;
      case 3:
        strcpy (pdfBeam[i], "anti-proton");
        break;
    }
  }
  if (0 == key && !strcmp("parton", pdfBeam[i])) {
    strcpy (pdfName[i], "OFF");
    sf_num[i] = 0;
  }
  if (!strcmp("proton", pdfBeam[i]) && !strcmp("parton", previous)) {
    strcpy (pdfName[i], "PDF:undefined");
  }

  return 0;
}


/* return pdf value of i-th parton in a point (x,Q) */
/* stability interface to double interFunc (double x, double q, pdfStr * W) from pdf.c */
double c_pdf (int i, double x, double q) {
  double r;

  i--;
  r = interFunc (x, q, pdfData + i);
  if (!r) {
    return 0.;
  }

  if (pdfData[i].pow0) {
    r *= pow (x, pdfData[i].pow0);
  }

  if (pdfData[i].pow1 > 0) {
    r *= pow (1 - x, pdfData[i].pow1);
  }

  if (r < 0) {
    r = 0;
  }

  return r;
}

double alpha_pdf (double q) {
  return interAlpha (q, pdfData + alphaMode - 1);
}

#ifndef LHAPDF
int pdfnamecmp (void) {
  if (!strcmp (pdfName[0], pdfName[1]))
    return 1;
  return 0;
}
#endif
