/*******************************************************************
 *  BINDING SITE PREDICTION PROGRAM
 *
 *  Input: features (.cns,...)
 *  Output: files con binding sites (1,0)
 *
 *  Descritpion: this program
 *
 *
 *
 *
 ********************************************************************/
#include "bsp.h"



int    SITE_SIZE = 10;
int    LOG       = 1;
int    N_STEP    = 1000;
int    NMC_MAX   = 1;
double TEMP      = 0.1;  // Temperature
double AACCESS   = 2.0;  // Accessibility in Angstrom square
double NN_DIST   = 6.0;  // Cutoff for nearest neighbour
double W_CNS     = 1.0;  // Weight for conservation parameter
double W_SIZE    = 1.0;  // First geometrical parameter
double W_SIZE2   = 1.0;  // . geometrical parameter
double W_CIRC    = 1.0;  // . geometrical parameter
double W_ACC     = 1.0;  // . geometrical parameter
double W_CONV    = 1.0;  // . geometrical parameter

int CORE        = 0;
int SURF        = 1;
int SITE        = 2;

int    LENGTH;


class prot Prot;


struct cns Cns;


struct lig Lig;

// Options
char    Sol_file[100];     
char    Cns_file[100];
char    Psa_file[100];
char    Lig_file[100];


char File_mc1[100];
char File_mc2[100];
char File_mc3[100];
char File_mc4[100];

char Usage[1000];

/*********************************************************************
 ****     MAIN    ****************************************************
 *********************************************************************/


int main(int argc, char *argv[])
{
  //void getoptions(int argc, char *argv[]);
  void write_param();
  void read_cns(char file[], struct cns *);
  void read_psa(char file[], struct psa *);
  void read_lig(char file[], struct lig *lig);
  void optimize_site(struct site *site);
  void write_down(struct site *site);
  void compare_site(struct site *site);


  get_options_str( Sol_file,  "-sol",    "Sol file", "");
  get_options_str( Lig_file,  "-lig",    "Lig file", "");
  get_options_str( Cns_file,  "-cns",    "Cns file", "");
  get_options_str( Psa_file,  "-psa",    "Psa file", "");
  get_options_aux( &TEMP,     "-temp",   "Temp",      'd');
  get_options_aux( &W_CNS,    "-wcns",   "Wcns",      'd');
  get_options_aux( &W_SIZE,   "-wsize",  "Wsize",     'd');
  get_options_aux( &W_SIZE2,  "-wsize2", "Wsize2",    'd');
  get_options_aux( &W_CIRC,   "-wcirc",  "Wcirc",     'd');
  get_options_aux( &W_ACC,    "-wacc",   "Wacc",      'd');
  get_options_aux( &W_CONV,   "-wconv",  "Wconv",     'd');
  get_options_aux( &NMC_MAX,  "-nmc",    "nmc_max",   'i');

  get_options(argc, argv);
  write_param();

  printf("Going to read sol...\n");
  Prot.read_sol( Sol_file);
  if(LOG==1){ Prot.write_sol("bsp_sol.dat"); }
  Prot.create_surfers(AACCESS);
  if(LOG==1){ Prot.rasmol_surfers("bsp_surf_rml.dat", AACCESS);}
  if(LOG==1){ Prot.write_surfers("bsp_surf.dat");}

  Prot.create_dmap2();
  Prot.create_nn_list(NN_DIST);
  if(LOG==1){ Prot.write_nn_list("bsp_nn.dat"); }
  if(LOG==1){ Prot.rasmol_nn_list("bsp_nn_rml.dat",""); }
  Prot.create_imap();
  if(LOG==1){ Prot.write_imap("bsp_imap.dat"); }

  Prot.evaluate_divergence();
  Prot.write_divergence("bsp_div.dat");

  LENGTH = Prot.nres;
  printf("Going to read cns...\n");  
  read_cns( Cns_file, &Cns );

  /*printf("Going to read psa...\n");
    read_psa( Psa_file, &Psa );*/

  printf("Going to read lig...\n");
  read_lig( Lig_file, &Lig );


  printf("\n");
  printf("Optimization...\n");
  printf("\n");

  struct site site[NMC_MAX];

  for(int i=0; i<NMC_MAX; i++){
    printf(" Optimization number %d\n", i+1);
    sprintf(File_mc1, "%s%d%s", "/tmp/andrea/mc1_", i+1, ".tmp");
    sprintf(File_mc2, "%s%d%s", "/tmp/andrea/mc2_", i+1, ".tmp");
    sprintf(File_mc3, "%s%d%s", "/tmp/andrea/mc3_", i+1, ".tmp");
    sprintf(File_mc4, "%s%d%s", "/tmp/andrea/mc4_", i+1, ".tmp");
    optimize_site(site+i);
  }
  
  printf("Write down site..\n");
  write_down(site);

  printf("Comparison...\n");
  compare_site(site);
}

