////////////////////////////////////////////////////////////////////////
//
// Score.h - contains classes for different kinds of scoring systems
//
// $Id: Score.C,v 1.7 2001/12/26 10:42:13 goetz Exp $
//
////////////////////////////////////////////////////////////////////////

#include "Score.h"

Score::~Score()
{
  delete [] colVal;
}

DiffScore::DiffScore(const Alignment &test, const Alignment &ref,
	       const SecWeight &sweight, const PwDistWeight &pweight)
  : Score("DiffScore")
{
  int alen( test.aliLength() ),
    numseq( test.numOfSeq() );
  colVal= new int[alen];
  int sum( 0 );
  
  for (int i=0; i<alen; i++) {
    // calculate a certain column "i":
    // Difference-SPScore: sum all pairs (j,k): 0 < j < numseq, 0 <= k < j
    int tmp= 0;                          // use for faster addition
    for (int j=1; j < numseq; j++)
      for (int k=0; k<j; k++) {
	// the conversion works as follows:
	// test.sequences[j][i].pos - get position of char in unaligned seq
	// -1 is marking a gap, so don't care for them, since only chars
	// are compared!!
	// ref.positions[j][ <this value> ] - get pos of char in ref alignment
	int pj= test.sequences[j][i].pos;
	int pk= test.sequences[k][i].pos;
	if ( (pj == -1) && (pk == -1) ); // two gaps - do nothing !
	else if ( (pj != -1) && (pk != -1) ) {
	  if ( ref.positions[j][ pj ] != ref.positions[k][ pk ] )
	    // they were found to be aligned to different residues, so increase
	    // number of differently aligned chars, weighted by sec str. data
	    // and pairwise sequence distance weight
	    tmp += int(max( sweight.w( test.sequences[j][i] ), 
			    sweight.w( test.sequences[k][i] ))
		       * pweight.d(j,k));
	} else if (pj == -1 ) { // we found one gap, have a look at ref al.
	  // now check if in reference there is a gap in sequence j as well.
	  // this can be done via the pk coordinate:
	  if ( ref.sequences[j][ ref.positions[k][ pk ] ].pos != -1 ) 
	    // oops, no gap, so increase differency count:
	    tmp += int(max( sweight.w( test.sequences[j][i] ), 
			    sweight.w( test.sequences[k][i] ))
		       * pweight.d(j,k));
	} else { // pk == -1, same for pk
	  if ( ref.sequences[k][ ref.positions[j][ pj ] ].pos != -1 ) 
	    // oops, no gap, so increase differency count:
	    tmp += int(max( sweight.w( test.sequences[j][i] ), 
			    sweight.w( test.sequences[k][i] ))
		       * pweight.d(j,k));
	}
      }
    colVal[i] = tmp;
    sum += tmp;
  }
  value= sum;
}

SPScore::SPScore(const Alignment &al, const ScoreMatrix &scr,
		 const SecWeight &sweight, const PwDistWeight &pweight)
  : Score("SPScore")
{
  int alen( al.aliLength() ),
    numseq( al.numOfSeq() );
  colVal= new int[alen];
  int sum( 0 );

  for (int i=0; i<alen; i++) {
    // calculate a certain column "i":
    // SPScore: sum all pairs (j,k): 0 < j < numseq, 0 <= k < j
    int tmp= 0;                          // use for faster addition
    for (int j=1; j < numseq; j++)
      for (int k=0; k<j; k++)
	tmp += int(scr.sc( al.sequences[j][i], al.sequences[k][i] )
		   * max( sweight.w( al.sequences[j][i] ), 
			  sweight.w( al.sequences[k][i] ))
		   * pweight.d(j, k) );
    colVal[i] = tmp;
    sum += tmp;
  }
  value= sum;
}
