/********************************************************************************************************
 * QRNA - Comparative analysis of biological sequences 
 *         with pair hidden Markov models, pair stochastic context-free
 *        grammars, and probabilistic evolutionary  models.
 *       
 * Version 2.0.0 (JUN 2003)
 *
 * Copyright (C) 2000-2003 Howard Hughes Medical Institute/Washington University School of Medicine
 * All Rights Reserved
 * 
 *     This source code is distributed under the terms of the
 *     GNU General Public License. See the files COPYING and LICENSE
 *     for details.
 ***********************************************************************************************************/

/* evolscorewithmodelscan.c
 *
 * ER, Mon Aug 16 12:37:54 CDT 2004 [St. Louis at work, Coro at Maribel's]
 * 
 * 
 * 
 */

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

#include "funcs.h"
#include "evolfuncs.h"
#include "globals.h"
#include "squid.h"
#include "structs.h"

#ifdef MEMDEBUG
#include "dbmalloc.h"
#endif


static void print_scan_ends (FILE *ofp, int leg, char *whichmodel, struct endscan_s *ends, int isreverse, int winner);
static void score_with_null_scan(FILE *ofp, int *isegX, int *isegY, int len, struct nullmodel_s *null, 
				 double nullsc, double nullrevsc, int verbose);

static void score_viterbi_diag_scan_fast(FILE *ofp, 
					 SQINFO sqinfoX, int *isegX,
					 SQINFO sqinfoY, int *isegY,
					 char *gss, int L, int win, int slide, int st, int stmod, int l, int lmax,
					 struct emodel_s          *emodel, 
					 struct dpdscanfast_s     *dpdscan, 		     		    
					 struct rnascfgscanfast_s *mx, 
					 struct sc3_s             *sc, 
					 struct ali_s             *ali, 
					 struct scanfast_s        *scanfast,
					 int alignment, int cyk, int doends, int fastintloop, int logodds, int ones, int parse, int rnass, 
					 int revstrand, int traceback, int *ret_windows);


/* Function: EvolScoreWithModelsScan()
 * Date:     ER, Mon Aug 16 12:39:18 CDT 2004  [St. Louis at work, Coro at Maribel's]
 *
 * Purpose:  decide which scoring method to use. Called by main().
 *
 * Args:     
 *
 * Returns:  void.
 */
int
EvolScoreWithModelsScanFast(FILE *ofp, 
			    SQINFO sqinfoX, int *isegX,
			    SQINFO sqinfoY, int *isegY,
			    char *gss,
			    int L, int win, int slide, int j, int jmod, int l, int lmax, 
			    struct emodel_s          *emodel, 
			    struct dpdscanfast_s     *dpdscan, 		   
			    struct rnascfgscanfast_s *mx, 
			    struct scores_s          *sc, 
			    struct ali_s             *ali, 
			    struct scanfast_s        *scanfast,
			    int alignment, int cyk, int doends, int fastintloop, int logodds, int ones, int parse, 
			    int rnass, int revstrand, int traceback, int verbose)
{
  int windows;
   
 /* Calculate the null-model scores
  */
  score_with_null_scan(ofp, isegX, isegY, l, emodel->null, sc->null, sc->nullrev, verbose);

  /* VITERBI (diag local aligmnent) 
   */
  score_viterbi_diag_scan_fast(ofp, sqinfoX, isegX, sqinfoY, isegY, gss, L, win, slide, j, jmod, l, lmax, emodel, dpdscan, 
			       mx, sc->vidiag, ali, scanfast, alignment, cyk, doends, fastintloop, logodds, ones, parse, rnass, revstrand, traceback, 
			       &windows);

  /*Other versions still not implemented in scanfast model */
  
  return windows;
}

