/********************************************************************************************************
 * 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.
 ***********************************************************************************************************/

/* evolscorewithmodels.c
 *
 * ER, Mon Aug 16 12:28:45 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 add_abs_to_end3s (int start, struct end3_s *end3s);
static void add_abs_to_ends (int start, struct end_s *ends);
static void cal_structure (FILE *ofp,
			   SQINFO sqinfoX, int *seqX,  
			   SQINFO sqinfoY, int *seqY, 
			   char *gss, int start, int L, 
			   struct rnamodel_s *rnamodel, 
			   struct rnascfg_s  *mx, 
			   struct sc3_s      *sc, 
			   int cyk, int logodds, int do_nus, int parse, int rnass, int traceback, struct end_s *rnaends, int isrnarev);
static void print_window_ends (FILE *ofp, int start, int leg, char *whichmodel, struct end_s *ends, int isreverse, int winnerstrand);
static void score_with_null(FILE *ofp, 
			    int *isegX, int *isegY, int len, 
			    struct nullmodel_s *null, 
			    double nullsc, 
			    double nullrevsc, 
			    int verbose);

static int score_global(FILE *ofp, 
			SQINFO sqinfoX, int *isegX, 
			SQINFO sqinfoY, int *isegY, 
			char *gss, int start, int win, 
			struct dos_s      d, 
			struct emodel_s   *emodel, 
			struct dpd_s     *dpd, 
			struct rnascfg_s *mx, 
			struct sc3_s     *sc, 
			struct ali_s     *ali, 
			int *ret_scfg_status, int *ret_scfgrv_status,
			int cyk, int fastintloop, int logodds, int ones, int parse, int rnass, int sweep, int traceback, 
			int doends, struct windowends_s *windowends);

static int score_viterbi_diag(FILE *ofp, 
			      FILE *regressfp, char *regressionfile, 
			      SQINFO sqinfoX, int *isegX, 
			      SQINFO sqinfoY, int *isegY,  
			      char *gss, int start, int win,
			      struct dos_s      d, 
			      struct emodel_s   *emodel,
			      struct dpd_s     *dpd, 
			      struct rnascfg_s *mx, 
			      struct sc3_s     *sc, 
			      struct ali_s     *ali, 
			      int *ret_scfg_status, int *ret_scfgrv_status,
			      int alignment, int cyk, int fastintloop, int logodds, int ones, int parse, int rnass, int sweep, int traceback, 
			      int doends, struct windowends_s *windowends);

static int score_forward_diag(FILE *ofp, 
			      SQINFO sqinfoX, int *isegX, 
			      SQINFO sqinfoY, int *isegY, 
			      char *gss, int start, int win, 
			      struct dos_s      d, 
			      struct emodel_s   *emodel, 
			      struct dpd_s     *dpd, 
			      struct rnascfg_s *mx, 
			      struct sc3_s     *sc, 
			      struct dpsc3_s   *ardiag, 
			      struct ali_s     *ali, 
			      int *ret_scfg_status, int *ret_scfgrv_status,
			      int cyk, int fastintloop, int logodds, int ones, int parse, int sweep, struct windowends_s *windowends);

static int score_semi(FILE *ofp, 
		      SQINFO sqinfoX, int *iseqX, int startX, int lenX, 
		      SQINFO sqinfoY, int *iseqY, int startY, int lenY,
		      char *gss, int start, int *ret_legnew, int Lw, 
		      struct dos_s      d,  
		      struct emodel_s   *emodel, 
		      struct dpd_s     *dpd, 
		      struct othdpf_s  *othdpf, 
		      struct rnascfg_s *mx, 
		      struct scores_s  *sc, 
		      struct ali_s     *ali, 
		      int alignment, int cyk, int fastintloop, int logodds, int ones, int parse, int rnass, int sweep, int traceback, 
		      int doends, struct windowends_s *windowends);

static int score_full(FILE *ofp, 
		      SQINFO sqinfoX, int *iseqX, int startX, int lenX, 
		      SQINFO sqinfoY, int *iseqY, int startY, int lenY,
		      char *gss, int start, int *ret_legnew, int Lw, 
		      struct dos_s     d, 
		      struct emodel_s   *emodel, 
		      struct dpf_s     *dpf, 
		      struct rnascfg_s *mx, 
		      struct scores_s  *sc, 
		      struct ali_s     *ali, 
		      int alignment, int cyk, int fastintloop, int logodds, int ones, int parse, int rnass, int sweep, int traceback,
		      int doends, struct windowends_s *windowends);

static void test_OTH_model(FILE *ofp, 
			   SQINFO sqinfoX, int *isegX, 
			   SQINFO sqinfoY, int *isegY, 
			   int win,  
			   struct othmodel_s *oth, 
			   struct othdpd_s   *othdp, 
			   double            *othsc, 
			   struct ali_s      *ali, 
			   int alignment, int traceback, 
			   struct windowends_s *windowends);


/* Function: EvolScoreWithModels()
 * Date:     ER, Mon Aug 16 12:30:57 CDT 2004 [St. Louis at work, Coro at Maribel's]
 *
 * Purpose:  decide which scoring method to use. Called by main().
 *
 * Args:     
 *
 * Returns:  void.
 */
