////////////////////////////////////////////////////////////////////////
//
// PwDistWeight.h - gives weighting factors for pairwise sequence 
//                  distances
//
// $Id: PwDistWeight.h,v 1.10 2002/01/11 17:06:05 goetz Exp $
//
////////////////////////////////////////////////////////////////////////

#ifndef PWDISTWEIGHT_H
#define PWDISTWEIGHT_H

#include "Alignment.h"
#include "ScoreMatrix.h"
#include "Exception.h"

//////////////////////////////////////////////////////////////////////
// abstract base class for all pairwise distance weighting matrices
class PwDistWeight
{
public:
  /** this function gives the distance weight of two chars */
  virtual double d(unsigned int i, unsigned int j) const =0;
  
  PwDistWeight(const string &name, unsigned int numOfSeq =0)
    : numOfSeq(numOfSeq), name(name)
  {};
  
  /** returns description of scoring matrix */
  operator const string() const 
  { return name; }

  /** number of sequences stored */
  const unsigned int numOfSeq;

  /** destructor */
  virtual ~PwDistWeight() {};
private:
  string name;
};

// debugging output: print pairwise distances matrix:
class ostream &operator << ( class ostream &, const PwDistWeight &);

//////////////////////////////////////////////////////////////////////
// default class: all factors are 1
class DefaultPwDist : public PwDistWeight
{
public:
  /** this function gives the distance weight of two chars */
  virtual double d(unsigned int i, unsigned int j) const;

  DefaultPwDist()
    : PwDistWeight("DefaultPwDist")
  {};
};

//////////////////////////////////////////////////////////////////////
// demo class : distance weight is difference between indices
class PwIndDist : public PwDistWeight
{
public:
  virtual double d(unsigned int i, unsigned int j) const;
  
  PwIndDist()
    : PwDistWeight("PwIndDist")
  {};
};

//////////////////////////////////////////////////////////////////////
// distance weights are (optionally scaled) pairwise distances between
// sequences
class PwDistDynPrg : public PwDistWeight
{
public:
  virtual double d(unsigned int i, unsigned int j) const;

  /** generate matrix of all pairwise distances of the unaligned 
   *  sequences of alignment "a" using the dynamic programming and
   *  the scoring System "s".
   *  If "scaleMax" <>0, all distances are translated to the interval 
   *  [0..scaleMaxTo], where:
   *               minimal Score -> 0
   *               maximal Score -> scaleMaxTo
   *  (the translation is affine-linear)
   *  If "changeorder" flag is given, all values are then changed as
   *    score -> scaleMaxTo-score
   *  hence:
   *               minimal Score -> scaleMaxTo
   *               maximal Score -> 0
   */
  PwDistDynPrg( const Alignment &a, const ScoreMatrix &s, 
		double scaleMaxTo= 0, bool changeOrder= false);
  
  /** for verifying / output: the value the maximum is scaled to */
  const double scaleMaxTo;

  /** order changed */
  const bool changeOrder;

  // destructor for cleanup
  ~PwDistDynPrg();
private:
  double **pwDist;
  const ScoreMatrix &s;
  // calculate pairwise distance of two sequences
  int pwAlign( const string &s1, const string &s2 );
  // maximum of 2 integers
  int max( int i1, int i2 )
  { return i1 > i2 ? i1 : i2; }
  // maximum of 3 integers
  int max( int i1, int i2, int i3 )
  { return max(i1, max(i2, i3)); }
};

//////////////////////////////////////////////////////////////////////
// class for scoring only sequences that belong to the same group 
// or upweighting groups 
// uses *.html description file to get group info
class GroupPwCut : public PwDistWeight
{
public:
  /** this function gives the distance weight of two chars */
  virtual double d(unsigned int i, unsigned int j) const;
  
  /** initialise pairwise weighting scheme: read data from BAliBASE
   *  .html-file. The alignment should contain data corresponding to the
   *  .html-file and is used to determine the order and internal number of
   *  the sequences and sequence names.
   *  See below for meaning of other parameters
   */
  GroupPwCut(class istream &ifs, const Alignment &al,
	     double groupWeight= 1, double noGroupWeight= 0)
    throw ( FFormatException );

  /** weight for a pair of sequences belonging to one group */
  const double groupWeight;

  /** weight for a pair of sequences belonging to different groups */
  const double noGroupWeight;

  virtual ~GroupPwCut();
private:
  bool **sameGroup;
};
#endif
