
/* copyright (c) 1996, 1997, 1998, 1999 William R. Pearson and the
   U. of Virginia */

/* $Name: fa34t26b4 $ - $Id: mshowbest.c,v 1.44 2006/06/30 19:46:36 wrp Exp $ */

/*   29-Oct-2003 - changes so that bbp->cont < 0 => aa1 sequence is
     already in aa1, no re_openlib or re_getlib required
*/

/*   14-May-2003 Changes to use a more consistent coordinate numbering
     system for displays.  aln->d_start[01] is now consistently used
     to report the start of the alignment in all functions, and
     mshowbest.c has been modified to use d_start[01] instead of
     d_start[01]-1.  aln->min[01] now starts at 0 for all functions;
     instead of 1 for some functions (dropnfa.c, dropgsw.c, dropfs2.c
     earlier).
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "defs.h"
#include "structs.h"
#include "param.h"

#ifndef PCOMPLIB
#include "mm_file.h"
#include "mw.h"
#else
#include "p_mw.h"
#endif


#define MAX_BLINE 256

#ifndef PCOMPLIB
/* function calls necessary to re_getlib() the sequence and, do
   alignments, if necessary
*/

#define RANLIB (m_fptr->ranlib)

int
re_getlib(unsigned char *, int, int, int, int, int, long *, long *, 
	  struct lmf_str *m_fptr);

#include "drop_func.h"

struct lmf_str *re_openlib(struct lmf_str *, int outtty);
#endif

extern void cal_coord(int n0, int n1, long sq0off, long loffset,
		      struct a_struct *aln);

void header_aux(FILE *);
void show_aux(FILE *, struct beststr *);
void w_abort (char *p, char *p1);

/* BBP_INFO get stuff directly from beststr or from beststr->desptr */
#ifdef PCOMPLIB
#define BBP_INFO(info) bbp->desptr->info
#else
#define BBP_INFO(info) bbp->info
#endif

extern double zs_to_bit(double, int, int);

/* showbest() shows a list of high scoring sequence descriptions, and
   their scores.  If -m 9, then an additional complete set of
   alignment information is provided.

   If PCOMPLIB or m_msg.quiet then the number of high scores to be
   shown is pre-determined by m_msg.mshow before showbest is called.

   The comp_lib.c version re_getlib()'s the sequence for its
   discription, and then does another alignment for -m 9 (Thus, it
   needs an f_str.  The PCOMPLIB version has everything available in
   beststr before showbest() is called.
*/

