#ifndef GENOTYPE_MATRIX_H
#define GENOTYPE_MATRIX_H

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

#include "Utils.h"
#include "BioSequenceMatrix.h"

typedef pair<int, int> COLUMN_PAIR;

// ***************************************************************************
// Define a reusable binary matrix class
// ***************************************************************************
class GenotypeMatrix : public BioSequenceMatrix
{
public:
    GenotypeMatrix();
    ~GenotypeMatrix();
    GenotypeMatrix(int nr, int nc);

    // Support assignment/copy constructor
    GenotypeMatrix(const GenotypeMatrix &rhs);
    GenotypeMatrix &operator=(const GenotypeMatrix &rhs);

    // Important interface functions we need
    virtual bool IsDataValid(int val); // check to see if this data is good for this class
                                       // e.g. for genotype data, 0, 1, 2
    virtual bool IsColComplement(int c1, int c2);
    virtual bool IsColDuplicate(int c1, int c2);
    virtual int GetMajorityState(int site);

    // DPPH needs these functions
    void PreSolve(); // perform neccessary preprocessing. For now, assume DPPH
    bool AreColumnsCompanion(int c1, int c2);
    bool AreColumnsForcedInPhase(int c1, int c2);
    bool AreColumnsForcedOutPhase(int c1, int c2);
    bool AreColumnsComplete(int c1, int c2);
    int GetNumTwosInRow(int r);
    bool IsSiteTrival(int site);

private:
    // Internal functions
    void SetupCompanionColumns(); // Initialize companion rows

    // Private data structures
    typedef map<COLUMN_PAIR, set<int>> COMPANION_ROW_MAP;
    COMPANION_ROW_MAP companionRows;
    typedef map<COLUMN_PAIR, int> FORCED_COL_MAP;
    FORCED_COL_MAP forcedColumnPairs; // value = 1 if out of phase, = 0 if in phase, otherwise no entry
    vector<COLUMN_PAIR> completePairs;
};

#endif //GENOTYPE_MATRIX_H
