#include "BioSequenceMatrix.h"
#include <cmath>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <fstream>
#include "Utils2.h"


// ***************************************************************************
// Define a reusable binary matrix class
// ***************************************************************************
#if 0
BioSequenceMatrix :: BioSequenceMatrix()
{
    fMissingValue = false;
}
#endif

BioSequenceMatrix :: ~BioSequenceMatrix() 
{
	Clear();
}


void BioSequenceMatrix :: AppendRow( const vector<int> &row )
{
    // Check to see if this is the first row, if so OK
    if( nCols == 0 && GetRowNum() == 0)
    {
        nCols = row.size();
    }

	if(row.size() != (unsigned int)nCols)
	{
		DEBUG("WRONG row width in AddRow");
		return; 
	}

	int *buf = new int [nCols]; 
	for(int i=0; i< nCols; ++i)
	{
		buf[i] = row[i];
	}
	rowsArray.push_back(buf); 
}

void BioSequenceMatrix :: AppendSetOfRows( const set<SEQUENCE> &rows)
{
    for( set<SEQUENCE> :: iterator it = rows.begin(); it != rows.end(); ++it)
    {
        AppendRow( *it );
    }
}

void BioSequenceMatrix :: AppendRows( const vector<SEQUENCE> &rows)
{
    for( unsigned int i = 0; i< rows.size(); ++i)
    {
        AppendRow( rows[i] );
    }
}

// This function removes a set of columns that are specified in the set as duplicateSites
void BioSequenceMatrix :: InsertColumns( const vector< SEQUENCE> &sitesValue , const vector<int> &sitesPos )
{
    // we require the site contains the same number of values as rows
    YW_ASSERT_INFO( sitesPos.size() == (unsigned int) sitesValue.size(), "Wrong vector size.");
    YW_ASSERT_INFO( sitesValue.size() > 0, "Can not be empty.");
    YW_ASSERT_INFO( sitesValue[0].size() == (unsigned int)GetRowNum(), "Size mismatch." );

    int totalLen = GetColNum() + sitesPos.size();

    // First we need to calculate where to put these new sites
    // remember the passed-in values are BEFORE insertion. For example, when we say we want to insert sites a,b
    // at location 0, 2, when mean we want to put a at 0 (this pushes the value forward
    vector<int> poses;
    int offset = 0;
    for(unsigned int i=0; i<sitesPos.size(); ++i)
    {
        // Treat out of ranges as close to real
        int realPos = sitesPos[i];
        if( realPos < 0 )
        {
            realPos = 0;
        }
        else if( realPos > GetColNum() )
        {
            realPos = GetColNum();
        }
        poses.push_back( realPos + offset );
        offset ++;
    }
//cout << "poses = ";
//DumpIntVec( poses );
	// now we create  a new matrix with different size
	for(unsigned int i=0; i<rowsArray.size(); ++i)
	{
		int *buf = new int[ totalLen ];
		int origPos = 0;
        int pos = 0;
		for(unsigned int j=0; j< poses.size(); ++j)
		{
//cout << "1. origPos = " << origPos << ", pos = " << pos << endl;
            for( ; pos < poses[j] ; ++pos)
            {
                buf[pos] = rowsArray[i][origPos++];
            }
            // Now add poses[j]
//cout << "Before assign site,  origPos = " << origPos << ", pos = " << pos << endl;
            buf[pos++] = sitesValue[j][i];

		}
        // We finish any leftover
        for( ; pos < totalLen; ++pos, ++origPos )
        {
//cout << "2. origPos = " << origPos << ", pos = " << pos << endl;
            buf[ pos ] =  rowsArray[i][origPos];
        }


		// now we free the memory of old buffer
		delete [] rowsArray[i];
		rowsArray[i] = buf;
	}

	nCols = totalLen; 
}

