#ifndef BIO_SEQUENCE_MATRIX_H
#define BIO_SEQUENCE_MATRIX_H

#include <list>
#include <vector>
#include <set>
#include <string>
#include <iostream>
#include <fstream>
#include <map> 
using namespace std;

#include "Utils.h"

#define MAX_SITE_NUM		1024000

// ***************************************************************************
// Common Utilities


// ***************************************************************************
// Define a reusable binary matrix class
// ***************************************************************************
class BioSequenceMatrix
{
public:
    //BioSequenceMatrix();
    virtual ~BioSequenceMatrix() = 0;

    // Important interface functions we need
    virtual bool IsDataValid(int val) = 0;      // check to see if this data is good for this class
                                                // e.g. for genotype data, 0, 1, 2
    void SetSize(int nr, int nc);

	// Matrix editing functions
	void AppendRow( const vector<int> &row );
    void AppendSetOfRows( const set<SEQUENCE> &rows);
    void AppendRows( const vector<SEQUENCE> &rows);
    void InsertColumns( const vector< SEQUENCE> &sitesValue , const vector<int> &sitesPos );
	void SetRow(int i, const vector<int> &valNew); 
	void SetCol(int i, const vector<int> &valNew); 
    void Clear();
    void Copy(const BioSequenceMatrix &rhs);
	virtual bool ReadFromFile( ifstream &inFile, bool fSkipFirstLine = true );
    //virtual bool ReadFromFilePartial( ifstream &inFile, bool fSkipFirstLine );
	void Dump() const;
    void OutputToFile(const char *fileName) const;
    void OutputToFile(ofstream &outFile) const;
	void RemoveRow( int rowIndex ); 
	void ExchangeColumns(int r1, int r2); 
	void RemoveColumns( set<int> &duplicateSites  );
	void RemoveRows(  set<int> &setRows   );
	void TrimDupRows( set<int> *pTrimedRows = NULL, vector<pair<int,int> > *pTrimRowInfo  =NULL); 
	virtual void FindNgbrDupCompSites(set<int> *pRemovedSet = NULL) ;
	virtual bool IsColComplement( int c1, int c2) = 0;
	virtual bool IsColDuplicate( int c1, int c2) = 0;
    void AppendMatrixByCol( const BioSequenceMatrix & appendedMat);
    void AppendMatrixByRow( const BioSequenceMatrix & appendedMat);


	// Overload operator for [], like a[1, 2]
	const int &operator ()(int r, int c) const;
	int& operator ()(int r, int c) ;
    const int &GetValAt(int r, int c) const;
	void SetValAt(int r, int c, int val);

	// Access matrix
    bool IsEmpty() const { return GetColNum() == 0 || GetRowNum() == 0; }
	int GetColNum() const { return nCols; }
	int GetRowNum() const { return rowsArray.size(); }
	void GetRow(int r, vector<int> &row) const; 
    void GetCol(int c, vector<int> &col) const;
    int FindRow(const SEQUENCE &seq) const;
    int FindColumn(const SEQUENCE &seq) const;
	void SubMatrix ( int rt, int rb, int cl, int cr, BioSequenceMatrix &submat) const; 
	void SubMatrixSelectedSites( const vector<int> &sites, BioSequenceMatrix &submat ) const; 
	void SubMatrixSelectedRows( const vector<int> &rows, BioSequenceMatrix &submat ) const; 
    void GetAllSequences(vector<SEQUENCE> &seqs) const;
    void GetSeqsFeqs( map<SEQUENCE, int> &mapSeqFreqs );
    void GetSeqsOccurrence( map<SEQUENCE, set<int> > &mapSeqOccurs );
    virtual int GetMajorityState( int site) = 0;
    void DumpRowMultiplicity() const;
    int GetMultiplictyForRow( int r ) const;
    int GetMultiplictyForRow( const SEQUENCE &seq ) const;
    int GetMultiplictyForRow( const SEQUENCE &seq, set<int> &identRows ) const;
    int GetMultiplictyForRowIV(int r, int left, int right) const;
    void GetColMultiplicityMap( vector<int> &listColMulti ) const;
    bool IsIntervalConsistent( int r1, int left1, int right1, int r2, int left2, int right2  ) const;
	bool IsMissingValue();
	bool IsMissingValueInSite( int c );
	bool IsMissingValueInRow( int r );
	int GetMissingValueNumInRow( int r );
    int GetMissingValueNumInCol(int c);
    void MapDupToNodup(map<int,int> &mapDupToNodup) const;
    int GetNodupRowsNum(vector<int> *pListUniqeRowIndex ) const;

protected:
    // Some functions
    bool CmpColumns (int c1, int c2); 

	// Internal data 
	// we represent a binary matrix as bool type
	vector<int *> rowsArray;	// array of rows
	int nCols;					// number of sites (columns)

private:
    // Disable certain operations
    BioSequenceMatrix & operator=( const BioSequenceMatrix &rhs) {return *this;}
    //bool fMissingValue;
};






#endif //BIO_SEQUENCE_MATRIX_H
