#include "TestGenome_Index_TableQ.h"

SimulateLongRead::SimulateLongRead(CGenomeInBits* pgenomeNTInBits, unsigned int startIndex)
{
    unsigned int halfLength = this->uiReadLength / 2;
    this->goodRead = pgenomeNTInBits->fragACGTKmerInBits(this->half1st, startIndex, halfLength);
    this->goodRead = this->goodRead & (pgenomeNTInBits->fragACGTKmerInBits(half2nd, startIndex + halfLength, halfLength));

    if (goodRead) {
        bool bOddReadLength = (this->uiReadLength % 2 == 1);
        decodeLongRead(this->half1st, this->half2nd, this->read, bOddReadLength);
    }
}


SimulateLongRead::~SimulateLongRead(void)
{
}

void introduceMutation(char* kmer, int mutationPattern)
{
    if (mutationPattern == 2 || mutationPattern == 3 || mutationPattern == 4) {
        mutateRead(kmer, mutationPattern);
    } else if (mutationPattern == (int)FULL_SENSITIVE_OPT_TO_ONE_BASE_ONE_COLOR_MIS) {
        mutatePairsOfConsecutiveBases(kmer, 1);
        mutateRead(kmer, 1);
    } else if (mutationPattern == (int)FULL_SENSITIVE_OPT_TO_TWO_BASE_MIS ) {
        mutatePairsOfConsecutiveBases(kmer, 2);
    } else if (mutationPattern == (int)FULL_SENSITIVE_OPT_TO_ONE_BASE_TWO_COLOR_MIS) {
        mutatePairsOfConsecutiveBases(kmer, 1);
        mutateRead(kmer, 2);
    }
}

/*
int getTestChrId(CGenome_Index_TableQ* table) {
}

const char* getTestChr(CGenome_Index_TableQ* table) {
}*/

/*
 * Test function which mutates every sliding windows on the reference genome and check if the all hits are found
 */
bool testGenome_Index_TableQ(CGenome_Index_TableQ* table)
{
    bool pass = true;
    CAlignmentsQ alignmentsQ('B');

    CchromosomeNTdata* testChr;
    unsigned int testChrId;
    if (table->pgenomeNT->iNo_of_chromosome > 1) {
        testChrId = 1; // If there are more than one chromosome, test the second one.
        testChr = table->pgenomeNT->paChromosomes[1];
    } else {
        testChrId = 0;
        testChr = table->pgenomeNT->paChromosomes[0];
    }
    unsigned int testGenomeIdStart = table->pgenomeNT->chrIndex2genomelocusID(testChrId, 0);
    unsigned int testGenomeIdEnd   = table->pgenomeNT->chrIndex2genomelocusID(testChrId, 0)
                                     + testChr->iChromosome_size - table->uiRead_Length;

    for (unsigned int i = testGenomeIdStart; i < testGenomeIdEnd; i++) {
        CReadInBits slideWindows;
        bool goodRead;
        goodRead = table->pgenomeNTInBits->fragACGTKmerInBits(slideWindows, i, table->uiRead_Length);
        if (table->bMapReadInColors) {
            slideWindows = bases2Colors(slideWindows);
        }

        if (goodRead) {
            char read[wordSize + 1];
            char originalRead[wordSize + 1];
            slideWindows.decode(read);

            CReadInBits readInBits(read);
            alignmentsQ.clearHits();
            // (1) Test exact match
            if (table->bMapReadInColors) {
                table->queryReadColors(readInBits, alignmentsQ, true, true);
            } else {
                table->queryReadBases(readInBits, alignmentsQ, true, true);
            }
            if (alignmentsQ.MinDiff != 0) {
                cout << "Miss exact match " << i << endl;
                pass = false;
                PRINT_MASKED_REPERAT_FLAG(table, i);
            }

            // (2) Test mutated reads
            myStrCpy(originalRead, read, MAX_READ_LENGTH);
            introduceMutation(read, table->chosenSeedId);
            CReadInBits mReadInBits(read);
            alignmentsQ.clearHits();

            if (table->bMapReadInColors) {
                table->queryReadColors(mReadInBits, alignmentsQ, true, true);
            } else {
                table->queryReadBases(mReadInBits, alignmentsQ, true, true);
            }
            if (alignmentsQ.MinDiff > table->uiSubDiffThreshold) {
                cout << "Miss mutated read" << i << endl;
                pass = false;
                // PRINT_MASKED_REPERAT_FLAG(table, i);
            } else if (alignmentsQ.MinDiff < table->uiSubDiffThreshold) {
                // cout << "Found better alignment!" << endl;
            }

            // (3) Check reversed complement reads
            if (table->bMapReadInColors) {
                table->pgenomeNTInBits->fragACGTKmerInBits(slideWindows, i, table->uiRead_Length);
                CReadInBits rcRead = reverseCompliment(table->uiRead_Length, slideWindows);
                CReadInBits rcReadInColors = bases2Colors(rcRead);

                rcReadInColors.decode(read);
                myStrCpy(originalRead, read, MAX_READ_LENGTH);
                introduceMutation(read, table->chosenSeedId);
                CReadInBits rcMreadInBits(read);
                alignmentsQ.clearHits();
                table->queryReadColors(rcMreadInBits, alignmentsQ, true, false);
            } else {
                reverseComplementKmer(read);
                CReadInBits rcMreadInBits(read);
                alignmentsQ.MinDiff = table->uiRead_Length; // SET A LARGE NUMBER
                table->queryReadBases(rcMreadInBits, alignmentsQ, true, false);
            }

            if (alignmentsQ.MinDiff > table->uiSubDiffThreshold) {
                cout << "Miss reversed mutated read" << i << endl;
                pass = false;
                // PRINT_MASKED_REPERAT_FLAG(table, i);
            } else if (alignmentsQ.MinDiff < table->uiSubDiffThreshold) {
                // cout << "Found better alignment!" << endl;
            }
        }
    }
    return(pass);
}

