#pragma once
#include "ReadsMapping.h"
#include "MappingResult.h"
#include "LongReadsSet.h"

class CBestPairedMapping
{
public:
    CBestPairedMapping(void);
    ~CBestPairedMapping(void);
    CMappingResult bm1, bm2;
    int bestMappingNo;
    int validMappingNo;
    unsigned int minDiff;
    inline void update(CMappingResult &m1, CMappingResult &m2, bool excludeAmbigousRead);
};

class CPairedReadsMapping : public CReadsMapping
{
public:
    CPairedReadsMapping(void);
    CPairedReadsMapping(const MappingOpts P);
    ~CPairedReadsMapping(void);
    //int mapPairedReadsInASingleFile(CPairedReadsSet& readSet, CGenome_Index_TableQ& table);
    int mapPairedReadsInPairedFiles(CReadInBitsSet& readSet1, CReadInBitsSet& readSet2,
                                    CGenome_Index_TableQ& table);
    int mapPairedReads(CReadInBitsSet& readSet1, CReadInBitsSet& readSet2,
                       CGenome_Index_TableQ& table);
    int mapPairedLongReadsInBases(CLongReadsSet& longReadSet1, CLongReadsSet& longReadSet2, const CGenome_Index_TableQ& table);
    int dealMappedSingleRead(const CGenome_Index_TableQ& table, CAlignmentsQ & Que, CMappingResult &m, bool bFirstEnd);
    int dealMappedPairedReads(CGenome_Index_TableQ& table);
    int dealMappedLongPairedRead(CAlignmentsQ& q1, CAlignmentsQ& q2, CMappingResult& m1, CMappingResult& m2, const CGenome_Index_TableQ& table);
    // F3read and R3read are index in AlignmentsQ
    void dealNoMapping(const CGenome_Index_TableQ& table, CMappingResult& m1, CMappingResult& m2);
    int dealBestMapping(const CGenome_Index_TableQ& table, CBestPairedMapping& bestMP, CMappingResult& m1, CMappingResult& m2);
    int printValidMappedPair(const CGenome_Index_TableQ& table, CMappingResult& m1, CMappingResult& m2, int validMappedPairNo);
    int printBestMappedPair(const CGenome_Index_TableQ& table, CMappingResult& m1, CMappingResult& m2, int minMismatchNo, int bestMappedPairNo);
    inline void getPairedRInfo(const CGenome_Index_TableQ& table, CMappingResult &m1, CMappingResult &m2, bool samFormat);
    void printAMappedPair(const CGenome_Index_TableQ& table, CMappingResult &m1, CMappingResult &m2, int noPairedLoc);
    void printMappedPairStats(ostream& out, CReadInBitsSet& readSet, unsigned int uiSubThreshold);
protected:
    void initialization(void);
    inline void bookNoMappedKeepPairs(bool sepMore, bool sepLess, bool pairedOnExpStrand);
    inline void bookKeepMappedPairs(CBestPairedMapping& bestMP);
    unsigned int getPairedReadSetSize
    (CReadInBitsSet& setA1, CReadInBitsSet& setA2, CReadInBitsSet& setB1, CReadInBitsSet& setB2);
    int noOfPairsInRange;
    int noOfPairsSepMore;
    int noOfPairsSepLess;
    int noOfPairsSepMoreAndLess;
    int noOfSingle1stEndMapped;
    int noOfSingle2ndEndMapped;
    int noOfAmbiguousPairs;
    int noOfExpMappedPairedStrand;
};

inline void CPairedReadsMapping::bookNoMappedKeepPairs(bool sepMore, bool sepLess, bool pairedOnExpStrand)
{
    if (sepMore && sepLess) {
        noOfPairsSepMoreAndLess++;
    } else if (sepMore) {
        noOfPairsSepMore++;
    } else if (sepLess) {
        noOfPairsSepLess++;
    }
    if (pairedOnExpStrand) {
        this->noOfExpMappedPairedStrand++;
    }
}

inline void CPairedReadsMapping::bookKeepMappedPairs(CBestPairedMapping& bestMP)
{
    this->noOfPairsInRange++;
    this->iMapCount++;
    this->iMapDiffCount[bestMP.minDiff]++;
    bool stricklyExcludeAmbiguous = opt.bExcludeAmbiguousPaired && opt.bGetAllAlignments; // -A -e
    bool bAmbiguous = (stricklyExcludeAmbiguous && bestMP.validMappingNo > 1) || bestMP.bestMappingNo > 1;
    if (bAmbiguous) {
        this->iMultiMappedReads++;
    }
}
inline void getSingleMappingInfo(CMappingResult &m, CAlignmentsQ &q, int mappingIndex);

// Map mated paired reads parallelly
int parallelMappingPairedReads(vector<string>& readSetsList1, vector<string>& readSetsList2,
                               CGenome_Index_TableQ& indexTable, MappingOpts P);
// For the paired read set in a file with 5'-3' concatenated with 3'-5'.
int parallelMappingPairedReads(vector<string>& readSetsList,
                               CGenome_Index_TableQ& indexTable, MappingOpts P);
int parallelMappingPairedLongReads(vector<string>& readSetsList1, vector<string>& readSetsList2,\
                                   CGenome_Index_TableQ& indexTable, MappingOpts P);