void write_param()
{
  FILE *fp = fopen_write("bsp_input.dat");
  fprintf(fp, "Here is the input of bsp\n\n");
  fprintf(fp, "SITE_SIZE:  %d\n",  SITE_SIZE);
  fprintf(fp, "N_STEP:     %d\n",  N_STEP);
  fprintf(fp, "TEMP:       %f\n",  TEMP);
  fprintf(fp, "W_CNS:      %f\n",  W_CNS);
  fprintf(fp, "W_SIZE:     %f\n",  W_SIZE);
  fprintf(fp, "W_SIZE2:    %f\n",  W_SIZE2);
  fprintf(fp, "W_CIRC:     %f\n",  W_CIRC);
  fprintf(fp, "W_ACC:      %f\n",  W_ACC);
  fprintf(fp, "W_CONV:     %f\n",  W_CONV);
  fprintf(fp, "AACCESS:    %f\n",  AACCESS);
  fclose(fp);
}

/*****************************************************
 -------------------    INPUT    ---------------------
 *****************************************************/
void read_cns(char file[], struct cns *cns)
{
  char buffer[1000];
  
  int n=0;

  cns->n1  = new int[LENGTH];
  cns->c2  = new char[LENGTH];
  cns->cns = new double[LENGTH];

  FILE *fp = fopen_read(file);
  for(int i=0 ;  ; i++){
    if(fgets(buffer, 1000, fp) == NULL){
      break;
    }
    if(n >= LENGTH){
      printf("ERRORE Length: %d n: %d\n", LENGTH, n);
      exit(0);
    }
    //printf("%5d %s\n",i+1, buffer);
    if(buffer[0]!='#'){
      sscanf(buffer, "%d %c %lf", &cns->n1[n], &cns->c2[n], &cns->cns[n]);
      if(LOG==1) printf("%3d %3d %c %8.3f\n", n, cns->n1[n], cns->c2[n], cns->cns[n]);
      n++;
    }
  }


  fclose(fp);
}

// Ligand
void read_lig(char file[], struct lig *lig)
{
  char buffer[1000];
  
  int n1,n2;
  char c;
  lig->lig  = new int[LENGTH];


  FILE *fp = fopen_read(file);
  int n=0;
  for(int i=0 ;  ; i++){
    if(fgets(buffer, 1000, fp) == NULL){
      break;
    }
    if(n >= LENGTH){
      printf("ERRORE Length: %d n: %d\n", LENGTH, n);
      exit(0);
    }
    //printf("%5d %s\n",i+1, buffer);
    if(buffer[0]!='#'){
      sscanf( buffer, "%d %d %c %d", &n1, &n2, &c, &lig->lig[n] );
      if(LOG==1) printf("%3d %3d %c %d\n", n1, n2, c, lig->lig[n] );
      n++;
    }
  }

  fclose(fp);
}



/************************************************
  ----   MINIMIZATION   BY   MONTE   CARLO   ----
*************************************************/