bool testMappingLongRead(CGenome_Index_TableQ* table)
{
    bool bOddReadLength = false; // Currently only test even long read
    bool pass = true;
    CAlignmentsQ alignmentsQ('B');

    CchromosomeNTdata* testChr;
    unsigned int testChrId;
    if (table->pgenomeNT->iNo_of_chromosome > 1) {
        testChrId = 1; // If there are more than one chromosome, test the second one.
        testChr = table->pgenomeNT->paChromosomes[1];
    } else {
        testChrId = 0;
        testChr = table->pgenomeNT->paChromosomes[0];
    }
    const unsigned halfLength = table->uiRead_Length;
    unsigned int testGenomeIdStart = table->pgenomeNT->chrIndex2genomelocusID(testChrId, 0);
    unsigned int testGenomeIdEnd   = table->pgenomeNT->chrIndex2genomelocusID(testChrId, 0)
                                     + testChr->iChromosome_size - halfLength;

    for (unsigned int i = testGenomeIdStart; i < testGenomeIdEnd; i++) {
        CReadInBits half1st, half2nd;
        bool goodRead;

        goodRead = table->pgenomeNTInBits->fragACGTKmerInBits(half1st, i, halfLength);
        goodRead = goodRead & (table->pgenomeNTInBits->fragACGTKmerInBits(half2nd, i + halfLength, halfLength));

        if (goodRead) {
            char read[MAX_LINE];
            char originalRead[MAX_LINE];
            decodeLongRead(half1st, half2nd, read, bOddReadLength);

            alignmentsQ.clearHits();
            // (1) Test exact match
            table->queryLongReadBases(half1st, half2nd, bOddReadLength, alignmentsQ, 1, true, true);

            if (alignmentsQ.MinDiff != 0) {
                cout << "Miss exact match " << i << endl;
                pass = false;
                PRINT_MASKED_REPERAT_FLAG(table, i);
            }

            // (2) Test mutated reads
            myStrCpy(originalRead, read, MAX_LINE);
            introduceMutation(read, table->chosenSeedId * 2);
            encodeLongRead(read, half1st, half2nd);
            alignmentsQ.clearHits();
            table->queryLongReadBases(half1st, half2nd, bOddReadLength, alignmentsQ, 1, true, true);

            if (alignmentsQ.MinDiff > table->uiSubDiffThreshold) {
                cout << "Miss mutated read" << i << endl;
                pass = false;
                // PRINT_MASKED_REPERAT_FLAG(table, i);
            } else if (alignmentsQ.MinDiff < table->uiSubDiffThreshold) {
                // cout << "Found better alignment!" << endl;
            }

            // (3) Check reversed complement reads
            reverseComplementKmer(read);
            CReadInBits rcR1, rcR2;
            encodeLongRead(read, rcR1, rcR2);
            alignmentsQ.MinDiff = table->uiRead_Length; // SET A LARGE NUMBER
            table->queryLongReadBases(rcR1, rcR2, bOddReadLength, alignmentsQ, 1, true, false);
            table->queryLongReadBases(rcR1, rcR2, bOddReadLength, alignmentsQ, 2, true, false);

            if (alignmentsQ.MinDiff > table->uiSubDiffThreshold) {
                cout << "Miss reversed mutated read" << i << endl;
                pass = false;
                // PRINT_MASKED_REPERAT_FLAG(table, i);
            } else if (alignmentsQ.MinDiff < table->uiSubDiffThreshold) {
                // cout << "Found better alignment!" << endl;
            }
        }
    }
    return(pass);
}