void BioSequenceMatrix :: AppendMatrixByCol( const BioSequenceMatrix & appendedMat)
{
    // Append the matrix by putting the matrix to the right
    // Make sure the row matches
    YW_ASSERT_INFO( appendedMat.IsEmpty() == false , "For now, do not allow appending empty matrix.");
    YW_ASSERT_INFO( IsEmpty() || GetRowNum() == appendedMat.GetRowNum(), "Can not append such matrix" );

    // Figure out the size
	vector<int *> rowsArrayNew;	// array of rows
    int rowNum, colNum;
    if( IsEmpty() == false)
    {
        rowNum = GetRowNum();
        colNum = GetColNum();
    }
    else
    {
        // Use the new matrix's value
        rowNum = appendedMat.GetRowNum();
        colNum = 0;
    }
    int numSitesNew = colNum + appendedMat.GetColNum();
    // Allocate space
    for(int r=0; r<rowNum; ++r)
    {
        int *buf = new int[ numSitesNew ];
        rowsArrayNew.push_back( buf );
    }
    // Now copy the stuff in
    for(int r=0; r<rowNum; ++r)
    {
        for(int c = 0; c < colNum; ++c)
        {
            rowsArrayNew[r][c]= rowsArray[r][c];
        }
        for(int c=0; c<appendedMat.GetColNum(); ++c)
        {
            rowsArrayNew[r][c + colNum ] = appendedMat(r, c );
        }
    }

    // Remove the old ones
    Clear();
    // Set to the new one
    nCols = numSitesNew;
    rowsArray = rowsArrayNew;
}

void BioSequenceMatrix :: AppendMatrixByRow( const BioSequenceMatrix & appendedMat)
{
    // Append the matrix by putting the matrix to the right
    // Make sure the row matches
    YW_ASSERT_INFO( appendedMat.IsEmpty() == false , "For now, do not allow appending empty matrix.");
    YW_ASSERT_INFO( IsEmpty() || GetColNum() == appendedMat.GetColNum(), "Can not append such matrix" );

    // Now copy the stuff in
    for(int r=0; r<appendedMat.GetRowNum(); ++r)
    {
		SEQUENCE seq;
		appendedMat.GetRow( r, seq );
		this->AppendRow( seq );
    }
}



void BioSequenceMatrix :: SetRow(int r, const vector<int> &valNew)
{
	if(valNew.size() != (unsigned int)nCols)
	{
		DEBUG("WRONG row width in SetRow");
		return; 
	}
	for(int i=0; i<nCols; ++i)
	{
		rowsArray[r][i] = valNew[i];
	}
}

void BioSequenceMatrix :: SetCol(int c, const vector<int> &valNew)
{
	if(valNew.size() != (unsigned int) GetRowNum() )
	{
		DEBUG("WRONG row width in SetRow");
		return; 
	}
	for(int i=0; i<GetRowNum(); ++i)
	{
		rowsArray[i][c] = valNew[i];
	}
}

void BioSequenceMatrix :: Clear()
{
	// Need to free up data if needed
	for(unsigned int i=0; i<rowsArray.size(); ++i)
	{
		delete [] rowsArray[i]; 
	}
    rowsArray.clear();
	nCols = 0; 
}

void BioSequenceMatrix :: Copy(const BioSequenceMatrix &rhs)
{
	Clear();	// 012713: it seems we should clear this one first
	for(unsigned int i=0; i<rhs.rowsArray.size(); ++i)
	{
		int *buf = new int [ rhs.nCols ]; 
		for(int j=0; j<rhs.nCols; ++j)
		{
			buf[j] = rhs.rowsArray[i][j]; 
		}
		rowsArray.push_back( buf ); 
	}
	nCols = rhs.nCols; 
}


			   
void  BioSequenceMatrix :: RemoveRow( int rowIndex )
{
	if( (unsigned int)rowIndex >= rowsArray.size() )
	{
		return; 
	}

	int nPos = -1; 
	for(vector<int *> :: iterator it = rowsArray.begin(); it != rowsArray.end(); ++it)
	{
		nPos ++; 
		if(nPos == rowIndex)
		{
            delete [] *it;
			rowsArray.erase ( it );
			return; 
		}
	}
	DEBUG("Something very wrong inside BioSequenceMatrix :: RemoveRow");
}