void
EvolScoreWithModels(FILE *ofp, 
		    FILE *printqfp,  char *printqfile, 
		    FILE *regressfp, char *regressionfile, 
		    SQINFO sqinfoX, int *isegX, int *iseqX, 
		    SQINFO sqinfoY, int *isegY, int *iseqY, 
		    char *gss,
		    int start, int win, int Lw, 
		    struct dos_s      d, 
		    struct emodel_s  *emodel, 
		    struct dpd_s     *dpd, 
		    struct dpf_s     *dpf, 
		    struct rnascfg_s *mx, 
		    struct scores_s  *sc, 
		    struct ali_s     *ali, 
		    int alignment, int cyk, int doends, int fastintloop, int logodds, int ones, int parse, int rnass, 
		    int shuffle, int sre_shuffle, int con_shuffle,
		    int sweep, int traceback, int verbose, int use_win_id, struct three_times_s time)
{
  struct windowends_s *windowends;
  int                  startX, endX;        /* first and last position of analysis for seqX   */
  int                  startY, endY;        /* first and last position of analysis for seqY   */
  int                  lenX, lenY;          /* len of seq's  without gaps                     */
  int                  fstX, fstY;          /* mapping of startX and startY to the seq without gaps */
  int                  leg_new;
  int                  is_significant;
  int                  scfg_status;
  int                  scfgrv_status;
  int                *iseqshX, *iseqshY;
  int                *seqX,    *seqY;
  double             *freqX,   *freqY;
  double             id, gap, mut;

  windowends = AllocWindowEnds();

  /* default values */
  
  is_significant = FALSE; /* TRUE = OTH score is significant, continue scoring with the COD and RNA models        */
  scfg_status    = FALSE; /* TRUE = the scfg part of the RNA model has already been calculated -- given strand    */
  scfgrv_status  = FALSE; /* TRUE = the scfg part of the RNA model has already been calculated -- reverse strand  */

  lenX = win;
  lenY = win; 
  
  if (sweep) startX = 0;
  else       startX = start;
  startY = start;
  endX = startX + lenX - 1;
  endY = startY + lenY - 1;

  freqX = AllocBaseFreq();
  freqY = AllocBaseFreq();
  
  
  /* (0) leg = minimum length of aligment 
     RemoveJointGaps(lenX, isegX+startX, lenY, isegY+startY, &win); 
     
     *
     * this function can be passed to analyze_2_sequences() in "qrna.c" if 
     * one wants to remove the common gaps of the two alignments globally.
     * The difference is only relevant when using a window.
     */
  
  /*if (verbose) 
    test_OTH_model(ofp, sqinfoX, isegX+startX, sqinfoY, isegY+startY, win, model->cod->COJ, 
		   dpd->oth, sc->ardiag->oth, ali, alignment, traceback, ends->oth);
  */

  /* if (shuffle == TRUE) shuffle aligment */
  if (shuffle || sre_shuffle || con_shuffle) {
    AllocIntSeqs(win, &iseqshX, &iseqshY);
    DupIntSeq(isegX, iseqshX, startX+win-1, win-1);
    DupIntSeq(isegY, iseqshY, startY+win-1, win-1);  

    if (shuffle)     Shuffle2IntSequences(iseqshX, iseqshY, win, win-1, win-1, verbose);
    if (sre_shuffle) QRNAIntShuffle(iseqshX, iseqshY, win);
    if (con_shuffle) QRNAIntConservedShuffle(iseqshX, iseqshY, win);

    seqX = iseqshX;
    seqY = iseqshY;
  }
  else {
    seqX = isegX+startX;
    seqY = isegY+startY;
  }

  PercIdSeqs(seqX, seqY, win-1, win-1, &id, &gap, &mut);

  PrintQfile(printqfp, printqfile, sqinfoX, seqX, sqinfoY, seqY, 0, win, start);
    
  /* (1) duplicate the region (start, start+win-1) of iseg into iseq. 
   *     Remove the gaps, and calculate lenX, and lenY.
   */
  DupIntSeq(seqX, iseqX, win-1, win-1);
  DupIntSeq(seqY, iseqY, win-1, win-1);  
      
  RemoveGaps(iseqX, win, &lenX, verbose); /* len of seqX without gaps */
  RemoveGaps(iseqY, win, &lenY, verbose); /* len of seqY without gaps */

  fstX = PosNoGaps(isegX, startX);
  fstY = PosNoGaps(isegY, startY);

  if (!sweep) {
    fprintf(ofp, "length alignment: %d (id=%.2f) (mut=%.2f) (gap=%.2f)", win, id, mut, gap);
    if      (shuffle)     fprintf(ofp, "(shuffled)\n");
    else if (sre_shuffle) fprintf(ofp, "(sre_shuffled)\n");
    else if (con_shuffle) fprintf(ofp, "(con_shuffled)\n");
    else                  fprintf(ofp, "\n");
    
    BaseComp(ofp, iseqX, lenX-1, lenX-1, freqX);
    BaseComp(ofp, iseqY, lenY-1, lenY-1, freqY);

    fprintf(ofp, "posX: %d-%d [%d-%d](%d) -- (%.2f %.2f %.2f %.2f) \n", 
	    startX, endX, fstX, fstX+lenX-1, lenX, freqX[0], freqX[1], freqX[2], freqX[3]);
    fprintf(ofp, "posY: %d-%d [%d-%d](%d) -- (%.2f %.2f %.2f %.2f) \n", 
	    startY, endY, fstY, fstY+lenY-1, lenY, freqY[0], freqY[1], freqY[2], freqY[3]);
  }

  /* Regression test info.
   */
  if (regressionfile != NULL) 
    PrintScanBanner(regressfp, startX, endX, lenX, lenY, fstX, fstY, freqX, freqY, id, gap, mut, use_win_id, time);
  
  /* Calculate the null-model scores
   */
  score_with_null(ofp, seqX, seqY, win, emodel->null, sc->null, sc->nullrev, verbose);
  
  /* GLOBAL (global alignment   */
  if (d.global) 
    is_significant = 
      score_global(ofp, sqinfoX, seqX, sqinfoY, seqY, gss, start, win, d, emodel, dpd, 
		   mx, sc->global, ali, &scfg_status, &scfgrv_status, 
		   cyk, fastintloop, logodds, ones, parse, rnass, sweep, traceback, doends, windowends);
  
  /* VITERBI (diag local aligmnent) 
   */
  if (d.vidiag) 
    is_significant = 
      score_viterbi_diag(ofp, regressfp, regressionfile, sqinfoX, seqX, sqinfoY, seqY, gss, start, win, d, emodel, dpd, 
			 mx, sc->vidiag, ali, &scfg_status, &scfgrv_status, 
			 alignment, cyk, fastintloop, logodds, ones, parse, rnass, sweep, traceback, doends, windowends);
  
  /* FORWARD (diag local aligmnent)
   */
  if (d.frdiag) 
    is_significant = 
      score_forward_diag(ofp, sqinfoX, seqX, sqinfoY, seqY, gss, start, win, d, emodel, dpd, 
			 mx, sc->frdiag, sc->ardiag, ali, &scfg_status, &scfgrv_status, 
			 cyk, fastintloop, logodds, ones, parse, sweep, windowends);

  /* SEMI-DIAG local aligmnent. [Here is where we use iseq]  
   */
  if (d.visemi || d.frsemi)
    is_significant = 
      score_semi(ofp, sqinfoX, iseqX, 0, lenX, sqinfoY, iseqY, 0, lenY, gss, start, &leg_new, Lw, d, emodel, 
		 dpd, dpf->oth, mx, sc, ali, alignment, 
		 cyk, fastintloop, logodds, ones, parse, rnass, sweep, traceback, doends, windowends);
  

  /* FULL local aligmnent.  [Here is where we use iseq]
   */
  if (d.vifull || d.frfull)
    is_significant = 
      score_full(ofp, sqinfoX, iseqX, 0, lenX, sqinfoY, iseqY, 0, lenY, gss, start, &leg_new, Lw, d, emodel,
		 dpf, mx, sc, ali, alignment, 
		 cyk, fastintloop, logodds, ones, parse, rnass, sweep, traceback, doends, windowends);
  
  if (is_significant && sweep) {
    fprintf(ofp, "length alignment: %d ", win);
    if (shuffle) fprintf(ofp, "(shuffled)\n");
    else         fprintf(ofp, "\n");
    
    BaseComp(ofp, iseqX, lenX-1, lenX-1, freqX);
    BaseComp(ofp, iseqY, lenY-1, lenY-1, freqY);

   fprintf(ofp, "posX: %d-%d [%d-%d](%d) -- (%.2f %.2f %.2f %.2f) \n", 
	   startX, endX, fstX, fstX+lenX-1, lenX, freqX[0], freqX[1], freqX[2], freqX[3]);
   fprintf(ofp, "posY: %d-%d [%d-%d](%d) -- (%.2f %.2f %.2f %.2f) \n", 
	   startY, endY, fstY, fstY+lenY-1, lenY, freqY[0], freqY[1], freqY[2], freqY[3]);
  }
  
  if (!d.vidiag && !d.vifull && !d.visemi && alignment) 
    Print2Seqs(ofp, &sqinfoX, seqX, &sqinfoY, seqY, 0, win);
  
  if (shuffle) {
    free(iseqshX);
    free(iseqshY);
  }
  free(freqX); free(freqY);
  FreeWindowEnds(windowends);
}