void optimize_site(struct site *site1)
{
  struct site site2[1];

  create_site( site1 );
  create_site( site2 );

  printf("Files: %s  %s  %s  %s\n", File_mc1, File_mc2, File_mc3, File_mc4);
  FILE *fp1 = fopen_write(File_mc1); 
  FILE *fp2 = fopen_write(File_mc2); 
  FILE *fp3 = fopen_write(File_mc3);
  FILE *fp4 = fopen_write(File_mc4);

  printf("  Create core...\n");
  create_core(site1);

  printf("  Initialize site...\n");
  fprintf(fp4,"    0 -> ");
  init_site(site1, fp4);

  score(site1);


  printf("  Starting minimization...\n\n");

  int nacc = 0;
  for( int i=0 ; i < N_STEP ;  i++ ){
    cp_site( site2, site1 );
    fprintf(fp4,"%5d -> ", i+1);
    mutate_site(site2, fp4);

    score(site2);

    if( metrop( site2->G - site1->G, TEMP)){
      cp_site( site1, site2 );
      nacc++;
    }
    composition_site(site1);
    fprintf        (fp1,"%5d  %8.3f  ", i+1,  site1->G);
    fprintf_energy (fp1, site1);
    fprintf        (fp2,"%5d  %8.3f  ", i+1, site1->G);
    fprintf_flag   (fp2, site1->flag);
    
  }

  fclose(fp1);
  fclose(fp2);
  fclose(fp3);
  fclose(fp4);
}

/*************************************************
---------------    COMPARE SITES    -----------
**************************************************/

void compare_site(struct site *site)
{
  int compare_lig(struct site *site, struct lig lig);

  FILE *fp = fopen_write("bsp_res.dat");
  for(int i=0; i<NMC_MAX; i++){
    site[i].m1 = compare_lig(site+i,Lig);
    fprintf(fp,"%5d  %8.3f  %8.3f\n",i+1, site[i].G, site[i].m1);
  }
  
  fclose(fp); 
}

int compare_lig(struct site *site, struct lig lig)
{
  int n=0;
  for(int i=0; i< LENGTH;i++){
    if(site->flag[i]==SITE && lig.lig[i]==1){
      n++;
    }
  }
  return n;
}


/*************************************************
---------------    CHECK AND WRITE     -----------
**************************************************/

void write_down(struct site *site)
{
  FILE *fp1 = fopen_write( "bsp_seq.dat" );
  FILE *fp2 = fopen_write( "bsp_en.dat" );

  fprintf(fp1, "%d   %d\n", NMC_MAX, LENGTH);
  for(int i=0; i<NMC_MAX; i++){
    fprintf     (fp1, "%5d  %8.3f  ", i+1, site[i].G);
    fprintf_flag(fp1, site[i].flag);

    fprintf       (fp2, "%5d  %8.3f  ", i+1, site[i].G);
    fprintf_energy(fp2, site+i);
  }
  fclose(fp1);
  fclose(fp2);
}


//Write down binding site
void write_site(char file[], struct site *site)
{
  FILE *fp = fopen_write(file);
  fprintf(fp, "%d\n", LENGTH);
  for(int i=0; i< LENGTH; i++){
    fprintf(fp, "%3d %3d\n", i+1, site->flag[i]);
  }
  fclose(fp);
}

// Print flag
void fprintf_flag(FILE *fp, int flag[])
{
  for(int i=0; i<LENGTH; i++){
    fprintf(fp,"%1d", flag[i]);
  }
  fprintf(fp, "\n");
}

// Print flag
void fprintf_energy(FILE *fp, struct site *site)
{
  fprintf(fp,"%6.2f ", site->G1);
  fprintf(fp,"%6.2f ", site->G2);
  fprintf(fp,"%6.2f ", site->G3);
  fprintf(fp,"%6.2f ", site->G4);
  fprintf(fp,"%6.2f ", site->G5);
  fprintf(fp,"%6.2f\n", site->G6);
}