// Consolidate rows in matrix
void BioSequenceMatrix:: TrimDupRows(set<int> *pTrimedRows, vector<pair<int,int> > *pTrimRowInfo  )
{

	set<int> setOfDuplicates;
	vector< pair<int,int> > listRowsDeletedWithExistingPairs;
	setOfDuplicates.clear(); 
	unsigned int r1, r2;
    int c;

	//bool res = false;		// we stop unless we find some duplicate rows and/or non-informat site

	for(r1=0; r1<rowsArray.size(); ++r1)
	{
		for( r2 = r1+1; r2 < rowsArray.size(); ++r2)
		{
			/*
				Now test whether row 1 and row 2 are the same
			*/
			bool fSame = true;
			for(c = 0; c< nCols; ++c)
			{
				if(rowsArray[r1][c] != rowsArray[r2][c])
				{
					fSame = false;
					break;
				}
			}
			if(  fSame )
			{
				if( setOfDuplicates.find(r2) == setOfDuplicates.end() )
				{
					pair<int,int> pp;
					pp.first = r2;			// first item is which row is removed
					pp.second = r1;			// second item is which row is the source (to be kepted)
					listRowsDeletedWithExistingPairs.push_back(pp);
				}

//cout << "row " << r2 << " is duplicate." << endl;
				setOfDuplicates.insert(  r2 );
			}
		}
	}
	/*
		Now we remove all duplicate rows 
	*/
	if( setOfDuplicates.size() > 0 )
	{
	//	res = true;
		RemoveRows( setOfDuplicates ); 
	}
	if( pTrimedRows != NULL )
	{
		*pTrimedRows = setOfDuplicates;
	}
	if( pTrimRowInfo != NULL )
	{
		*pTrimRowInfo = listRowsDeletedWithExistingPairs;
	}

	return;
}

void BioSequenceMatrix :: DumpRowMultiplicity() const
{
    // This function dump out duplicate row information
    map<SEQUENCE, int> mapRowMultiplicity;
    for(int r = 0; r< GetRowNum(); ++r)
    {
        SEQUENCE row;
        GetRow( r, row );
        if( mapRowMultiplicity.find( row ) == mapRowMultiplicity.end() )
        {
            mapRowMultiplicity.insert( map<SEQUENCE,int> :: value_type (row, 1) );
        }
        else
        {
            mapRowMultiplicity[row]++;
        }
    }
    // Now dump out info
    cout << "In this matrix, the multiplicity of rows is: \n";
    for( map<SEQUENCE, int> :: iterator it = mapRowMultiplicity.begin(); it != mapRowMultiplicity.end(); ++it )
    {
        cout << "seq = ";
        DumpSequence( it->first );
        cout << ", multiplicty = ";
        cout << it->second << endl;
    }
}

void BioSequenceMatrix :: GetColMultiplicityMap( vector<int> &listColMulti ) const
{
    // for each col (site), find out the number of duplicate each site has (that is, listMulti[i] = # of sites with the same column)
    listColMulti.clear();
    listColMulti.resize( GetColNum() );
    map<SEQUENCE, set<int> > mapColMulti;
    for(int c=0; c<GetColNum(); ++c)
    {
        SEQUENCE col;
        GetCol(c, col);
        mapColMulti[col].insert(c);
    }
    for( map<SEQUENCE, set<int> > :: iterator it = mapColMulti.begin(); it != mapColMulti.end(); ++it)
    {
        for(set<int> :: iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2)
        {
            listColMulti[ *it2 ] = it->second.size();
        }
    }
}

int BioSequenceMatrix :: GetMultiplictyForRow( int r ) const
{
    SEQUENCE seqRow;
    GetRow( r, seqRow );
    return GetMultiplictyForRow( seqRow );
}

int BioSequenceMatrix :: GetMultiplictyForRow( const SEQUENCE &seqRow ) const
{
    int res = 0;
    for(int i=0; i<GetRowNum(); ++i)
    {
        SEQUENCE curRow;
        GetRow(i, curRow);
        if( curRow == seqRow )
        {
            ++res;
        }
    }
    return res;
}

int BioSequenceMatrix :: GetMultiplictyForRow( const SEQUENCE &seqRow, set<int> &identRows ) const
{
    identRows.clear();
    int res = 0;
    for(int i=0; i<GetRowNum(); ++i)
    {
        SEQUENCE curRow;
        GetRow(i, curRow);
        if( curRow == seqRow )
        {
            identRows.insert( i );
            ++res;
        }
    }
    //YW_ASSERT_INFO( res > 0, "Must appear at least once." );
    return res;
}