void
add_abs_to_ends (int start, struct end_s *ends)
{
  int x;

      for (x = 0; x < MAX_NUM_ENDS; x++) 
	if (ends->lend[x] > -1 && ends->rend[x]-ends->lend[x] > 0) {
	  ends->lend[x] += start;
	  ends->rend[x] += start;
	}
}

void
add_abs_to_end3s (int start, struct end3_s *end3s)
{
  add_abs_to_ends (start, end3s->oth);
  add_abs_to_ends (start, end3s->cod);
  add_abs_to_ends (start, end3s->rna);
}

void
cal_structure (FILE *ofp,
	       SQINFO sqinfoX, int *seqX,  
	       SQINFO sqinfoY, int *seqY, 
	       char *gss, int start, int L, 
	       struct rnamodel_s *rnamodel, 
	       struct rnascfg_s  *mx, 
	       struct sc3_s      *sc, 
	       int cyk, int logodds, int do_nus, int parse, int rnass, int traceback, struct end_s *rnaends, int isrnarev)
{
  int d;
  
  d = abs(rnaends->rend[0] - rnaends->lend[0]);
  
  if (d > 0) {
    if (cyk && ((rnass) || traceback)) 
      {
	if (!parse)
	  CYKTracebackRNA(ofp, sqinfoX, seqX, sqinfoY, seqY, gss, start, L, rnamodel->pi2, mx, do_nus, logodds, TRUE, rnaends, isrnarev);
	else 
	  CYKParseTracebackRNA(ofp, sqinfoX, seqX, sqinfoY, seqY, gss, start, L, rnamodel->pi2, mx, do_nus, logodds, traceback, rnaends, isrnarev);
      }
    
    if (!cyk && rnass) 
      PosteriorRNA(ofp, sqinfoX, seqX, sqinfoY, seqY, gss, start, L, rnamodel, mx, do_nus, logodds, traceback, rnaends, isrnarev);
  }
}