void showbest (FILE *fp, 
#ifndef PCOMPLIB
	       unsigned char **aa0, unsigned char *aa1, int maxn,
#endif
	       struct beststr **bptr,int nbest, int qlib, struct mngmsg *m_msg,
	       struct pstruct pst, struct db_str db,
	       char *gstring2
#ifndef PCOMPLIB
	       ,void **f_str
#endif
)
{
  int ntmp = 0;
  char bline[MAX_BLINE], fmt[40], pad[MAX_BLINE], rline[40];
  char l_name[128];
  int istart = 0, istop, ib;
  int nshow;
  int quiet;
  int r_margin;
  struct beststr *bbp;
  int n1tot;
  char *bp;
  char rel_label[12];
  char tmp_str[20], *seqc;
  int seqc_len;
  long loffset, l_off;
  int n0, n1;
  struct rstruct rst;
  int lc, maxc, nident, ngap;
  float percent, gpercent;
  struct a_struct *aln_p;
  int *tres;
  int gi_num;

#ifndef PCOMPLIB
  struct lmf_str *m_fptr;
#endif

  strncpy(rel_label,"\0",2);
#ifdef SHOWREL
  strncpy(rel_label," related",sizeof(rel_label));
#endif
#ifdef SHOWUN
  strncpy(rel_label," unrelated",sizeof(rel_label));
#endif
  rel_label[sizeof(rel_label)-1]='\0';

#ifdef PCOMPLIB
  quiet = 1;
#else
  quiet = m_msg->quiet;
#endif

  n0 = m_msg->n0;

  if (m_msg->aln.llen > MAX_BLINE) m_msg->aln.llen = MAX_BLINE;

  if (pst.zsflag < 0) r_margin = 10;
  else if (pst.zsflag>=0  && m_msg->srelv > 1 ) r_margin = 19;
  else r_margin = 10;

  if (m_msg->markx & MX_M9SUMM && m_msg->show_code == SHOW_CODE_ID) {
#ifdef SHOWSIM
    r_margin += 15;
#else
    r_margin += 10;
#endif
  }

  if (m_msg->nframe < 0) 
#ifndef SUPERFAMNUM
    sprintf(fmt,"%%-%ds (%%4d)",m_msg->aln.llen-r_margin);
#else
    sprintf(fmt,"%%-%ds [%%4d](%%4d)",m_msg->aln.llen-(r_margin+4));
#endif
  else 
    sprintf(fmt,"%%-%ds (%%4d)",m_msg->aln.llen-(r_margin+4));

  memset(pad,' ',m_msg->aln.llen-(r_margin+6));
  pad[m_msg->aln.llen-(r_margin+12)]='\0';

  if (quiet != -1) {	/* quiet is set to -1 in comp_mlib.c to force
			   all significant hits to be shown */
    nshow = 20;
    if (m_msg->mshow == -1) nshow = nbest;		/* show all */
    /* show specified number */
    else if (m_msg->mshow_flg) {
      nshow = min (m_msg->mshow, nshow);
    }
  }
  else nshow = m_msg->nshow;

  if (quiet==0) istop = 20;
  else istop = nshow;

  if (quiet==0) {
    printf(" How many scores would you like to see? [%d] ",m_msg->nshow);
    fflush(stdout);
    if (fgets(rline,20,stdin)==NULL) exit(0);
    nshow = m_msg->nshow;
    if (rline[0]!='\n' && rline[0]!=0) sscanf(rline,"%d",&nshow);
    if (nshow<=0) nshow = min(20,nbest);
  }

  if ((bp = strchr (m_msg->qtitle, '\n')) != NULL) *bp = '\0';
/*   fprintf (fp, "%3d %s\n", qlib,m_msg->qtitle); */

  if (m_msg->markx & MX_HTML) fprintf(fp,"<p><tt><pre>\n");

  if (pst.zsflag >= 0) {
    if (bptr[0]->escore < m_msg->e_cut) {
      if (m_msg->z_bits==1) {/* show bit score */
	fprintf(fp,"The best%s scores are:%s%s bits E(%ld)",
	       rel_label,pad,m_msg->label,pst.zdb_size);
      }
      else {/* show z-score */
	fprintf(fp,"The best%s scores are:%s%s z-sc E(%ld)",
	      rel_label,pad,m_msg->label,pst.zdb_size);
      }
      header_aux(fp);
      if (m_msg->markx & MX_M9SUMM) {
	if (m_msg->show_code == SHOW_CODE_ID) {
#ifdef SHOWSIM
	  fprintf(fp," %%_id  %%_sim  alen");
#else
	  fprintf(fp," %%_id  alen");
#endif
	}
	else {
	if (m_msg->markx & MX_HTML && m_msg->show_code !=1) { fprintf(fp,"<!-- ");}
#ifndef SHOWSIM
	  fprintf(fp,"\t%%_id  %%_gid %4s  alen  an0  ax0  pn0  px0  an1  ax1 pn1 px1 gapq gapl  fs ",m_msg->f_id1);
#else
	  fprintf(fp,"\t%%_id  %%_sim %4s  alen  an0  ax0  pn0  px0  an1  ax1 pn1 px1 gapq gapl  fs ",m_msg->f_id1);
#endif
	}
	if (m_msg->show_code == SHOW_CODE_ALIGN) {	fprintf(fp," aln_code"); }
	if (m_msg->markx & MX_HTML && m_msg->show_code!=1) { fprintf(fp," -->");}
      }
      fprintf(fp,"\n");
    }
    else {
      fprintf(fp,"!! No library sequences with E() < %.2g\n",m_msg->e_cut);
      m_msg->nshow = 0;
      if (m_msg->markx & MX_HTML) fprintf(fp,"<p></tt></pre>\n");
      return;
    }
  }
  else {
    fprintf(fp,"The best%s scores are:%s%s",rel_label,pad,m_msg->label);
    header_aux(fp);
    if (m_msg->markx & MX_M9SUMM) {
      if (m_msg->show_code == SHOW_CODE_ID) {
#ifdef SHOWSIM
	fprintf(fp," %%_id  %%_sm  alen");
#else
	fprintf(fp," %%_id  alen");
#endif
      }
      else {
#ifndef SHOWSIM
	fprintf(fp,"\t%%_id  %%_gid %4s  alen  an0  ax0  pn0  px0  an1  ax1 pn1 px1 gapq gapl  fs ",m_msg->f_id1);
#else
	fprintf(fp,"\t%%_id  %%_sim %4s  alen  an0  ax0  pn0  px0  an1  ax1 pn1 px1 gapq gapl  fs ",m_msg->f_id1);
#endif
      }
    }
    if (m_msg->show_code == SHOW_CODE_ALIGN) {	fprintf(fp," aln_code"); }
    fprintf(fp,"\n");
  }

  istart = 0;
l1:
  istop = min(nbest,nshow);
  for (ib=istart; ib<istop; ib++) {
    bbp = bptr[ib];
#ifdef SUPERFAMNUM
    if (BBP_INFO(nsfnum) > 0 && sfn_cmp(m_msg->qsfnum_n,BBP_INFO(sfnum))) continue;
#ifdef SHOWUN
    if (BBP_INFO(nsfnum) > 0 && sfn_cmp(m_msg->qsfnum,BBP_INFO(sfnum))) {
      istop = min(istop+1,nbest);
    /*
      fprintf(stderr,"skipping %d: %d==%d\n",ib,m_msg->qsfnum,BBP_INFO(sfnum));
      */
      continue;
    }
#endif
#ifdef SHOWREL
    if (BBP_INFO(nsfnum) == 0 || (BBP_INFO(nsfnum) > 0 && !sfn_cmp(m_msg->qsfnum,BBP_INFO(sfnum)))) {
      istop = min(istop+1,nbest);
    /*
      fprintf(stderr,"skipping %d: %d==%d\n",ib,m_msg->qsfnum,BBP_INFO(sfnum));
      */
      continue;
    }
#endif
#endif
    if (quiet==1 && pst.zsflag>=0) {
      if (bbp->escore > m_msg->e_cut) {
	nshow = ib;
	goto done;
      }
      else if (bbp->escore < m_msg->e_low) continue;
    }

#ifndef PCOMPLIB
    if ((m_fptr=re_openlib(bbp->m_file_p,!m_msg->quiet))==NULL) {
      fprintf(stderr,"*** cannot re-open %s\n",bbp->m_file_p->lb_name);
      exit(1);
    }
    RANLIB(bline,m_msg->aln.llen,bbp->lseek,bbp->libstr,m_fptr);
#else
  strncpy(bline,BBP_INFO(bline),m_msg->aln.llen-r_margin);
  bline[m_msg->aln.llen]='\0';
#endif

  /* l_name is used to build an HTML link from the bestscore line to
     the alignment.  It can also be used to discriminate multiple hits
     from the same long sequence.  This requires that fast_pan use -m 6. */

  strncpy(l_name,bline,sizeof(l_name)); /* get rid of text after second "|" */
  l_name[sizeof(l_name)-1]='\0';
  if ((bp=strchr(l_name,' '))!=NULL) *bp=0;
  if ((bp=strchr(&l_name[3],'|'))!=NULL) *bp='\0';
  if (m_msg->nframe > 2) sprintf(&l_name[strlen(l_name)],"_%d",bbp->frame+1);
  else if (m_msg->nframe > 0 && bbp->frame == 1)
    strncat(l_name,"_r",sizeof(l_name));
  if (bbp->cont-1 > 0) {
    sprintf(tmp_str,":%d",bbp->cont-1);
    strncat(l_name,tmp_str,sizeof(l_name)-strlen(l_name));
  }


#ifndef PCOMPLIB
  if (m_msg->stages>1 || m_msg->markx & MX_M9SUMM) {
    if (bbp->cont >= 0) {
      n1 = re_getlib(aa1,maxn,m_msg->maxt3,m_msg->loff,bbp->cont,m_msg->term_code,
		     &loffset,&l_off,bbp->m_file_p);
    }
    else { n1 = maxn;}
    if (! m_msg->markx & MX_M9SUMM) {
      do_opt (aa0[bbp->frame], m_msg->n0, aa1, n1, bbp->frame, &pst, f_str[bbp->frame], &rst);
      bbp->score[2]=rst.score[2];
    }
    else {
      bbp->sw_score = 
	do_walign(aa0[bbp->frame],m_msg->n0, aa1, n1, bbp->frame, 
		  &pst, f_str[bbp->frame], &bbp->a_res, &bbp->have_ares);

      
      /* save the alignment encoding for future use */
      if (bbp->have_ares && ((tres = calloc(bbp->a_res.nres+1,sizeof(int)))!=NULL)) {
	memcpy(tres,bbp->a_res.res,sizeof(int)*bbp->a_res.nres);
	bbp->a_res.res = tres;
      }

      aln_func_vals(bbp->frame, &m_msg->aln);

      maxc = bbp->a_res.nres + 4*m_msg->aln.llen+4;
      seqc = NULL;
      seqc_len = 0;
      if (m_msg->show_code == SHOW_CODE_ALIGN) {
	if ((seqc=(char *)calloc(maxc,sizeof(char)))!=NULL) {
	  lc=calc_code(aa0[bbp->frame],m_msg->n0,
		       aa1,n1, 
		       &m_msg->aln,bbp->a_res,
		       pst,seqc,maxc,f_str[bbp->frame]);
	  seqc_len = strlen(seqc);
	}
      }
      else {
	lc=calc_id(aa0[bbp->frame],m_msg->n0,aa1,n1,
		   &m_msg->aln, bbp->a_res,
		   pst,f_str[bbp->frame]);
      }
      m_msg->aln.a_len = lc;

      nident = m_msg->aln.nident;
      if (lc > 0) percent = (100.0*(float)nident)/(float)lc;
      else percent = -1.00;

      ngap = m_msg->aln.ngap_q + m_msg->aln.ngap_l;
#ifndef SHOWSIM
      if (lc-ngap > 0) gpercent = (100.0*(float)nident)/(float)(lc-ngap);
      else gpercent = -1.00;
#else
      if (lc-ngap > 0) gpercent = (100.0*(float)m_msg->aln.nsim)/(float)(lc);
      else gpercent = -1.00;
#endif

    }
  }
#endif

  n1tot = (BBP_INFO(n1tot_p)) ? *BBP_INFO(n1tot_p) : bbp->n1;

  bp = bline;
  if ((m_msg->markx & MX_HTML) && !strncmp(bline,"gi|",3)) {
    bp = strchr(bline+4,'|')+1;
    *(bp-1) = 0;
    gi_num = atoi(bline+3);
  }

#ifndef SUPERFAMNUM
  bp[m_msg->aln.llen-r_margin]='\0';
#else
  bp[m_msg->aln.llen-r_margin-5]='\0';
#endif

  if (m_msg->nframe == -1) bp[m_msg->aln.llen-r_margin]='\0';
  else bp[m_msg->aln.llen-(r_margin+4)]='\0';

#ifndef SUPERFAMNUM
  fprintf (fp, fmt,bp,n1tot);
#else
  if (m_msg->nframe == -1) {
    fprintf (fp, fmt,bp,BBP_INFO(sfnum[0]),n1tot);
  }
  else {fprintf (fp, fmt,bp,n1tot);}
#endif

  if (m_msg->nframe > 2) fprintf (fp, " [%d]", bbp->frame+1);
  else if (m_msg->nframe >= 0) fprintf(fp," [%c]",(bbp->frame > 0 ?'r':'f'));

  if (m_msg->srelv == 1) fprintf (fp, " %4d", bbp->score[pst.score_ix]);
  else {
    if (m_msg->srelv-1 > 0) fprintf (fp, " %4d", bbp->score[0]);
    if (m_msg->srelv-1 > 1 || m_msg->stages>1)
      fprintf (fp, " %4d", bbp->score[1]);
    fprintf (fp, " %4d", bbp->score[pst.score_ix]);
  }

  if (pst.zsflag>=0) { 
    if (m_msg->z_bits==1) {
      fprintf (fp, " %.1f %7.2g",zs_to_bit(bbp->zscore,m_msg->n0,bbp->n1),bbp->escore);
    }
    else fprintf (fp, " %.1f %7.2g",bbp->zscore,bbp->escore);
  }
  show_aux(fp,bbp);

#ifdef PCOMPLIB
  n1 = bbp->n1;
  percent = bbp->percent;
  gpercent = bbp->gpercent;
  aln_p = bbp->aln_d;
  seqc = bbp->aln_code;
  seqc_len = bbp->aln_code_n;
  loffset = bbp->desptr->loffset;
  l_off = 0;
#else
  aln_p = &(m_msg->aln);
#endif

  if (m_msg->markx & MX_M9SUMM) {
    if (m_msg->show_code != SHOW_CODE_ID) {
      if (m_msg->markx & MX_HTML) fprintf(fp,"<!-- ");
      cal_coord(m_msg->n0,bbp->n1,m_msg->sq0off,loffset+l_off-1,aln_p);

      /*            %_id  %_sim s-w alen an0  ax0  pn0  px0  an1  ax1  pn1  px1 gapq gapl fs  */
      /*                    alignment    min  max            min  max */
      /*                    sequence coordinate    min  max            min  max */
      fprintf(fp,"\t%5.3f %5.3f %4d %4d %4ld %4ld %4ld %4ld %4ld %4ld %4ld %4ld %3d %3d %3d",
	      percent/100.0,gpercent/100.0, bbp->sw_score,aln_p->a_len,
	      aln_p->d_start0,aln_p->d_stop0,
	      m_msg->sq0off, m_msg->sq0off+m_msg->n0-1,
	      aln_p->d_start1,aln_p->d_stop1,
	      loffset+l_off, loffset+l_off+bbp->n1-1,
	      aln_p->ngap_q,aln_p->ngap_l,aln_p->nfs);
      if (m_msg->show_code == SHOW_CODE_ALIGN
	  && seqc_len > 0 && seqc != NULL) {
	fprintf(fp,"\t%s",seqc);
      /*      fprintf(fp," [%2d:%d]",bbp->wrkr,bbp->seqnm); */
	free(seqc);
	seqc = NULL;
      }
      if (m_msg->markx & MX_HTML) fprintf(fp," -->");
    }
    else {
#ifdef SHOWSIM
      fprintf(fp," %5.3f %5.3f %4d", percent/100.0,(float)aln_p->nsim/(float)aln_p->a_len,aln_p->a_len);
#else
      fprintf(fp," %5.3f %4d", percent/100.0,aln_p->a_len);
#endif
    }
  }
  if (m_msg->markx & MX_HTML) fprintf(fp," <A HREF=\"#%s\">align</A>",l_name);
  fprintf (fp, "\n");
  fflush(fp);
  }

  if (quiet==0) {
    printf(" More scores? [0] ");
    fflush(stdout);
    if (fgets(rline,20,stdin)==NULL) exit(0);
    ntmp = 0;
    if (rline[0]!='\n' && rline[0]!=0) sscanf(rline,"%d",&ntmp);
    if (ntmp<=0) ntmp = 0;
    if (ntmp>0) {
      istart = istop;
      nshow += ntmp;
      goto l1;
    }
  }
  else if (quiet == 1)
    if (ib < nbest && (pst.zsflag>=0 && bbp->escore < m_msg->e_cut)) {
      if (m_msg->mshow_flg && istop >= m_msg->mshow) goto done;
      istart=istop;
      nshow += 10;
      goto l1;
    }

 done:
  m_msg->nshow = nshow;
  if (m_msg->markx & MX_HTML) fprintf(fp,"</pre></tt><p><hr><p>\n");
  if (fp!=stdout) fprintf(fp,"\n");
}

/*
  q[] has one set of sfnums, 0 terminated
  s[] has second
  return first match or 0
*/