int BioSequenceMatrix :: GetMultiplictyForRowIV(int r, int left, int right) const
{
    SEQUENCE row;
    GetRow(r, row );
    SEQUENCE rowIV;
    GetSeqInterval( row, rowIV, left, right);
    int res = 0;
    for(int i=0; i<GetRowNum(); ++i)
    {
        SEQUENCE curRow;
        GetRow(i, curRow);
        SEQUENCE rowIV1;
        GetSeqInterval( curRow, rowIV1, left, right);

        if( rowIV1 == rowIV )
        {
            ++res;
        }
    }
    return res;
}



bool BioSequenceMatrix :: ReadFromFile( ifstream &inFile, bool fSkipFirstLine )
{
	bool res = true; 

	// Now, we first check one row to find out how many sites
	// first read in the matrix name first
	const int BUF_SZ = MAX_SITE_NUM*sizeof(int);
    char buf[BUF_SZ];		// assume maximum sites allowed are 4096
    if( fSkipFirstLine == true )
    {
        inFile.getline(buf, BUF_SZ);
//	cout << "Matrix name is " << buf << endl; 
    }
    
	int rowLength = 0;
	while( !inFile.eof() )
	{
		inFile.getline(buf, BUF_SZ);
		DEBUG("strlen of buf ");
		DEBUG(strlen(buf));
		DEBUG("\n");
		DEBUG("buffer is:");
		DEBUG(buf);
		DEBUG("\n");
        
        // ignore any ine starting with #
        if( buf[0] == '#')
        {
            continue;
        }
        
		int curRowLen = 0 ;
		curRowLen = strlen(buf);
		// but we need to check to make sure there is no garbage character at the end
		for(int i=curRowLen-1;;)
		{
			if(i >0 &&   buf[i]  != '0' && buf[i] != '1' && buf[i] != '2' 
                && buf[i] != '*' && buf[i] != '?' )	
			{
				i--;
				curRowLen --;
			}
			else
			{
				break;
			}
		}

		if(rowLength == 0)
		{
			rowLength = curRowLen; 
		}
		if(rowLength != curRowLen )
		{
			// for some reason, we are getting a smaller size
			// simplely terminate here
			//DEBUG("Warning: one row of fle seems to have fewer data bits.\n");
			//res = false;
			break;
		}
		int *pRow = new int[rowLength];
		for(int i=0; i<rowLength; ++i)
		{
			if(buf[i] == '1')
			{
				pRow[i] = 1;
			}
			else if(buf[i] == '0')
			{
				pRow[i] = 0;
			}
			else if(buf[i] == '2')
			{
				pRow[i] = 2;
			}
            else if( buf[i] == '*' || buf[i] == '?' )
            {
                pRow[i] = MISSING_VALUE_BIT;
            }
            else
            {
                printf( "Read one line: %s\n", buf);
                YW_ASSERT_INFO(false, "Un-recognized characters in input.");
                exit(1);
            }
		}
		// Now put it into a list
		rowsArray.push_back(pRow);
	}


	// Now set return value
	nCols = rowLength;

	
	return res;
}

#if 0
bool BioSequenceMatrix :: ReadFromFilePartial( ifstream &inFile, bool fSkipFirstLine )
{
    // different from the previous version, read from the middle of the file and stop whenever needed
    bool res = true;
    
	// Now, we first check one row to find out how many sites
	char buf[MAX_SITE_NUM];		// assume maximum sites allowed are 4096
    
	// first read in the matrix name first
	const int BUF_SZ = MAX_SITE_NUM*sizeof(int);
    if( fSkipFirstLine == true )
    {
        inFile.getline(buf, BUF_SZ);
        //	cout << "Matrix name is " << buf << endl;
    }
    
	int rowLength = 0;
	while( !inFile.eof() )
	{
		inFile.getline(buf, BUF_SZ);
		DEBUG("strlen of buf ");
		DEBUG(strlen(buf));
		DEBUG("\n");
		DEBUG("buffer is:");
		DEBUG(buf);
		DEBUG("\n");
		int curRowLen = 0 ;
		curRowLen = strlen(buf);
		// but we need to check to make sure there is no garbage character at the end
		for(int i=curRowLen-1;;)
		{
			if(i >0 &&   buf[i]  != '0' && buf[i] != '1' && buf[i] != '2'
               && buf[i] != '*' && buf[i] != '?' )
			{
				i--;
				curRowLen --;
			}
			else
			{
				break;
			}
		}
        
		if(rowLength == 0)
		{
			rowLength = curRowLen;
		}
		if(rowLength != curRowLen )
		{
			// for some reason, we are getting a smaller size
			// simplely terminate here
			//DEBUG("Warning: one row of fle seems to have fewer data bits.\n");
			//res = false;
			break;
		}
		int *pRow = new int[rowLength];
		for(int i=0; i<rowLength; ++i)
		{
			if(buf[i] == '1')
			{
				pRow[i] = 1;
			}
			else if(buf[i] == '0')
			{
				pRow[i] = 0;
			}
			else if(buf[i] == '2')
			{
				pRow[i] = 2;
			}
            else if( buf[i] == '*' || buf[i] == '?' )
            {
                pRow[i] = MISSING_VALUE_BIT;
            }
            else
            {
                YW_ASSERT_INFO(false, "Un-recognized characters in input.");
                exit(1);
            }
		}
		// Now put it into a list
		rowsArray.push_back(pRow);
	}
    
	// Now set return value
	nCols = rowLength;
    
	return res;
}
#endif