void
score_with_null(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);
}

int
score_global(FILE *ofp, 
	     SQINFO sqinfoX, int *isegX, 
	     SQINFO sqinfoY, int *isegY, 
	     char *gss, int start, int win,
	     struct dos_s      d, 
	     struct emodel_s   *emodel, 
	     struct dpd_s     *dpd, 
	     struct rnascfg_s *mx, 
	     struct sc3_s     *sc, 
	     struct ali_s     *ali, 
	     int *ret_scfg_status, int *ret_scfgrv_status,
	     int cyk, int fastintloop, int logodds, int ones, int parse, int rnass, int sweep, int traceback, 
	     int doends, struct windowends_s *windowends)
{
  struct end_s *rnaends;
  int isrnarev = FALSE;
  int scfg_status;
  int scfgrv_status;
 
  scfg_status   = *ret_scfg_status;
  scfgrv_status = *ret_scfgrv_status;

  ScoreWithOTH2(ofp, isegX, isegY, 0, win, emodel->oth, sc->oth, ones, traceback);
  ScoreWithCOD(ofp, isegX, isegY, 0, win, emodel->cod, emodel->null, dpd->cod, sc->cod, logodds, ones, traceback);
  EvolScoreWithRNA(ofp, sqinfoX, isegX, sqinfoY, isegY, gss, 0, win, emodel, dpd->oth, mx, sc->rna,
		   ret_scfg_status, ret_scfgrv_status, cyk, fastintloop, logodds, d.nus, ones, parse, traceback);
  
  if (sc->rna->mn > sc->rna->pl) { isrnarev = TRUE;  rnaends = windowends->rev->rna; }
  else                           { isrnarev = FALSE; rnaends = windowends->fwd->rna; }

  /* since this is "global", ends are the total ends
   */
  windowends->fwd->cod->lend[0] = 0;
  windowends->rev->cod->lend[0] = 0;
  windowends->fwd->cod->rend[0] = win - 1;
  windowends->rev->cod->rend[0] = win - 1;
  
  windowends->fwd->oth->lend[0] = 0;
  windowends->rev->oth->lend[0] = 0;
  windowends->fwd->oth->rend[0] = win - 1;
  windowends->rev->oth->rend[0] = win - 1;
  
  windowends->fwd->rna->lend[0] = 0;
  windowends->rev->rna->lend[0] = 0;
  windowends->fwd->rna->rend[0] = win - 1;
  windowends->rev->rna->rend[0] = win - 1;
  
  cal_structure(ofp, sqinfoX, isegX, sqinfoY, isegY, gss, 0, win, emodel->rna, mx, sc, 
		cyk, logodds, d.nus, parse, rnass, traceback, rnaends, isrnarev);

  /* add absolute position to ends
   */
  add_abs_to_end3s(start, windowends->fwd);
  add_abs_to_end3s(start, windowends->rev);

  fprintf(ofp, "GLOBAL -- ");
  RNAbanner(ofp, cyk);

  PrintScores(ofp, sc, doends, windowends, start, start+win, ones);

  *ret_scfg_status   = scfg_status;
  *ret_scfgrv_status = scfgrv_status;

  return 1;
}