bool testMappingLongSOLiDRead(CGenome_Index_TableQ* table)
{
    bool bOddReadLength = false;
    bool pass = true;
    CAlignmentsQ alignmentsQ('B');

    CchromosomeNTdata* testChr;
    unsigned int testChrId;
    if (table->pgenomeNT->iNo_of_chromosome > 1) {
        testChrId = 1; // If there are more than one chromosome, test the second one.
        testChr = table->pgenomeNT->paChromosomes[1];
    } else {
        testChrId = 0;
        testChr = table->pgenomeNT->paChromosomes[0];
    }
    const unsigned halfLength = table->uiRead_Length;
    unsigned int testGenomeIdStart = table->pgenomeNT->chrIndex2genomelocusID(testChrId, 0);
    unsigned int testGenomeIdEnd   = table->pgenomeNT->chrIndex2genomelocusID(testChrId, 0)
                                     + testChr->iChromosome_size - halfLength;

    for (unsigned int i = testGenomeIdStart; i < testGenomeIdEnd; i++) {
        CReadInBits half1st, half2nd, half1stInColors, half2ndInColors;
        bool goodRead;

        goodRead = table->pgenomeNTInBits->fragACGTKmerInBits(half1st, i, halfLength);
        goodRead = goodRead & (table->pgenomeNTInBits->fragACGTKmerInBits(half2nd, i + halfLength, halfLength));

        if (goodRead) {
            char read[MAX_LINE];
            char originalRead[MAX_LINE];
            decodeLongRead(half1st, half2nd, read, bOddReadLength);
            // TODO: encode each half in colors signals
            alignmentsQ.clearHits();
            // (1) Test exact match
            table->queryLongReadColors(half1stInColors, half2ndInColors, bOddReadLength, alignmentsQ, 1, true, true);

            if (alignmentsQ.MinDiff != 0) {
                cout << "Miss exact match " << i << endl;
                pass = false;
                PRINT_MASKED_REPERAT_FLAG(table, i);
            }

            // (2) Test mutated reads
            myStrCpy(originalRead, read, MAX_LINE);
            introduceMutation(read, table->chosenSeedId * 2);
            encodeLongRead(read, half1st, half2nd);
            // TODO: encode each half in colors signals
            alignmentsQ.clearHits();
            table->queryLongReadColors(half1stInColors, half2ndInColors, bOddReadLength, alignmentsQ, 1, true, true);

            if (alignmentsQ.MinDiff > table->uiSubDiffThreshold) {
                cout << "Miss mutated read" << i << endl;
                pass = false;
                // PRINT_MASKED_REPERAT_FLAG(table, i);
            } else if (alignmentsQ.MinDiff < table->uiSubDiffThreshold) {
                // cout << "Found better alignment!" << endl;
            }

            // (3) Check reversed complement reads
            reverseComplementKmer(read);
            CReadInBits rcR1, rcR2;
            encodeLongRead(read, rcR1, rcR2);
            // TODO: encode each half in colors signals
            alignmentsQ.MinDiff = table->uiRead_Length; // SET A LARGE NUMBER
            table->queryLongReadBases(rcR1, rcR2, bOddReadLength, alignmentsQ, 1, true, false);
            table->queryLongReadBases(rcR1, rcR2, bOddReadLength, alignmentsQ, 2, true, false);

            if (alignmentsQ.MinDiff > table->uiSubDiffThreshold) {
                cout << "Miss reversed mutated read" << i << endl;
                pass = false;
                // PRINT_MASKED_REPERAT_FLAG(table, i);
            } else if (alignmentsQ.MinDiff < table->uiSubDiffThreshold) {
                // cout << "Found better alignment!" << endl;
            }
        }
    }
    return(pass);
}