// Dump the content of matrix
void BioSequenceMatrix :: Dump() const
{
	cout << "positions: Matrix has  ";
	cout << nCols;
	cout << " columns and ";
	cout << rowsArray.size() ;
	cout << " rows.\n";
	for(unsigned int i=0; i<rowsArray.size(); ++i)
	{
		for( int j=0; j< nCols; ++j)
		{
            if( rowsArray[i][j] != MISSING_VALUE_BIT)
            {
			    cout << rowsArray[i][j];
            }
            else
            {
                cout << "*";
            }
		}
		cout << endl;
	}
}

void BioSequenceMatrix :: OutputToFile(const char *fileName) const
{
    //
    ofstream outFile;
    outFile.open (fileName);
    OutputToFile(outFile);
#if 0
	outFile << "Matrix has  ";
	outFile << nCols;
	outFile << " columns and ";
	outFile << rowsArray.size() ;
	outFile << " rows.\n";
	for(unsigned int i=0; i<rowsArray.size(); ++i)
	{
		for( int j=0; j< nCols; ++j)
		{
            if( rowsArray[i][j] != MISSING_VALUE_BIT)
            {
			    outFile << rowsArray[i][j];
            }
            else
            {
                outFile << "*";
            }
		}
		outFile << endl;
	}
#endif
    outFile.close();
}

void BioSequenceMatrix :: OutputToFile(ofstream &outFile) const
{
    //
    //ofstream outFile;
    //outFile.open (fileName);
	outFile << "Matrix has  ";
	outFile << nCols;
	outFile << " columns and ";
	outFile << rowsArray.size() ;
	outFile << " rows.\n";
	for(unsigned int i=0; i<rowsArray.size(); ++i)
	{
		for( int j=0; j< nCols; ++j)
		{
            if( rowsArray[i][j] != MISSING_VALUE_BIT)
            {
			    outFile << rowsArray[i][j];
            }
            else
            {
                outFile << "*";
            }
		}
		outFile << endl;
	}
    //outFile.close();
}

void BioSequenceMatrix :: ExchangeColumns(int c1, int c2)
{
	// This function exchanges two columns in this matrix
	for(unsigned int i=0; i<rowsArray.size(); ++i)
	{
		int tmp = rowsArray[i][c1];
		rowsArray[i][c1] = rowsArray[i][c2]; 
		rowsArray[i][c2] = tmp;  
	}
} 

// Offer direct access, but do not allow direct assignment
const int &BioSequenceMatrix :: operator () (int r, int c)  const
{
	return rowsArray[r][c];
}

int &BioSequenceMatrix :: operator () (int r, int c)  
{
	return rowsArray[r][c];
}

const int & BioSequenceMatrix :: GetValAt(int r, int c) const
{
	return rowsArray[r][c];
}

void BioSequenceMatrix :: SetValAt(int r, int c, int val)
{
	rowsArray[r][c] = val;
}


void BioSequenceMatrix :: GetAllSequences( vector<SEQUENCE> &seqs ) const
{
    seqs.clear();
    for(int i = 0; i<GetRowNum(); ++i)
    {
        SEQUENCE row;
        GetRow( i, row );
        seqs.push_back( row );
    }
}