int
score_viterbi_diag(FILE *ofp, 
		   FILE *regressfp, char *regressionfile, 
		   SQINFO sqinfoX, int *isegX, 
		   SQINFO sqinfoY, int *isegY,  
		   char *gss, int start, int win,
		   struct dos_s      d, 
		   struct emodel_s   *emodel, 
		   struct dpd_s     *dpd,  
		   struct rnascfg_s *mx, 
		   struct sc3_s     *sc, 
		   struct ali_s     *ali, 
		   int *ret_scfg_status,int *ret_scfgrv_status,
		   int alignment, int cyk, int fastintloop, int logodds, int ones, int parse, int rnass, int sweep, int traceback, 
		   int doends, struct windowends_s *windowends)
{
  struct end_s *rnaends;
  int   isrnarev = FALSE;
  int   scfg_status;
  int   scfgrv_status;

  scfg_status   = *ret_scfg_status;
  scfgrv_status = *ret_scfgrv_status;

  ViterbiOTHDiag(ofp, sqinfoX, isegX, sqinfoY, isegY, 0, win, emodel->oth, dpd->oth, sc->oth, 
		 ali, alignment, ones, sweep, traceback, doends, windowends);
   /*if (sweep && sc->oth < 0.0) return 0;*/

  ViterbiCODDiag(ofp, sqinfoX, isegX, sqinfoY, isegY, 0, win, emodel->cod, dpd, emodel->null, sc->cod, 
		ali, alignment, logodds, ones, traceback, doends, windowends);  
  EvolViterbiRNADiag(ofp, sqinfoX, isegX, sqinfoY, isegY, gss, 0, win, emodel, dpd, mx, sc->rna, 
		     ali, &scfg_status, &scfgrv_status, alignment, cyk, fastintloop, logodds, 
		     d.nus, ones, parse, traceback, doends, windowends);
  
 /* Regression test info.
   */
  if (regressionfile != NULL) {
    fprintf(regressfp, "+> %f %f %f\n", sc->oth->pl,sc->cod->pl,sc->rna->pl);
    fprintf(regressfp, "-> %f %f %f\n", sc->oth->mn,sc->cod->mn,sc->rna->mn);
  }
  
  if (sc->rna->mn > sc->rna->pl) { isrnarev = TRUE;  rnaends = windowends->rev->rna; }
  else                           { isrnarev = FALSE; rnaends = windowends->fwd->rna; }
  
  cal_structure(ofp, sqinfoX, isegX, sqinfoY, isegY, gss, 0, win, emodel->rna, mx, sc, 
		cyk, logodds, d.nus, parse, rnass, traceback, rnaends, isrnarev);
  
  /* add absolute position to ends
   */
  add_abs_to_end3s(start, windowends->fwd);
  add_abs_to_end3s(start, windowends->rev);
 
  fprintf(ofp, "LOCAL_DIAG_VITERBI -- ");
  RNAbanner(ofp, cyk);
  PrintScores(ofp, sc, doends, windowends, start, start+win, ones);

  *ret_scfg_status   = scfg_status;
  *ret_scfgrv_status = scfgrv_status;

  return 1;
}

