////////////////////////////////////////////////////////////////////////
//
// Alignment.h - a class containing all data structures for storing a 
//               multiple sequence alignment
//
// $Id: Alignment.h,v 1.7 2001/12/28 18:27:15 goetz Exp $
//
////////////////////////////////////////////////////////////////////////

#ifndef ALIGNMENT_H
#define ALIGNMENT_H

#include "Exception.h"
#include <iostream.h>
#include <vector.h>
#include <string>

///////////////////////////////////////////////////////////////////////
// Data types for storing sequences

/** data type for storing a position of a sequence character whithin
 *  a sequence 
 */
typedef int Alcharpos;

//////////////////////////////////////////////////////////////////////
/** Data type for storing information about secondary structures */
struct SecStructure
{
  /** types of considered secondary structures 
   */
  enum stype { UNKNOWN=0, ALPHA, BETA };
  
  /** kind of secondary structure */
  stype type;
  /** beginning in sequence */
  Alcharpos beg;
  /** end in sequence */
  Alcharpos end;

  /** default constructor: create unknown sec_structure object */
  SecStructure() 
    : type( UNKNOWN ), beg(0), end(0) 
  {}
  
  /** create object with given parameters */
  SecStructure( stype type, Alcharpos beg, Alcharpos end )
    : type(type), beg(beg), end(end) 
  {}

  /** calculate length of secondary structure */
  unsigned int len() const
  { return end-beg; }
};

// for (debugging) output - only type is written ("a" / "b" / " ");
class ostream & operator << ( class ostream &, const SecStructure &);

//////////////////////////////////////////////////////////////////////
// Data type for a character in an alignment (with position information
// and secondary structure info)

struct Alchar 
{
  // the character stored
  char c;
  // position within sequence
  Alcharpos pos;
  // secondary structure
  SecStructure secstr;

  /** default constructor: no data */
  Alchar() {};

  /** constructor: without secondary structure and position.
   *  Handle with care!
   */
  Alchar( char c )
    : c(c), pos(0)
  {}

  /** constructor: without secondary structure */
  Alchar( char c, Alcharpos pos )
    : c(c), pos(pos)
  {}

  /** constructor: with all */
  Alchar( char c, Alcharpos pos, const SecStructure &secstr ):
    c(c), pos(pos), secstr(secstr)
  {}

  /** gives info, whether char is gap; must be represented as '.' ! */
  bool isGap () const
  { return c == '.'; }
};

class ostream & operator << ( class ostream &, const Alchar &);

//////////////////////////////////////////////////////////////////////
/** data structure for storing an alignment */
struct Alignment
{
  /** the name of the alignment */
  const string name;
  /** the real data storage where the sequences are stored 
   *  sequences[i][j] holds al_i[j]
   */
  Alchar **sequences;
  /** auxiliary array: gives positions of characters of original sequences
   *  in alignment: positions[i][j] gives position of char s_i[j] in 
   *  sequences[i], -1 if gap
   */
  Alcharpos **positions;
  /** auxiliary array: length of original sequences */
  Alcharpos *origLength;

  /** constructor: create an alignment from an .msf -file (GCG/MSF-File 
   *  format - the alignment and sequence length in the header are ignored)
   *  this version does not parse any secondary structure information file
   * @param msf   open input stream operating on the .msf file
   * @param name  name for the alignment - printed in output etc.
   */
  Alignment( istream &msf, const string &name= "<unnamed>" )
    throw (IOException, FFormatException );
  
  /** constructor: create an alignment from an .msf -file (GCG/MSF-File 
   *  format - the alignment and sequence length in the header are ignored)
   * @param msf   open input stream operating on the .msf file
   * @param ftb   open input stream on the .ftb structure file
   * @param refal open input stream on the .msf reference alignment file
   * @param name  name for the alignment - printed in output etc.
   */
  Alignment( istream &msf, istream &ftb, istream &refal,
	     const string &name= "<unnamed>" )
    throw (IOException, FFormatException );
  
  /** return number of sequences of the alignment */
  unsigned int numOfSeq () const
  { return seqnames.size(); }

  /** return length of alignment */
  unsigned int aliLength () const
  { return buffers[0].length(); }

  /** a flag stating if secondary structure information is available */
  bool hasSecStr;

  // number of sequence is determined during parsing, so we need a dynamic
  // data structure: vector<string>
  vector<string> seqnames;

  // destructor: clean up all dynamically allocated stuff
  ~Alignment();
private:
  /** read alignment (following headers) from the .msf file 
   *  @param if        input file 
   */ 
  void readMsfIntoBuffers( istream &is )
    throw ( IOException, FFormatException );
  /** create sequence array from alignment */
  void parseBuffers();
  /** reads BAliBASE .msf Alignment file and creates the according alignment
   *  as a conversion containing the conversion between reference alignment 
   *  positions and absolute (sequence) positions.
   *  needs seqnames to be set up already for order checking in .msf file 
   */
  void readFtbFile( istream &ftb, istream &refAl )
    throw ( IOException, FFormatException );
  // some internal states and variables for the the communication between
  // the above functions

  string* buffers;
}; // class Alignment

// for debugging output:
class ostream & operator << ( class ostream &, const Alignment &);

#endif