void BioSequenceMatrix :: SubMatrix ( int rt, int rb, int cl, int cr, BioSequenceMatrix &submat) const
{
	// This function gets a submatrix, bounded from top row (rt), bottom row (rb)
	// left column (cl), right column cr
	submat.Clear();
	submat.SetSize(rb-rt+1, cr-cl+1); 

	// Now we set rows
	for(int i=rt; i<=rb; ++i)
	{
		// get a vector of values
		vector<int> row; 
		for(int j=cl; j<=cr; ++j)
		{
			row.push_back( rowsArray[i][j] );
		}

		// set row to submatrix
		submat.SetRow(i - rt, row); 
	}
}

// This function gets a submatrix from selected sites
void BioSequenceMatrix ::  SubMatrixSelectedSites( const vector<int> &sites, BioSequenceMatrix &submat ) const
{
	// This function gets a submatrix, with same number of rows but smaller number of sites
	submat.Clear();
	submat.SetSize(rowsArray.size(), sites.size() ); 

	// Now we set rows
	for(unsigned int i=0; i<rowsArray.size(); ++i)
	{
		// get a vector of values
		vector<int> row; 
		for(unsigned int j=0; j<sites.size(); ++j)
		{
			int s = sites[j]; 
            YW_ASSERT_INFO(  s < GetColNum() , "SubMatrixSelectedSites: index out of range."  );
			row.push_back( rowsArray[i][s] );
		}

		// set row to submatrix
		submat.SetRow(i , row); 
	}
	
} 

void BioSequenceMatrix :: SubMatrixSelectedRows( const vector<int> &rows, BioSequenceMatrix &submat ) const 
{
	// This function gets a submatrix, with same number of rows but smaller number of sites
	submat.Clear();
	submat.SetSize(rows.size(), nCols );

	// Now set rows 
	for(unsigned int i=0; i<rows.size(); ++i)
	{
		vector<int> r;
		GetRow( rows[i], r);
		submat.SetRow(i, r); 
	}
}

void BioSequenceMatrix :: GetRow(int r,  vector<int> &row) const
{
	row.clear(); 
	for(int i=0; i<nCols; ++i)
	{
		row.push_back( rowsArray[r][i] );
	}
}
void BioSequenceMatrix :: GetCol(int c, vector<int> &col) const
{
    col.clear();
	for(int i=0; i<GetRowNum(); ++i)
	{
		col.push_back( rowsArray[i][c] );
	}
}

int BioSequenceMatrix :: FindRow(const SEQUENCE &seq) const
{
    // This function search the matrix to see if it contains this sequence
    // return -1 if not found
    YW_ASSERT_INFO( seq.size() == (unsigned int)GetColNum(), "Size does not match." );
    
    for(int i=0; i<GetRowNum(); ++i)
    {
        bool fFound = true;
        for(int j = 0; j<GetColNum(); ++j)
        {
            if(  rowsArray[i][j] != seq[j]  )
            {
                fFound = false;
                break;
            }
        }
        if( fFound == true)
        {
            return i;
        }
    }
    return -1;
}
int BioSequenceMatrix :: FindColumn(const SEQUENCE &seq) const
{
    // This function search the matrix to see if it contains this sequence
    // return -1 if not found
    YW_ASSERT_INFO( seq.size() == (unsigned int)GetRowNum(), "Size does not match." );
    
    for(int i=0; i<GetColNum(); ++i)
    {
        bool fFound = true;
        for(int j = 0; j<GetRowNum(); ++j)
        {
            if(  rowsArray[j][i] != seq[j]  )
            {
                fFound = false;
                break;
            }
        }
        if( fFound == true)
        {
//cout << "Col ";
//DumpIntVec( seq );
//cout << "is in this matrix: ";
//this->Dump();
            return i;
        }
    }
    return -1;
}

// This function removes a set of columns that are specified in the set as duplicateSites
void BioSequenceMatrix :: RemoveColumns( set<int> &duplicateSites  )
{
	if( duplicateSites.size() == 0 )
		return; 

	// now we create  a new matrix with different size
	for(unsigned int i=0; i<rowsArray.size(); ++i)
	{
		int *buf = new int[nCols - duplicateSites.size() ];
		int cPos = 0;
		for(int j=0; j< nCols; ++j)
		{
			if(  duplicateSites.find(j) == duplicateSites.end()    )
			{
				// j is not duplicate, so we should copy it
				buf[cPos++] = rowsArray[i][j];
			}
		}

		// now we free the memory of old buffer
		delete [] rowsArray[i];
		rowsArray[i] = buf;
	}

	nCols -= duplicateSites.size(); 
}