int
score_forward_diag(FILE *ofp, 
		   SQINFO sqinfoX, int *isegX, 
		   SQINFO sqinfoY, int *isegY,
		   char *gss, int start, int win, 
		   struct dos_s      d, 
		   struct emodel_s   *emodel, 
		   struct dpd_s     *dpd, 
		   struct rnascfg_s *mx, 
		   struct sc3_s     *sc, 
		   struct dpsc3_s   *ardiag, 
		   struct ali_s     *ali, 
		   int *ret_scfg_status, int *ret_scfgrv_status,
		   int cyk, int fastintloop, int logodds, int ones, int parse, int sweep, struct windowends_s *windowends)
{   
 int scfg_status;
 int scfgrv_status;

  scfg_status   = *ret_scfg_status;
  scfgrv_status = *ret_scfgrv_status;

  ForwardOTHDiag(ofp, isegX, isegY, 0, win, emodel->oth, dpd->oth, sc->oth, ardiag->oth, ones);
  /*if (sweep && sc->oth < 0.0) return 0;*/

  ForwardCODDiag(ofp, isegX, isegY, 0, win, emodel->cod, dpd, emodel->null, sc->cod, logodds, ardiag, ones);
  EvolForwardRNADiag(ofp, sqinfoX, isegX, sqinfoY, isegY, gss, 0, win, emodel, dpd, mx, sc->rna, ardiag, 
		 &scfg_status, &scfgrv_status, cyk, fastintloop, logodds, d.nus, ones, parse);
  
  fprintf(ofp, "LOCAL_DIAG_FORWARD -- ");
  RNAbanner(ofp, cyk);
  PrintScores(ofp, sc, FALSE, windowends, start, start+win, ones);

  *ret_scfg_status   = scfg_status;
  *ret_scfgrv_status = scfgrv_status;

  return 1;
}


/* Function: score_semi()
 * Date:     ER, Sat Feb 26 16:34:13 CST 2000 [St. Louis]
 *
 * Purpose:  this is a little trick, to not to have to implement the full COD/RNA.
 *      
 *           I take the "new aligment" generated by 
 *           ViterbiOTH_L2() and use it to calculate COD and RNA scores
 *           as if it where a "given alignment" therefore as a diag DP
 *
 * Args:     
 *
 * Returns:  void.
 */