void
print_scan_ends (FILE *ofp, int leg, char *whichmodel, struct endscan_s *ends, int isreverse, int winnerstrand)
{
  char *strand;
  int   lend, rend;
  int   x;

  if (isreverse) { if (winnerstrand) strand = "*(-) "; else strand = " (-) "; }
  else           { if (winnerstrand) strand = " (+) "; else strand = "*(+) "; }

  fprintf(ofp, "%s ends %s=  ", whichmodel, strand);

  if (isreverse)
    {
      for (x = 0; x < MAX_NUM_ENDS; x++)
	{
	  if (ends->lend[x] > -1 && ends->rend[x]-ends->lend[x] > 0) {
	    
	    /* for the reversed strand, report the ends in the other (the "given")  strand
	     */
	    rend = leg - 1 - ends->lend[x];
	    lend = leg - 1 - ends->rend[x];
	    
	    ends->rend[x] = rend;
	    ends->lend[x] = lend;
	    
	    fprintf(ofp, "(%d..[%d]..%d) ", ends->lend[x], ends->rend[x]-ends->lend[x]+1, ends->rend[x]);
	  }
	}  
      fprintf(ofp, "\n");  
    }

  else
    {
      for (x = MAX_NUM_ENDS-1; x >= 0; x--)
	if (ends->lend[x] > -1 && ends->rend[x]-ends->lend[x] > 0) {
 	  fprintf(ofp, "(%d..[%d]..%d) ", ends->lend[x], ends->rend[x]-ends->lend[x]+1, ends->rend[x]);
	}
      fprintf(ofp, "\n");  
    }
  
}

void
score_with_null_scan(FILE *ofp, int *isegX, int *isegY, int len, struct nullmodel_s *null, 
		     double nullsc, double nullrevsc, int verbose)
{
  nullsc    = ScoreWithNullDiag(isegX, isegY, 0, len, null);
  nullrevsc = ScoreWithNullRevDiag(isegX, isegY, 0, len, null);
  if (verbose) PrintNull(ofp, null, nullsc, nullrevsc);
}