// Remove one row from matrix
void BioSequenceMatrix :: RemoveRows(  set<int> &setRows   )
{
	vector<int *> saveMat;

	for( unsigned int i=0; i<rowsArray.size(); ++i  )
	{
		if( setRows.find( i ) == setRows.end() )
		{
			// Only if row i is not inside the rows set, we will save it
			saveMat.push_back(   rowsArray[i] );
		}
		else
		{
			// Ohterwise, we free it
			delete [] rowsArray[i]; 
		}
	}

	/*
		Now revert back
	*/
	rowsArray.clear();
	rowsArray.swap(saveMat); 

}

void BioSequenceMatrix :: SetSize(int nr, int nc)
{
	// This function initialize a nr by nc matrix
	// and by default, fill in all 0 (false)
	nCols = nc; 
	for(int i=0; i<nr; ++i)
	{
		int *buf = new int [ nc ]; 
		for(int j=0; j<nc; ++j)
		{
			buf[j] = 0;
		}
		rowsArray.push_back( buf ); 
	}
}

void BioSequenceMatrix :: FindNgbrDupCompSites(set<int> *pRemovedSet )
{
	set<int> setOfRemovals;		// contains sites to be removed
	int cleft = 0;
	while( cleft < nCols-1)
	{
		// Check to see if the next row  immediately is complement or not 
		if( IsColComplement( cleft, cleft+1 ) == true || IsColDuplicate( cleft, cleft+1)== true)
		{
			setOfRemovals.insert( cleft+1 );
//cout << "Site " << cleft+1 << " is same/complement." << endl;
		}
		// Consider  next site
		cleft ++;
	}
    if( pRemovedSet != NULL)
    {
        pRemovedSet->clear();
        *pRemovedSet = setOfRemovals;
    }
	// Finally, remove columns
//	RemoveColumns( setOfRemovals );
}

void BioSequenceMatrix :: GetSeqsFeqs( map<SEQUENCE, int> &mapSeqFreqs )
{
    // Insert, for each sequence, how many times they appears in the matrix
    mapSeqFreqs.clear();

    for( int r = 0; r<GetRowNum(); ++r)
    {
        SEQUENCE row;
        GetRow( r, row );
        if( mapSeqFreqs.find( row ) == mapSeqFreqs.end()  )
        {
            map<SEQUENCE, int> :: value_type p( row, 1 );
            mapSeqFreqs.insert( p );
        }
        else
        {
            mapSeqFreqs[row] ++;
        }
    }
}

void BioSequenceMatrix :: GetSeqsOccurrence( map<SEQUENCE, set<int> > &mapSeqOccurs )
{
    // For each distinct seq, find their occurance (which rows match this seq)
    mapSeqOccurs.clear();
    
    for( int r = 0; r<GetRowNum(); ++r)
    {
        SEQUENCE row;
        GetRow( r, row );
        if( mapSeqOccurs.find( row ) == mapSeqOccurs.end()  )
        {
            set<int> ss;
            map<SEQUENCE, set<int> > :: value_type p( row, ss );
            mapSeqOccurs.insert( p );
        }
        mapSeqOccurs[row].insert(r);
    }
}

bool BioSequenceMatrix :: IsIntervalConsistent( int r1, int left1, int right1, int r2, int left2, int right2  ) const
{
//cout << "r1 = " << r1 << ", left1 = " << left1 << ", right1 = " << right1 ;
//cout << ", r2 = " << r2 << ", left2 = " << left2 << ", right2 = " << right2  << endl;
    // Test if the two interval are consistent (i.e. has the same value at the overlap
    INTERVAL iv1(left1, right1);
    INTERVAL iv2(left2, right2);
    INTERVAL ivInt;
    if( GetIntervalOverlap(iv1, iv2, ivInt )  == false )
    {
        // If the interval are not overlapping, yes, they are consistent
        return true;
    }
//cout << "intersection: left = " << ivInt.first << ", right = " << ivInt.second << endl;
    SEQUENCE row1;
    GetRow( r1, row1);
    SEQUENCE row1IV;
    GetSeqInterval( row1, row1IV, ivInt.first, ivInt.second );
    SEQUENCE row2;
    GetRow( r2, row2);
    SEQUENCE row2IV;
    GetSeqInterval( row2, row2IV, ivInt.first, ivInt.second );
    return ( row1IV == row2IV);
}