int
score_semi(FILE *ofp, 
	   SQINFO sqinfoX, int *iseqX, int startX, int lenX, 
	   SQINFO sqinfoY, int *iseqY, int startY, int lenY,
	   char *gss, int start, int *ret_legnew, int Lw, 
	   struct dos_s      d, 
	   struct emodel_s   *emodel, 
	   struct dpd_s     *dpd, 
	   struct othdpf_s  *othdpf, 
	   struct rnascfg_s *mx, 
	   struct scores_s  *sc, 
	   struct ali_s     *ali, 
	   int alignment, int cyk, int fastintloop, int logodds, int ones, int parse, int rnass, int sweep, int traceback, 
	   int doends, struct windowends_s *windowends)
{
  struct end_s *rnaends;
  int     Ltot;       /* total space necessary to allocate a possible alignment of the two sequences */
  int     legnew;     /* length of new aligment generated by full viterbi                            */
  int     isrnarev      = FALSE;
  int     scfg_status   = FALSE;
  int     scfgrv_status = FALSE;
  double  id, gap, mut;

  /* (1) apply full viterbi according to the OTH emodel
   */
  ViterbiOTHFull(ofp, sqinfoX, iseqX, sqinfoY, iseqY, startX, startY, lenX, lenY,
		 &legnew, Lw, emodel->oth, othdpf, sc->vifull->oth, ali, alignment, ones, sweep, traceback, doends, windowends);
  
  /*if (sweep && sc->visemi->oth < -300.0) return 0;*/

  /* (2) dump the alignments in iseq and calculate the length of the alignment
   */

  Ltot = (lenX > lenY)? 2*lenX : 2*lenY;
  IntizeGapAsequence(ali->charX, Ltot-legnew, legnew, iseqX, FALSE);
  IntizeGapAsequence(ali->charY, Ltot-legnew, legnew, iseqY, FALSE);
  
  PercIdSeqs(iseqX, iseqY, legnew-1, legnew-1, &id, &gap, &mut);

  if (legnew > 2*Lw) 
    Die ("alignment is larger than allocated space\n");
    
  if (d.visemi) 
    {
      ViterbiCODDiag(ofp, sqinfoX, iseqX, sqinfoY, iseqY, 0, legnew, emodel->cod, dpd, emodel->null, sc->visemi->cod, 
		     ali, alignment, logodds, ones, traceback, doends, windowends);

      /*if (sweep && sc->visemi->oth < 0.0) return 0;*/

      EvolViterbiRNADiag(ofp, sqinfoX, iseqX, sqinfoY, iseqY, gss, 0, legnew, emodel, dpd, mx, sc->visemi->rna, ali, 
			 &scfg_status, &scfgrv_status, alignment, cyk, fastintloop, logodds, d.nus, ones, parse, traceback, doends, windowends);
      
      if (sc->visemi->rna->mn > sc->visemi->rna->pl) { isrnarev = TRUE;  rnaends = windowends->rev->rna; }
      else                                           { isrnarev = FALSE; rnaends = windowends->fwd->rna; }

      cal_structure(ofp, sqinfoX, iseqX, sqinfoY, iseqY, gss, 0, legnew, emodel->rna, mx, sc->visemi, 
		    cyk, logodds, d.nus, parse, rnass, traceback, rnaends, isrnarev);
 
      /* add absolute position to ends
       */
      add_abs_to_end3s(start, windowends->fwd);
      add_abs_to_end3s(start, windowends->rev);
      
      fprintf(ofp, "LOCAL_SEMI_VITERBI -- ");
      RNAbanner(ofp, cyk);
      fprintf(ofp, "length alignment: %d (id=%.2f) (gap=%.2f) (mut=%.2f)\n", legnew, id, gap, mut);
      PrintScores(ofp, sc->visemi, doends, windowends, start, start+legnew, ones);    
    }

  if (d.frsemi) 
    {
      ForwardOTHDiag(ofp, iseqX, iseqY, 0, legnew, emodel->oth, dpd->oth, sc->frsemi->oth, sc->ardiag->oth, ones);
      /*if (sweep && sc->frsemi->oth < -300.0) return 0;*/

      ForwardCODDiag(ofp, iseqX, iseqY, 0, legnew, emodel->cod, dpd, emodel->null, sc->frsemi->cod,
		     logodds, sc->ardiag, ones);
      EvolForwardRNADiag(ofp, sqinfoX, iseqX, sqinfoY, iseqY, gss, 0, legnew, emodel, dpd, mx, sc->frsemi->rna, sc->ardiag, 
			 &scfg_status, &scfgrv_status, cyk, fastintloop, logodds, d.nus, ones, parse);

      fprintf(ofp, "LOCAL_SEMI_FORWARD -- ");
      RNAbanner(ofp, cyk);
      PrintScores(ofp, sc->frsemi, doends, windowends, start, start+legnew, ones);
    }

  *ret_legnew = legnew;
  return 1;
}