void
score_viterbi_diag_scan_fast(FILE *ofp, 
			     SQINFO sqinfoX, int *isegX, 
			     SQINFO sqinfoY, int *isegY, 
			     char *gss, int L, int win, int slide, int j, int jmod, int l, int lmax,
			     struct emodel_s           *emodel, 
			     struct dpdscanfast_s     *dpdscan, 		     		    
			     struct rnascfgscanfast_s *mx, 
			     struct sc3_s             *sc, 
			     struct ali_s             *ali, 
			     struct scanfast_s        *scanfast,
			     int alignment, int cyk, int doends, int fastintloop, int logodds, int ones, int parse, int rnass, 
			     int revstrand, int traceback, int *ret_windows)
{
  struct othdpscanfast_s  *dpoth;
  struct coddpscanfast_s  *dpcod;
  struct rnadpscanfast_s  *dprna;
  struct rnamtxscanfast_s *mtx;
  struct end3scan_s       *ends;
  double                  *othscwin;
  double                  *codscwin;
  double                  *rnascwin;
  double                   othsc;
  double                   codsc;
  double                   rnasc;
  int                      jwrite;
  int                      idx;
  int                      d, dmax;
  int                      exact;
  int                      n_windows = 0;

  ends = AllocEnd3ScanFast();
  
  d    = l - 1;
  dmax = lmax - 1;
  
  if (revstrand) {
    dpoth = dpdscan->othscan2->htoscan;
    dpcod = dpdscan->codscan2->docscan;
    dprna = dpdscan->rnascan2->anrscan;
    
    othscwin = scanfast->sc->othrev;
    codscwin = scanfast->sc->codrev;
    rnascwin = scanfast->sc->rnarev;

    mtx = mx->inrv;
  }
  else {
    dpoth = dpdscan->othscan2->othscan;
    dpcod = dpdscan->codscan2->codscan;
    dprna = dpdscan->rnascan2->rnascan;

    othscwin = scanfast->sc->oth;
    codscwin = scanfast->sc->cod;
    rnascwin = scanfast->sc->rna;

    mtx = mx->in;
  }

   /* for every (j,d) parir 
   *
   * calculate:   fjmx[jmod][d], COJ[jmod][d], ROJ[jmod][d], wx[jmod][d]
   *
   */
  
  /* The flmx's for the 8 OTH models 
   *   O(1) in memory
   */
  ScoreWithNullFJScan(isegX, isegY, win, j, jmod, l, emodel->oth->FLN, dpoth->flmx);
  
  ScoreWithNullFJScan(isegX, isegY, win, j, jmod, l, emodel->cod->COB->FLN, dpcod->cob->flmx);
  ScoreWithNullFJScan(isegX, isegY, win, j, jmod, l, emodel->cod->COJ->FLN, dpcod->coj->flmx);
  ScoreWithNullFJScan(isegX, isegY, win, j, jmod, l, emodel->cod->COE->FLN, dpcod->coe->flmx);

  ScoreWithNullFJScan(isegX, isegY, win, j, jmod, l, emodel->rna->ROB->FLN,        dprna->rob->flmx);
  ScoreWithNullFJScan(isegX, isegY, win, j, jmod, l, emodel->rna->ROJ->FLN,        dprna->roj->flmx);
  ScoreWithNullFJScan(isegX, isegY, win, j, jmod, l, emodel->rna->ROE->FLN,        dprna->roe->flmx);
  ScoreWithNullFJScan(isegX, isegY, win, j, jmod, l, emodel->rna->pi2->Rloop->FLN, mtx->othj->flmx);


  /* The frmx's for the 8 OTH models 
   *   O(1) in memory
   */
  ScoreWithNullFJScan(isegX, isegY, win, j, jmod, l, emodel->oth->FRN, dpoth->frmx);
  
  ScoreWithNullFJScan(isegX, isegY, win, j, jmod, l, emodel->cod->COB->FRN, dpcod->cob->frmx);
  ScoreWithNullFJScan(isegX, isegY, win, j, jmod, l, emodel->cod->COJ->FRN, dpcod->coj->frmx);
  ScoreWithNullFJScan(isegX, isegY, win, j, jmod, l, emodel->cod->COE->FRN, dpcod->coe->frmx);

  ScoreWithNullFJScan(isegX, isegY, win, j, jmod, l, emodel->rna->ROB->FRN,        dprna->rob->frmx);
  ScoreWithNullFJScan(isegX, isegY, win, j, jmod, l, emodel->rna->ROJ->FRN,        dprna->roj->frmx);
  ScoreWithNullFJScan(isegX, isegY, win, j, jmod, l, emodel->rna->ROE->FRN,        dprna->roe->frmx);
  ScoreWithNullFJScan(isegX, isegY, win, j, jmod, l, emodel->rna->pi2->Rloop->FRN, mtx->othj->frmx);


  /* The fjmx's for the 8 OTH emodels 
   *   O(1) in memory
   */
  ScoreWithNullFJScan(isegX, isegY, win, j, jmod, l, emodel->oth->FJN, dpoth->fjmx);
  
  ScoreWithNullFJScan(isegX, isegY, win, j, jmod, l, emodel->cod->COB->FJN, dpcod->cob->fjmx);
  ScoreWithNullFJScan(isegX, isegY, win, j, jmod, l, emodel->cod->COJ->FJN, dpcod->coj->fjmx);
  ScoreWithNullFJScan(isegX, isegY, win, j, jmod, l, emodel->cod->COE->FJN, dpcod->coe->fjmx);

  ScoreWithNullFJScan(isegX, isegY, win, j, jmod, l, emodel->rna->ROB->FJN,        dprna->rob->fjmx);
  ScoreWithNullFJScan(isegX, isegY, win, j, jmod, l, emodel->rna->ROJ->FJN,        dprna->roj->fjmx);
  ScoreWithNullFJScan(isegX, isegY, win, j, jmod, l, emodel->rna->ROE->FJN,        dprna->roe->fjmx);
  ScoreWithNullFJScan(isegX, isegY, win, j, jmod, l, emodel->rna->pi2->Rloop->FJN, mtx->othj->fjmx);
  
  /* COJ -- ROJ 
   *   O(1) in memory if exact == FALSE
   *   O(w) in memory if exact == TRUE
   */
  exact = FALSE;
  FillOTHMtxScanFast(ofp, sqinfoX, isegX, sqinfoY, isegY, L, win, j, jmod, l, emodel->cod->COJ,  
		     emodel->null, dpcod->coj, dpcod->cod->COJ, exact, FALSE, ends->oth);
  FillOTHMtxScanFast(ofp, sqinfoX, isegX, sqinfoY, isegY, L, win, j, jmod, l, emodel->rna->ROJ,  
		     emodel->null, dprna->roj, dprna->rna->ROJ, exact, FALSE, ends->oth);
  
  /* rnaj */
  FillOTHMtxScanFast(ofp, sqinfoX, isegX, sqinfoY, isegY, L, win, j, jmod, l, emodel->rna->pi2->Rloop, 
		     emodel-> null, mtx->othj, mtx->rnaj, exact, logodds, ends->oth);
  
  /* SCFG */
  if (cyk) CYKRNAScanFast(ofp, sqinfoX, isegX, sqinfoY, isegY, win, j, jmod, l, emodel->rna, emodel->null,
			  mtx, logodds, traceback);
  else     InsideRNAScanFast(ofp, sqinfoX, isegX, sqinfoY, isegY, win, j, jmod, l, emodel->rna, emodel->null,
			     mtx, mtx->sc, mtx->vp, fastintloop, logodds, traceback);
  
  /* Calculate oth cod and rna SCORES 
   *
   *
   *           Forward "full window" [dfmax == win-1 OR j == L-1]
   *
   *                        Store F(seq)[j][dfmax]   into F(seq)[jf]
   *
   *
   *           Backward a "full window" [j = L-1 - n*off AND j-off > 0 AND if (n>0) j+off-dbmax(j+off) > 0 ]
   *
   *                        Store F(seqrv)[j][dbmax] into F(seqrv)[jb] 
   *
   *
   */
  if (IsFullWindow(revstrand, L, win, slide, j))
    { 
      
     /* Do the OTH HMM-like calculation
       */
      othsc = ViterbiOTHDiagScanFast(ofp, sqinfoX, isegX, sqinfoY, isegY, L, win, j-dmax, (jmod-dmax<0)? jmod-dmax+win:jmod-dmax, l, lmax,
				     emodel->oth, dpoth, revstrand, traceback, doends, ends->oth);
      /* Do the COD HMM-like calculation
       */
      codsc = ViterbiCODDiagScanFast(ofp, sqinfoX, isegX, sqinfoY, isegY, L, win, j-dmax, (jmod-dmax<0)? jmod-dmax+win:jmod-dmax, l, lmax,
				     emodel->cod, dpcod, emodel->null, ali, alignment, logodds, revstrand, traceback, doends, ends); 
      /* Do the RNA HMM-like calculation
       */
      rnasc = EvolViterbiRNADiagScanFast(ofp, sqinfoX, isegX, sqinfoY, isegY, gss, L, win, j-dmax, (jmod-dmax<0)? jmod-dmax+win:jmod-dmax, l, lmax,
					 emodel, dprna, mtx, ali, alignment, cyk, logodds, parse, revstrand, traceback, doends, ends); 
      
      /* 
       * STORE SCORES if at a "full window"
       */
      if (d >= 0 && d == dmax) {
	
	n_windows ++;
	

	if (revstrand) {  
	  if (j < win-1) jwrite = L - 1;
	  else           jwrite = (L-1) + (win-1) -j;    
	  
	  /* paranoia */
	  if (IndexForwardWindow (L, win, slide, jwrite) != IndexBackwardWindow (L, win, slide, j)) 
	    Die ("check the jwrite assignments for the backward strand [jwrite, dfmax(jwrite)] = %d %d [j, dbmax(j)] = %d %d\n",
		 jwrite, IndexForwardWindow (L, win, slide, jwrite), j, IndexBackwardWindow (L, win, slide, j));
	  
	}
	else {
	  jwrite = j;
	}  

	idx = IndexWindow(j, L, win, slide, revstrand);
	
	if (idx > NumberScanningWindows(L, win, slide)) 
	  Die("score_viterbi_diag_scan_fast(): wrong number of windows (%d %d)", idx,  NumberScanningWindows(L, win, slide));
	
	othscwin[idx] = othsc;
	codscwin[idx] = codsc;
	rnascwin[idx] = rnasc;
	
	if (revstrand) CopyEnd3ScanFast(scanfast->ends->rev[idx], ends);
	else           CopyEnd3ScanFast(scanfast->ends->fwd[idx], ends);
	
      }
      
    }
  
  FreeEnd3ScanFast(ends);
  
  *ret_windows = n_windows;
}