bool BioSequenceMatrix :: IsMissingValue()
{
#if 0
    // A rather inefficient way of doing things
    if( fMissingValue == true )
    {
        return true;
    }
#endif

    // now double check to make sure
    for( int r = 0; r < GetRowNum(); ++r  )
    {
        for(int c = 0; c< GetColNum(); ++c)
        {
            if( GetValAt(r, c) ==  MISSING_VALUE_BIT )
            {
            //    fMissingValue = true;
                return true;
            }
        }
    }
    return false;
}

bool BioSequenceMatrix :: IsMissingValueInSite( int c )
{
    // now double check to make sure
    for( int r = 0; r < GetRowNum(); ++r  )
    {
        if( GetValAt(r, c) ==  MISSING_VALUE_BIT )
        {
        //    fMissingValue = true;
            return true;
        }
    }
    return false;
}

bool BioSequenceMatrix :: IsMissingValueInRow( int r )
{
	return GetMissingValueNumInRow(r) > 0;
}

int BioSequenceMatrix :: GetMissingValueNumInRow( int r )
{
	int res = 0;
    // now double check to make sure
    for( int c = 0; c < GetColNum(); ++c  )
    {
        if( GetValAt(r, c) ==  MISSING_VALUE_BIT )
        {
            res++;
        }
    }
    return res;
}
int BioSequenceMatrix :: GetMissingValueNumInCol( int c )
{
    int res = 0;
    // now double check to make sure
    for( int r = 0; r < GetRowNum(); ++r  )
    {
        if( GetValAt(r, c) ==  MISSING_VALUE_BIT )
        {
            res++;
        }
    }
    return res;
}


void BioSequenceMatrix :: MapDupToNodup(map<int,int> &mapDupToNodup) const
{
    // create a mapping from no-duplicate to duplicate indices
    set<int> rowsProcessed;

    int rowNoDup = 0;
    for( int r=0; r<GetRowNum(); ++r )
    {
        if( rowsProcessed.find(r) != rowsProcessed.end() )
        {
            continue;
        }
        SEQUENCE seq;
        GetRow( r, seq );
        set<int> identRows;
        GetMultiplictyForRow( seq, identRows);
//cout << "seq = ";
//DumpSequence( seq );
//DumpIntSet( identRows );
        // Add to map
        for( set<int> :: iterator it = identRows.begin(); it != identRows.end(); ++it )
        {
            int ss = *it;
            mapDupToNodup.insert( map<int,int> :: value_type( ss, rowNoDup )  ) ;
        }
        rowNoDup ++;
        UnionSets( rowsProcessed, identRows );
    }
}

int BioSequenceMatrix :: GetNodupRowsNum( vector<int> *pListUniqeRowIndex ) const
{
    int res = 0;
    for( int r=0; r<GetRowNum(); ++r )
    {
        SEQUENCE seq;
        GetRow( r, seq );
//cout << "seq = ";
//DumpSequence( seq );
//DumpIntSet( identRows );
        // Add to map
        bool fUnique = true;
        for( int r2 = 0; r2 < r ; ++r2 )
        {
            SEQUENCE seq2;
            GetRow( r2, seq2 );
            if( seq2 == seq )
            {
                fUnique = false;
                break;
            }
        }
        if( fUnique == true )
        {
            res ++;
			if( pListUniqeRowIndex != NULL)
			{
				pListUniqeRowIndex->push_back(r);
			}
        }
    }
    return res;
}

///////////////////////////////////////////////////////////////////////////////////////////
//		Inernal utility functions
///////////////////////////////////////////////////////////////////////////////////////////




bool BioSequenceMatrix :: CmpColumns (int c1, int c2)
{
	bool res = true; 

	if(c1 == c2)
	{
		return true; 
	}

	for(unsigned int i=0; i<rowsArray.size(); ++i)
	{
		if(rowsArray[i][c1] != rowsArray[i][c2] )
		{
			res = false; 
			break; 
		}
	}

	return res;
} 