int
score_full(FILE *ofp, 
	   SQINFO sqinfoX, int *iseqX, int startX, int lenX, 
	   SQINFO sqinfoY, int *iseqY, int startY, int lenY,
	   char *gss, int start, int *ret_legnew, int Lw, 
	   struct dos_s      d, 
	   struct emodel_s   *emodel, 
	   struct dpf_s     *dpf, 
	   struct rnascfg_s *mx, 
	   struct scores_s  *sc, 
	   struct ali_s     *ali, 
	   int alignment, int cyk, int fastintloop, int logodds, int ones, int parse, int rnass, int sweep, int traceback, 
	   int doends, struct windowends_s *windowends)
{
  int legnew;     /* length of new aligmnt generated by full viterbi  */

 /* apply full-viterbi/full-froward according to the three  emodels
   */
  if (d.vifull) {
    if (!d.visemi)
      ViterbiOTHFull(ofp, sqinfoX, iseqX, sqinfoY, iseqY, startX, startY, lenX, lenY, &legnew, Lw, 
		     emodel->oth, dpf->oth, sc->vifull->oth,
		     ali, alignment, ones, sweep, traceback, doends, windowends);
    else {
      sc->vifull->oth = sc->visemi->oth;
      legnew = *ret_legnew;
    }

  /* this one compares the different ways of calculating viterbiOTHFull
   */
  
   if (FALSE) 
      CompareOTHFull(ofp, sqinfoX, iseqX, sqinfoY, iseqY, startX, lenX, startY, lenY, 
		     &legnew, Lw, emodel->cod->COJ, dpf->oth, ali, windowends);

   ViterbiCODFull(ofp, sqinfoX, iseqX, sqinfoY, iseqY, startX, startY, lenX, lenY, &legnew, Lw,
		  emodel->cod, dpf, emodel->null, sc->vifull->cod,
		  ali, alignment, logodds, ones, traceback, doends, windowends);
     
    sc->vifull->rna->pl = 0.0;
    sc->vifull->rna->mn = 0.0;
    
    /* add absolute position to ends
     */
    add_abs_to_end3s(start, windowends->fwd);
    add_abs_to_end3s(start, windowends->rev);
    
    fprintf(ofp, "LOCAL_FULL_VITERBI --under construction -- ");
    RNAbanner(ofp, cyk);
    fprintf(ofp, "length of alignment: %d\n", legnew);
    PrintScores(ofp, sc->vifull, doends, windowends, start, start+legnew, ones);
  }
  
  if (d.frfull) {
    ForwardOTHFull(ofp, iseqX, iseqY, startX, startY, lenX, lenY, Lw, emodel->oth, dpf->oth, sc->frfull->oth, sc->arfull->oth, ones);

    sc->frfull->cod->pl = 0.0;
    sc->frfull->cod->mn = 0.0;
    sc->frfull->rna->pl = 0.0;
    sc->frfull->rna->mn = 0.0;
    
    fprintf(ofp, "LOCAL_FULL_FORWARD -- under construction -- ");
    RNAbanner(ofp, cyk);
    PrintScores(ofp, sc->frfull, doends, windowends, start, start+legnew, ones);
  }

  *ret_legnew = legnew;

  return 1;
}

void
test_OTH_model(FILE *ofp, 
	       SQINFO sqinfoX, int *isegX, 
	       SQINFO sqinfoY, int *isegY, 
	       int win,
	       struct othmodel_s *oth, 
	       struct othdpd_s   *othdp, 
	       double            *othsc, 
	       struct ali_s      *ali, 
	       int alignment, int traceback, struct windowends_s *windowends)
{
  struct end_s *othends;

  othends = windowends->fwd->oth;

  TestViterbiOTH(ofp, sqinfoX, isegX, sqinfoY, isegY, 0, win, oth, othdp, 
		 ali, alignment, traceback, othends);
  TestForwardOTH(ofp, isegX, isegY, 0, win, oth, othdp, othsc);
  CompareOTH(ofp, sqinfoX, isegX, sqinfoY, isegY, 0, win, oth, othdp, 
	     othsc, ali, alignment, traceback);
}


void
print_window_ends (FILE *ofp, int start, int leg, char *whichmodel, struct end_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 = start + leg - 1 - ends->lend[x];
	    lend = start + 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");  
    }
  
}