bool testMappingLongPairedRead(CGenome_Index_TableQ* table)
{

    bool bOddReadLength = false;
    bool pass = true;

    /*
    CAlignmentsQ alignmentsQ('B');

    CchromosomeNTdata* testChr;
    unsigned int testChrId;
    if (table->pgenomeNT->iNo_of_chromosome > 1) {
        testChrId = 1; // If there are more than one chromosome, test the second one.
        testChr = table->pgenomeNT->paChromosomes[1];
    } else {
        testChrId = 0;
        testChr = table->pgenomeNT->paChromosomes[0];
    }
    int separation = 300;
    const unsigned halfLength = table->uiRead_Length;
    SimulateLongRead::uiReadLength = table->uiRead_Length * 2;
    unsigned int testGenomeIdStart = table->pgenomeNT->chrIndex2genomelocusID(testChrId, 0);
    unsigned int testGenomeIdEnd   = table->pgenomeNT->chrIndex2genomelocusID(testChrId, 0)
                                     + testChr->iChromosome_size - halfLength = separation;

    for (unsigned int i = testGenomeIdStart; i < testGenomeIdEnd; i++) {
        CReadInBits half1st, half2nd, half1stInColors, half2ndInColors;
        SimulateLongRead r1(table->pgenomeNTInBits, i);
    	SimulateLongRead r2(table->pgenomeNTInBits, i + separation);
    	if (r1.goodRead && r2.goodRead) {
            char originalRead[MAX_LINE];
            alignmentsQ.clearHits();
            // (1) Test exact match
    		table->queryLongReadColors(r1.half1st, r1.half2nd, bOddReadLength, alignmentsQ, 1, true, true);

            if (alignmentsQ.MinDiff != 0) {
                cout << "Miss exact match " << i << endl;
                pass = false;
                PRINT_MASKED_REPERAT_FLAG(table, i);
            }

            // (2) Test mutated reads
            myStrCpy(originalRead, r.read, MAX_LINE);
            introduceMutation(read, table->chosenSeedId * 2);
            encodeLongRead(read, half1st, half2nd);
            // TODO: encode each half in colors signals
            alignmentsQ.clearHits();
            table->queryLongReadColors(half1stInColors, half2ndInColors, bOddReadLength, alignmentsQ, 1, true, true);

            if (alignmentsQ.MinDiff > table->uiSubDiffThreshold) {
                cout << "Miss mutated read" << i << endl;
                pass = false;
                // PRINT_MASKED_REPERAT_FLAG(table, i);
            } else if (alignmentsQ.MinDiff < table->uiSubDiffThreshold) {
                // cout << "Found better alignment!" << endl;
            }

            // (3) Check reversed complement reads
            reverseComplementKmer(read);
            CReadInBits rcR1, rcR2;
            encodeLongRead(read, rcR1, rcR2);
            // TODO: encode each half in colors signals
            alignmentsQ.MinDiff = table->uiRead_Length; // SET A LARGE NUMBER
            table->queryLongReadBases(rcR1, rcR2, bOddReadLength, alignmentsQ, 1, true, false);
            table->queryLongReadBases(rcR1, rcR2, bOddReadLength, alignmentsQ, 2, true, false);

            if (alignmentsQ.MinDiff > table->uiSubDiffThreshold) {
                cout << "Miss reversed mutated read" << i << endl;
                pass = false;
                // PRINT_MASKED_REPERAT_FLAG(table, i);
            } else if (alignmentsQ.MinDiff < table->uiSubDiffThreshold) {
                // cout << "Found better alignment!" << endl;
            }
        }
    }
    */
    return(pass);
}