#include "stdafx.h"
#include "SeedPattern.h"

// This function return the hash value of first 13 bits
inline unsigned int getF0SeedHashValue(WORD_SIZE encodedRead)
{
    const WORD_SIZE HASH_MASK = 0x1fff;
    return ((unsigned int)(encodedRead & HASH_MASK)); // Get the first 13 digit
}

unsigned int getF0SeedHashValue(CReadInBits r)
{
    WORD_SIZE hashValue = getF0SeedHashValue(r.UpperBits);
    hashValue <<= BITS_FOR_HASHING;
    hashValue += getF0SeedHashValue(r.LowerBits);
    return ((unsigned int)hashValue);
}

ptHashFunc selectF0(int readlength)
{
    if (BITS_FOR_HASHING <= (unsigned int) readlength ) {
        if (readlength <= 32) {
            return &getF0SeedHashValue;
        } else if (readlength <= 48) {
            LOG_INFO("\nInfo %d: Use S1 seed instead %d\n", WARNING_LOG, readlength);
            return &getF1SeedHashValue;
        } else if (readlength <= 64) {
            LOG_INFO("\nInfo %d: Use S2 seed instead %d\n", WARNING_LOG, readlength);
            return &getF2SeedHashValue;
        }
    } else {
        // TODO deal with reads shorter than 13.
        ;
    }
    LOG_INFO("\nInfo %d: No hash function defined for read with length %d\n", WARNING_LOG, readlength);
    return (NULL);
}

// private function called by its overloaded getF1SeedHashKey(WORD_SIZE encoedRead, WORD_SIZE encoedRead);
inline unsigned int getF0SeedKey(WORD_SIZE encoedRead, int keyWeight)
{
    // Use the suffixLength bits based on the seed pattern 11*1**(111*1**)(111*1**)1 to create a value
    if (keyWeight > 0 ) {
        WORD_SIZE HASH_MASK = ((0x01 << keyWeight) - 1);
        WORD_SIZE uiKey =  encoedRead & HASH_MASK;
        return ((unsigned int)uiKey);
    } else {
        return(0);
    }
}

unsigned int getF0SeedKey(CReadInBits r, int keyWeight)
{
    r.UpperBits >>= BITS_FOR_HASHING;
    r.LowerBits >>= BITS_FOR_HASHING;
    unsigned int uiKey1 = getF0SeedKey(r.UpperBits, keyWeight);
    unsigned int uiKey2 = getF0SeedKey(r.LowerBits, keyWeight);
#ifdef EXTEND_SEED
    unsigned int uiKey = InterleaveBits((unsigned short) uiKey2, (unsigned short)  uiKey1);
#else
    unsigned int uiKey = (uiKey1 << keyWeight) + uiKey2;
#endif
    return (uiKey);
}

////////////////////////////////////////////////////////////////////////////////
inline unsigned int getF1SeedHashValue15(WORD_SIZE encodedRead)
{
    WORD_SIZE hashValue = 0;

    hashValue += (encodedRead & 0x07); // Get the first 3 digit
    hashValue <<= 3;
    encodedRead >>= 4;

    hashValue += (encodedRead & 0x07); // Get the first 4-6 digit
    hashValue <<= 3;
    encodedRead >>= 4;

    hashValue += (encodedRead & 0x07); // Get the first 7-9 digit
    hashValue <<= 3;
    encodedRead >>= 4;
    return (unsigned int) hashValue;
}

// This function is based on the seed pattern (111*).
inline unsigned int getF1SeedHashValue(WORD_SIZE encodedRead)
{
    // To save the number of CPU instructions, the value encoded bits that doesn't follow the order of reads
    // It still gets the first  digit and the fifth digit.. and so on to get total 13 digits
    WORD_SIZE hashValue = 0;

    hashValue += (encodedRead & 0x07); // Get the first 3 digit
    hashValue <<= 3;
    encodedRead >>= 4;

    hashValue += (encodedRead & 0x07); // Get the first 4-6 digit
    hashValue <<= 3;
    encodedRead >>= 4;

    hashValue += (encodedRead & 0x07); // Get the first 7-9 digit
    hashValue <<= 3;
    encodedRead >>= 4;

    hashValue += (encodedRead & 0x07); // Get the first 11-12 digit
    hashValue <<= 1;
    encodedRead >>= 4;

    hashValue += (encodedRead & 0x01); // Get the 13th position
    return (unsigned int) hashValue;
}

unsigned int getF1SeedHashValue15(CReadInBits r)
{
    WORD_SIZE hashValue = getF1SeedHashValue15(r.UpperBits);
    hashValue <<= BITS_FOR_HASHING;
    hashValue += getF1SeedHashValue15(r.LowerBits);
    return ((unsigned int)hashValue);
}

unsigned int getF1SeedHashValue(CReadInBits r)
{
    WORD_SIZE hashValue = getF1SeedHashValue(r.UpperBits);
    hashValue <<= BITS_FOR_HASHING;
    hashValue += getF1SeedHashValue(r.LowerBits);
    return ((unsigned int)hashValue);
}

ptHashFunc selectF1(int readlength)
{
    if (15 <= readlength && readlength < 20) {
        return &getF1SeedHashValue15;
    } else if (20 <= readlength && readlength <= 60) {
        return &getF1SeedHashValue;
    } else {
        LOG_INFO("\nInfo %d: No hash function defined for read with length %d\n", WARNING_LOG, readlength);
        return (NULL);
    }
}

// private function callse by its overloaded getF1SeedHashKey(WORD_SIZE encoedRead, WORD_SIZE encoedRead);
inline unsigned int getF1SeedKey(WORD_SIZE encoedRead, int keyWeight)
{
    //index 234567 8901234  5678901 2
    // Use the suffixLength bits based on the seed pattern 11*1**(111*1**)(111*1**)1 to create a value
    if (keyWeight > 0 ) {
        WORD_SIZE uiKey =  encoedRead & 0x03; // Get the 14 and 15 digit
        encoedRead >>= 3;
        for (keyWeight -= 2; keyWeight > 0; keyWeight -= 3) {
            uiKey += encoedRead & 0x07;
            uiKey <<= 3;
            encoedRead >>= 4;
        }
        uiKey >>= (-1 * keyWeight);
        return ((unsigned int)uiKey);
    } else {
        return(0);
    }
}

unsigned int getF1SeedKey(CReadInBits r, int keyWeight)
{
    r.UpperBits >>= 20; // The first 20 base are used as hash key (111*)(111*)(111*)(111*)1
    r.LowerBits >>= 20;
    unsigned int uiKey1 = getF1SeedKey(r.UpperBits, keyWeight);
    unsigned int uiKey2 = getF1SeedKey(r.LowerBits, keyWeight);
#ifdef EXTEND_SEED
    unsigned int uiKey = InterleaveBits((unsigned short) uiKey2, (unsigned short)  uiKey1);
#else
    unsigned int uiKey = (uiKey1 << keyWeight) + uiKey2;
#endif
    return (uiKey);
}

////////////////////////////////////////////////////////////////////////////////
// This function is based on the seed pattern (111*1**)(111*1**)(111*1**)1.
inline unsigned int getF2SeedHashValue(WORD_SIZE encodedRead)
{
    // To save the number of CPU instructions, the value encoded bits that doesn't follow the order of reads
    // It still gets the first 3 digit and the fifth digit.. and so on to get total 13 digits
    WORD_SIZE hashValue = (encodedRead & 0x07) << 1; // Get the first 3 digit
    encodedRead >>= 4;

    hashValue += (encodedRead & 0x01); // Get the first 4th digit in the 5th position
    hashValue <<= 3;
    encodedRead >>= 3;

    hashValue += (encodedRead & 0x07); // Get the 5-7th digit
    hashValue <<= 1;
    encodedRead >>= 4;

    hashValue += (encodedRead & 0x01); // Get 8th digit
    hashValue <<= 3;
    encodedRead >>= 3;

    hashValue += (encodedRead & 0x07); // Get 9-11th digit
    hashValue <<= 1;
    encodedRead >>= 4;

    hashValue += (encodedRead & 0x01); // Get 12th digit
    hashValue <<= 1;
    encodedRead >>= 3;

    hashValue += (encodedRead & 0x01); // Get the 13th position
    return (unsigned int) hashValue;
}

unsigned int getF2SeedHashValue(CReadInBits r)
{
    WORD_SIZE hashValue = getF2SeedHashValue(r.UpperBits);
    hashValue <<= BITS_FOR_HASHING;
    hashValue += getF2SeedHashValue(r.LowerBits);
    return ((unsigned int)hashValue);
}

unsigned int getF2SeedHashValue4ReadLength25_27(CReadInBits r)
{
    const int weight = 12;
    const int eliminatedCarePossitionsNo = 1;
    unsigned int hashValue = getF2SeedHashValue(r.UpperBits);
    hashValue >>= eliminatedCarePossitionsNo;
    hashValue <<= weight;
    hashValue += (getF2SeedHashValue(r.LowerBits) >> eliminatedCarePossitionsNo);
    return hashValue;
}
unsigned int getF2SeedHashValue4ReadLength23_24(CReadInBits r)
{
    const int weight = 11;
    const int eliminatedCarePossitionsNo = 2;
    unsigned int hashValue = getF2SeedHashValue(r.UpperBits);
    hashValue >>= eliminatedCarePossitionsNo;
    hashValue <<= weight;
    hashValue += (getF2SeedHashValue(r.LowerBits) >> eliminatedCarePossitionsNo);
    return hashValue;
}
unsigned int getF2SeedHashValue4ReadLength22(CReadInBits r)
{
    const int weight = 10;
    const int eliminatedCarePossitionsNo = 3;
    unsigned int hashValue = getF2SeedHashValue(r.UpperBits);
    hashValue >>= eliminatedCarePossitionsNo;
    hashValue <<= weight;
    hashValue += (getF2SeedHashValue(r.LowerBits) >> eliminatedCarePossitionsNo);
    return hashValue;
}
unsigned int getF2SeedHashValue4ReadLength21(CReadInBits r)
{
    const int weight = 9;
    const int eliminatedCarePossitionsNo = 4;
    unsigned int hashValue = getF2SeedHashValue(r.UpperBits);
    hashValue >>= eliminatedCarePossitionsNo;
    hashValue <<= weight;
    hashValue += (getF2SeedHashValue(r.LowerBits) >> eliminatedCarePossitionsNo);
    return hashValue;
}
unsigned int getF2SeedHashValue4ReadLength20(CReadInBits r)
{
    const int weight = 8;
    const int eliminatedCarePossitionsNo = 5;
    unsigned int hashValue = getF2SeedHashValue(r.UpperBits);
    hashValue >>= eliminatedCarePossitionsNo;
    hashValue <<= weight;
    hashValue += (getF2SeedHashValue(r.LowerBits) >> eliminatedCarePossitionsNo);
    return hashValue;
}

ptHashFunc selectF2(int readlength)
{
    if (readlength > 27) {
        return &getF2SeedHashValue;
    } else if (25 <= readlength && readlength <= 27) {
        return &getF2SeedHashValue4ReadLength25_27;
    } else if (23 <= readlength && readlength <= 24) {
        return &getF2SeedHashValue4ReadLength23_24;
    } else if (readlength == 22) {
        return &getF2SeedHashValue4ReadLength22;
    } else if (readlength == 21) {
        return &getF2SeedHashValue4ReadLength21;
    } else if (readlength == 20) {
        return &getF2SeedHashValue4ReadLength20;
    } else {
        LOG_INFO("\nInfo %d: No hash function defined for read with length %d\n", WARNING_LOG, readlength);
        return (NULL);
    }
}

// private function callse by its overloaded getF2SeedHashKey(WORD_SIZE encoedRead, WORD_SIZE encoedRead);
inline unsigned int getF2SeedKey(WORD_SIZE encoedRead, int keyWeight)
{
    //index 234567 8901234  5678901 2
    // Use the suffixLength bits based on the seed pattern 11*1**(111*1**)(111*1**)1 to create a value
    WORD_SIZE uiKey =  encoedRead & 0x03; // Get the 14 and 15 digit
    encoedRead >>= 3;
    uiKey <<= 1; // Get the 16 digit
    uiKey += (encoedRead & 0x01);
    for (keyWeight -= 3; keyWeight > 0; keyWeight -= 4) {
        encoedRead >>= 3;

        uiKey <<= 1; // Get 17th + 4i digit
        uiKey += (encoedRead & 0x01);
        encoedRead >>= 1;

        uiKey <<= 1; // Get 18th + 4i digit
        uiKey += (encoedRead & 0x01);
        encoedRead >>= 1;

        uiKey <<= 1; // Get 19th + 4i digit
        uiKey += (encoedRead & 0x01);
        encoedRead >>= 2; // don't care

        uiKey <<= 1; // Get 20th + 4i digit
        uiKey += (encoedRead & 0x01);
    }
    uiKey >>= (-1 * keyWeight);
    return ((unsigned int)uiKey);
}

unsigned int getF2SeedKey(CReadInBits r, int keyWeight)
{
    r.UpperBits >>= 22; // The first 22 base are used as hash key (111*1**)(111*1**)(111*1**)1
    r.LowerBits >>= 22;
    unsigned int uiKey1 = getF2SeedKey(r.UpperBits, keyWeight);
    unsigned int uiKey2 = getF2SeedKey(r.LowerBits, keyWeight);
#ifdef EXTEND_SEED
    unsigned int uiKey = InterleaveBits((unsigned short) uiKey2, (unsigned short)  uiKey1);
#else
    unsigned int uiKey = (uiKey1 << keyWeight) + uiKey2;
#endif
    return (uiKey);
}

////////////////////////////////////////////////////////////////////////////////
inline unsigned int getS1_1SeedHashValue(WORD_SIZE Bits)
{
    // For read length >= 32 (SOLiD Read length 33), it has corresponding seed with weight >= 13
    // 32 - (10-1) = 23
    // (1111**1***) (1111**1***) 111
    WORD_SIZE hashValue = 0;

    hashValue += (Bits & 0x0f); // Get the first 4 digit
    Bits >>= 6;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 5 th digit
    Bits >>= 4;
    hashValue <<= 4;

    hashValue += (Bits & 0x0f); // Get the first 6-9 digit
    Bits >>= 6;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 10 digit
    Bits >>= 4;

    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 11 digit
    Bits >>= 1;

    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 12 digit
    Bits >>= 1;

    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 13 digit
    return ((unsigned int)hashValue);
}

unsigned int getS1_1SeedHashValue(CReadInBits r)
{
    unsigned int hashValue = getS1_1SeedHashValue(r.UpperBits);
    hashValue <<= BITS_FOR_HASHING; // BITS_FOR_HASHING is a fixed bits for 13
    hashValue += getS1_1SeedHashValue(r.LowerBits);
    return hashValue;
}

// Get first 12 care bits and concatenate the key together.
unsigned int getS1_1SeedHashValue4ReadLength31(CReadInBits r)
{
    const int weight = 12;
    const int eliminatedCarePossitionsNo = 1;
    unsigned int hashValue = getS1_1SeedHashValue(r.UpperBits);
    hashValue >>= eliminatedCarePossitionsNo;
    hashValue <<= weight;
    hashValue += (getS1_1SeedHashValue(r.LowerBits) >> eliminatedCarePossitionsNo);
    return hashValue;
}

// Get first 11 care bits and concatenate the key together.
unsigned int getS1_1SeedHashValue4ReadLength30(CReadInBits r)
{
    const int weight = 11;
    const int eliminatedCarePossitionsNo = 2;
    unsigned int hashValue = getS1_1SeedHashValue(r.UpperBits);
    hashValue >>= eliminatedCarePossitionsNo;
    hashValue <<= weight;
    hashValue += (getS1_1SeedHashValue(r.LowerBits) >> eliminatedCarePossitionsNo);
    return hashValue;
}

// Get first 10 care bits and concatenate the key together.
unsigned int getS1_1SeedHashValue4ReadLength26_29(CReadInBits r)
{
    const int weight = 10;
    const int eliminatedCarePossitionsNo = 3;
    unsigned int hashValue = getS1_1SeedHashValue(r.UpperBits);
    hashValue >>= eliminatedCarePossitionsNo;
    hashValue <<= weight;
    hashValue += (getS1_1SeedHashValue(r.LowerBits) >> eliminatedCarePossitionsNo);
    return hashValue;
}

// Get first 9 care bits and concatenate the key together.
unsigned int getS1_1SeedHashValue4ReadLength23_25(CReadInBits r)
{
    const int weight = 9;
    const int eliminatedCarePossitionsNo = 4;
    unsigned int hashValue = getS1_1SeedHashValue(r.UpperBits);
    hashValue >>= eliminatedCarePossitionsNo;
    hashValue <<= weight;
    hashValue += (getS1_1SeedHashValue(r.LowerBits) >> eliminatedCarePossitionsNo);
    return hashValue;
}

ptHashFunc selectS1_1(int readlength)
{
    if (readlength > 31) {
        return &getS1_1SeedHashValue;
    } else if (readlength == 31) {
        return &getS1_1SeedHashValue4ReadLength31;
    } else if (readlength == 30) {
        return &getS1_1SeedHashValue4ReadLength30;
    } else if (26 <= readlength && readlength <= 29) {
        return &getS1_1SeedHashValue4ReadLength26_29;
    } else if (23 <= readlength && readlength <= 25) {
        return &getS1_1SeedHashValue4ReadLength23_25;
    } else {
        LOG_INFO("\nInfo %d: No hash function defined for read with length %d\n", WARNING_LOG, readlength);
        return (NULL);
    }
}

inline unsigned int getS1_1SeedKey(WORD_SIZE Bits, int keyWeight)
{
    // 1**1*** 1111**1*** 111
    WORD_SIZE uiKey = 0;
    // For read lenght = 33 to 35, keyWeight == 1
    uiKey += (Bits & 0x01); // Get the first 14 digit
    if (keyWeight > 1) {
        Bits >>= 3;
        uiKey <<= 1;
        uiKey += (Bits & 0x01); // Get the first 15 th digit, for read length 36 to 39

        for (keyWeight -= 2; keyWeight > 0; keyWeight -= 5) { // For read lenght == 40
            Bits >>= 4;
            uiKey <<= 1;
            uiKey += (Bits & 0x01); // Get 16 th + 5i;

            Bits >>= 1;
            uiKey <<= 1;
            uiKey += (Bits & 0x01); // Get 17 th + 5i;

            Bits >>= 1;
            uiKey <<= 1;
            uiKey += (Bits & 0x01); // Get 18 th + 5i;

            Bits >>= 1;
            uiKey <<= 1;
            uiKey += (Bits & 0x01); // Get 19 th + 5i;

            Bits >>= 3;
            uiKey <<= 1;
            uiKey += (Bits & 0x01); // Get 20 th + 5i;
        }
        uiKey >>= (-1 * keyWeight);
    }
    return ((unsigned int)uiKey);
}

unsigned int getS1_1SeedKey(CReadInBits r, int keyWeight)
{
    // The seed pattern is (1111**1***)(1111**1***)111
    // The first 13 care position, that is the first 23 positions are used for hash value.
    // keyWeight number of base used to generate key for binary search
    if (keyWeight > 0) {
        r.UpperBits >>= 23;
        r.LowerBits >>= 23;
        unsigned int uiKey1 = getS1_1SeedKey(r.UpperBits, keyWeight);
        unsigned int uiKey2 = getS1_1SeedKey(r.LowerBits, keyWeight);
#ifdef EXTEND_SEED
        unsigned int uiKey = InterleaveBits((unsigned short) uiKey2, (unsigned short)  uiKey1);
#else
        unsigned int uiKey = (uiKey1 << keyWeight) + uiKey2;
#endif
        return uiKey;
    } else
        return (0);
}

////////////////////////////////////////////////////////////////////////////////
inline unsigned int getS2_0SeedHashValue(WORD_SIZE Bits)
{
    // For read length >= 35 or more, weight is 13. (Note SOliD read 35 actually has only color 34)
    // (1111**1****)(1111**1****)111
    WORD_SIZE hashValue = 0;

    hashValue += (Bits & 0x0f); // Get the first 4 digit
    Bits >>= 6;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 5 digit
    Bits >>= 5;
    hashValue <<= 4;

    hashValue += (Bits & 0x0f); // Get the first 6-9 digit
    Bits >>= 6;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 10 digit
    Bits >>= 5;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 11 digit
    Bits >>= 1;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 12 digit
    Bits >>= 1;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 13 digit

    return ((unsigned int)hashValue);
}

unsigned int getS2_0SeedHashValue(CReadInBits r)
{
    WORD_SIZE hashValue = getS2_0SeedHashValue(r.UpperBits);
    hashValue <<= BITS_FOR_HASHING; // BITS_FOR_HASHING is a fixed bits for 13
    hashValue += getS2_0SeedHashValue(r.LowerBits);
    return ((unsigned int)hashValue);

}

inline unsigned int getS2_0SeedHashValue4ReadLength34(WORD_SIZE Bits)
{
    // For read 34, the seed length is 24.
    // (1111**1****)(1111**1****)11
    WORD_SIZE hashValue = 0;

    hashValue += (Bits & 0x0f); // Get the first 4 digit
    Bits >>= 6;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 5 digit
    Bits >>= 5;
    hashValue <<= 4;

    hashValue += (Bits & 0x0f); // Get the first 6-9 digit
    Bits >>= 6;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 10 digit
    Bits >>= 5;
    hashValue <<= 2;
    hashValue += (Bits & 0x03); // Get the first 11 - 12th digit

    return ((unsigned int)hashValue);
}

// For Solid Read, the read length typical read length is 34.
// The seed weight for it is 12
unsigned int getS2_0SeedHashValue4ReadLength34(CReadInBits r)
{
    const int weight = 12;
    WORD_SIZE hashValue = getS2_0SeedHashValue4ReadLength34(r.UpperBits);
    hashValue <<= weight;
    hashValue += getS2_0SeedHashValue4ReadLength34(r.LowerBits);
    return ((unsigned int)hashValue);
}

inline unsigned int getS2_0SeedHashValue4ReadLength33(WORD_SIZE Bits)
{
    // For read 33, the seed length is 23.
    // (1111**1****)(1111**1****)1
    WORD_SIZE hashValue = 0;

    hashValue += (Bits & 0x0f); // Get the first 4 digit
    Bits >>= 6;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 5 digit
    Bits >>= 5;
    hashValue <<= 4;

    hashValue += (Bits & 0x0f); // Get the first 6-9 digit
    Bits >>= 6;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 10 digit
    Bits >>= 5;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 11th digit

    return ((unsigned int)hashValue);
}

// For read length is 33, the seed weight for it is 11
unsigned int getS2_0SeedHashValue4ReadLength33(CReadInBits r)
{
    const int weight = 11;
    WORD_SIZE hashValue = getS2_0SeedHashValue4ReadLength33(r.UpperBits);
    hashValue <<= weight;
    hashValue += getS2_0SeedHashValue4ReadLength33(r.LowerBits);
    return ((unsigned int)hashValue);
}

inline unsigned int getS2_0SeedHashValue4ReadLength28_32(WORD_SIZE Bits)
{
    // For read 32, the seed length is 22. The weight is 10
    // (1111**1****)(1111**1****)
    // For read 28, the seed length is 18. The weight is 10
    // (1111**1****)(1111**1)
    WORD_SIZE hashValue = 0;

    hashValue += (Bits & 0x0f); // Get the first 4 digit
    Bits >>= 6;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 5 digit
    Bits >>= 5;
    hashValue <<= 4;

    hashValue += (Bits & 0x0f); // Get the first 6-9 digit
    Bits >>= 6;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 10 digit
    return ((unsigned int)hashValue);
}
// Hash Value for read length 28 to 32. Get the first 10 care bits and concatenate them together
unsigned int getS2_0SeedHashValue4ReadLength28_32(CReadInBits r)
{
    const int weight = 10;
    WORD_SIZE hashValue = getS2_0SeedHashValue4ReadLength28_32(r.UpperBits);
    hashValue <<= weight;
    hashValue += getS2_0SeedHashValue4ReadLength28_32(r.LowerBits);
    return ((unsigned int)hashValue);
}


inline unsigned int getS2_0SeedHashValue4ReadLength25_27(WORD_SIZE Bits)
{
    // For read 25, the seed length is 15. The weight is 9
    // (1111**1****)(1111)
    WORD_SIZE hashValue = 0;

    hashValue += (Bits & 0x0f); // Get the first 4 digit
    Bits >>= 6;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 5 digit
    Bits >>= 5;
    hashValue <<= 4;

    hashValue += (Bits & 0x0f); // Get the first 6-9 digit
    return ((unsigned int)hashValue);
}

// Hash Value for read length 25. Get the first 9 care bits and concatenate them together
unsigned int getS2_0SeedHashValue4ReadLength25_27(CReadInBits r)
{
    const int weight = 9;
    WORD_SIZE hashValue = getS2_0SeedHashValue4ReadLength25_27(r.UpperBits);
    hashValue <<= weight;
    hashValue += getS2_0SeedHashValue4ReadLength25_27(r.LowerBits);
    return ((unsigned int)hashValue);
}

ptHashFunc selectS2_0(int readlength)
{
    if (readlength > 34) {
        return &getS2_0SeedHashValue;
    } else if (readlength == 34) {
        return &getS2_0SeedHashValue4ReadLength34;
    } else if (readlength == 33) {
        return &getS2_0SeedHashValue4ReadLength33;
    } else if (28 <= readlength && readlength <= 32) {
        return &getS2_0SeedHashValue4ReadLength28_32;
    } else if (25 <= readlength && readlength <= 27) {
        return &getS2_0SeedHashValue4ReadLength25_27;
    } else {
        LOG_INFO("\nInfo %d: No hash function defined for read with length %d\n", WARNING_LOG, readlength);
        return (NULL);
    }
}

inline unsigned int getS2_0SeedKey(WORD_SIZE Bits, int keyWeight)
{
    // 1(**1****)1111**1****)
    WORD_SIZE uiKey = (Bits & 0x01);; // 14th bit
    for (keyWeight -= 1; keyWeight > 0; keyWeight -= 5) {
        Bits >>= 3;
        uiKey <<= 1;
        uiKey += (Bits & 0x01); // 15th bit
        Bits >>= 5;

        uiKey <<= 1;
        uiKey += (Bits & 0x01); // 16th bit
        Bits >>= 1;

        uiKey <<= 1;
        uiKey += (Bits & 0x01); // 17th bit
        Bits >>= 1;

        uiKey <<= 1;
        uiKey += (Bits & 0x01); // 18th bit
        Bits >>= 1;

        uiKey <<= 1;
        uiKey += (Bits & 0x01); // 19th bit
    }
    uiKey >>= (-1 * keyWeight);
    return ((unsigned int)uiKey);
}

unsigned int getS2_0SeedKey(CReadInBits r, int keyWeight)
{
    // The seed pattern is (1111**1****)(11111**1****)
    // The first 13 care position, that is the first 25 position are used for hash value
    if (keyWeight > 0) {
        r.UpperBits >>= 25;
        r.LowerBits >>= 25;
        unsigned int uiKey1 = getS2_0SeedKey(r.UpperBits, keyWeight);
        unsigned int uiKey2 = getS2_0SeedKey(r.LowerBits, keyWeight);
#ifdef EXTEND_SEED
        unsigned int uiKey = InterleaveBits((unsigned short) uiKey2, (unsigned short)  uiKey1);
#else
        unsigned int uiKey = (uiKey1 << keyWeight) + uiKey2;
#endif
        return uiKey;
    } else
        return (0);
}


inline unsigned int getS2_0SeedKey4ReadLength34(WORD_SIZE Bits, int keyWeight)
{
    keyWeight = 0;
    // 11(**1****)1
    WORD_SIZE uiKey = (Bits & 0x03);; // 13 14th bit

    Bits >>= 4;
    uiKey <<= 1;
    uiKey += (Bits & 0x01); // 15th bit
    Bits >>= 5;

    uiKey <<= 1;
    uiKey += (Bits & 0x01); // 16th bit

    return ((unsigned int)uiKey);
}

// EXTEND_SEED
unsigned int getS2_0SeedKey4ReadLength34(CReadInBits r, int keyWeight)
{
    // The seed pattern is (1111**1****)(1111**1****)11
    // The first 13 care position, that is the first 25 position are used for hash value
    if (keyWeight > 0) {
        r.UpperBits >>= 24;
        r.LowerBits >>= 24;
        unsigned int uiKey1 = getS2_0SeedKey4ReadLength34(r.UpperBits, keyWeight);
        unsigned int uiKey2 = getS2_0SeedKey4ReadLength34(r.LowerBits, keyWeight);
        unsigned int uiKey = InterleaveBits((unsigned short) uiKey2, (unsigned short)  uiKey1);
        return uiKey;
    } else
        return (0);
}



////////////////////////////////////////////////////////////////////////////////
inline unsigned int getF3SeedHashValue(WORD_SIZE Bits)
{

    // To save the number of CPU instructions, the value enocoded bits that doesn't follow the order of reads
    // It still gets the first 3 digit and the fivth digit.. and so on to get total 13 digits
    WORD_SIZE hashValue = 0;

    hashValue += (Bits & 0x07); // Get the first 3 digit
    Bits >>= 4;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 4th digit
    Bits >>= 3;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 5th digit
    Bits >>= 4;
    hashValue <<= 3;

    hashValue += (Bits & 0x07); // Get the first 6-8 digit
    Bits >>= 4;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 9th digit
    Bits >>= 3;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 10th digit
    Bits >>= 4;
    hashValue <<= 3;
    hashValue += (Bits & 0x07); // Get the first 11-13th digit
    return ((unsigned int)hashValue);
}

unsigned int getF3SeedHashValue(CReadInBits r)
{
    WORD_SIZE hashValue = getF3SeedHashValue(r.UpperBits);
    hashValue <<= BITS_FOR_HASHING;
    hashValue += getF3SeedHashValue(r.LowerBits);
    return ((unsigned int)hashValue);
}

inline unsigned int getF3SeedHashValue4ReadLength34(WORD_SIZE Bits)
{

    // To save the number of CPU instructions, the value enocoded bits that doesn't follow the order of reads
    // It still gets the first 3 digit and the fivth digit.. and so on to get total 13 digits
    WORD_SIZE hashValue = 0;

    hashValue += (Bits & 0x07); // Get the first 3 digit
    Bits >>= 4;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 4th digit
    Bits >>= 3;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 5th digit
    Bits >>= 4;
    hashValue <<= 3;

    hashValue += (Bits & 0x07); // Get the first 6-8 digit
    Bits >>= 4;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 9th digit
    Bits >>= 3;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 10th digit
    Bits >>= 4;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 11th digit
    Bits >>= 1;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 12th digit
    return ((unsigned int)hashValue);
}

unsigned int getF3SeedHashValue4ReadLength34(CReadInBits r)
{
    // The seed length is (34 - 10) = 24.
    // // (11101001000 11101001000 11. Has weight only 12
    const int weight = 12;
    WORD_SIZE hashValue = getF3SeedHashValue4ReadLength34(r.UpperBits);
    hashValue <<= weight;
    hashValue += getF3SeedHashValue4ReadLength34(r.LowerBits);
    return ((unsigned int)hashValue);
}

unsigned int getF3SeedHashValue4ReadLength33(CReadInBits r)
{
    // The seed length is (33 - 10) = 23.
    // // (11101001000 11101001000 1. Has weight only 11
    const int eliminatedCarePossitionsNo = 1;
    const int weight = 11;
    unsigned int hashValue = getF3SeedHashValue4ReadLength34(r.UpperBits);
    hashValue >>= eliminatedCarePossitionsNo;
    hashValue <<= weight;
    hashValue += (getF3SeedHashValue4ReadLength34(r.LowerBits) >> eliminatedCarePossitionsNo);
    return hashValue;
}


inline unsigned int getF3SeedHashValue4ReadLength29_32(WORD_SIZE Bits)
{
    // The seed length is (32 - 10) = 22.
    // (11101001000 11101001000. Has weight only 11
    WORD_SIZE hashValue = 0;

    hashValue += (Bits & 0x07); // Get the first 3 digit
    Bits >>= 4;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 4th digit
    Bits >>= 3;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 5th digit
    Bits >>= 4;
    hashValue <<= 3;

    hashValue += (Bits & 0x07); // Get the first 6-8 digit
    Bits >>= 4;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 9th digit
    Bits >>= 3;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the first 10th digit
    return ((unsigned int)hashValue);
}

// Get first 10 care bits and concatenate together.
unsigned int getF3SeedHashValue4ReadLength29_32(CReadInBits r)
{
    // The seed length is (29 - 10) = 19.
    // 11101001000 11101001 Has weight only 10
    const int weight = 10;
    WORD_SIZE hashValue = getF3SeedHashValue4ReadLength29_32(r.UpperBits);
    hashValue <<= weight;
    hashValue += getF3SeedHashValue4ReadLength29_32(r.LowerBits);
    return ((unsigned int)hashValue);
}

// Get first 9 care bits and concatenate together.
unsigned int getF3SeedHashValue4ReadLength26_28(CReadInBits r)
{
    // The seed length is (26 - 10) = 16.
    // 11101001000 11101 Has weight only 9
    const int eliminatedCarePossitionsNo = 1;
    const int weight = 9;
    unsigned int hashValue = getF3SeedHashValue4ReadLength29_32(r.UpperBits);
    hashValue >>= eliminatedCarePossitionsNo;
    hashValue <<= weight;
    hashValue += (getF3SeedHashValue4ReadLength29_32(r.LowerBits) >> eliminatedCarePossitionsNo);
    return hashValue;
}

// Get first 8 care bits and concatenate together.
unsigned int getF3SeedHashValue4ReadLength25(CReadInBits r)
{
    // The seed length is (25 - 10) = 15.
    // 11101001000 11101 Has weight only 8
    const int eliminatedCarePossitionsNo = 2;
    const int weight = 8;
    unsigned int hashValue = getF3SeedHashValue4ReadLength29_32(r.UpperBits);
    hashValue >>= eliminatedCarePossitionsNo;
    hashValue <<= weight;
    hashValue += (getF3SeedHashValue4ReadLength29_32(r.LowerBits) >> eliminatedCarePossitionsNo);
    return hashValue;
}

ptHashFunc selectF3(int readlength)
{
    if (readlength > 34) {
        return &getF3SeedHashValue;
    } else if (readlength == 34) {
        return &getF3SeedHashValue4ReadLength34;
    } else if (readlength == 33) {
        return &getF3SeedHashValue4ReadLength33;
    } else if (29 <= readlength && readlength <= 32) {
        return &getF3SeedHashValue4ReadLength29_32;
    } else if (26 <= readlength && readlength <= 28) {
        return &getF3SeedHashValue4ReadLength26_28;
    } else {
        LOG_INFO("\nInfo %d: No hash function defined for read with length %d\n", WARNING_LOG, readlength);
        return (NULL);
    }
}

unsigned int getF3SeedKey(WORD_SIZE Bits, int keyWeight)
{
    // Use the suffixLength bits based on the seed pattern (11101001000 11101001000 1110 ) (100 1000 1110) (100 1000 1110) to create a value
    WORD_SIZE uiKey =  0;
    for (; keyWeight > 0; keyWeight -= 5) {
        uiKey <<= 1;
        uiKey += (Bits & 0x01);
        Bits >>= 3;

        uiKey <<= 1;
        uiKey += (Bits & 0x01);
        Bits >>= 4;

        uiKey <<= 1;
        uiKey += (Bits & 0x01);
        Bits >>= 1;

        uiKey <<= 1;
        uiKey += (Bits & 0x01);
        Bits >>= 1;

        uiKey <<= 1;
        uiKey += (Bits & 0x01);  // for read length 47 (Possition 36)
        Bits >>= 2;
    }
    uiKey >>= (-1 * keyWeight);
    return ((unsigned int)uiKey);
}

unsigned int getF3SeedKey(CReadInBits r, int keyWeight)
{
    if (keyWeight > 0) {
        // The seed pattern is 11101001000 11101001000 111 01
        // The first 13 care position, that is the first 25 position are used for hash value
        r.UpperBits >>= 26;
        r.LowerBits >>= 26;

        unsigned int uiKey1 = getF3SeedKey(r.UpperBits, keyWeight);
        unsigned int uiKey2 = getF3SeedKey(r.LowerBits, keyWeight);
#ifdef EXTEND_SEED
        unsigned int uiKey = InterleaveBits((unsigned short) uiKey2, (unsigned short)  uiKey1);
#else
        unsigned int uiKey = (uiKey1 << keyWeight) + uiKey2;
#endif
        return uiKey;
    } else {
        return(0);
    }
}

unsigned int getF3SeedKey4ReadLength34(WORD_SIZE Bits, int keyWeight)
{
    // Use the suffixLength bits based on the seed pattern (11101001000 11101001000 11)10 100 1000 1 to create a value
    // the keyWeight under extended seed is 12 + 4. (Because the maximium weight is 16 add 4)
    keyWeight = 0;
    WORD_SIZE uiKey =  0;

    uiKey += (Bits & 0x01);
    uiKey <<= 1;
    Bits >>= 2;

    uiKey += (Bits & 0x01);
    uiKey <<= 1;
    Bits >>= 3;

    uiKey += (Bits & 0x01);
    uiKey <<= 1;
    Bits >>= 4;

    uiKey += (Bits & 0x01);

    return ((unsigned int)uiKey);
}

unsigned int getF3SeedKey4ReadLength34(CReadInBits r, int keyWeight)
{
    if (keyWeight > 0) {
        // Use the suffixLength bits based on the seed pattern (11101001000 11101001000 11)10 100 1000 1 to create a value
        // the keyWeight under extended seed is 12 + 4. (Because the maximum weight is 16 add 4)
        r.UpperBits >>= 24;
        r.LowerBits >>= 24;

        unsigned int uiKey1 = getF3SeedKey4ReadLength34(r.UpperBits, keyWeight);
        unsigned int uiKey2 = getF3SeedKey4ReadLength34(r.LowerBits, keyWeight);

        unsigned int uiKey = InterleaveBits((unsigned short) uiKey2, (unsigned short)  uiKey1);

        return uiKey;
    } else {
        return(0);
    }
}

unsigned int getF3SeedKey4ReadLength32(WORD_SIZE Bits, int keyWeight)
{
    // Use the suffixLength bits based on the seed pattern (11101001000 11101001000) 1110 100 1000
    // the keyWeight under extended seed is 10 + 5. (Because the maximum weight is 10 add 5)
    WORD_SIZE uiKey =  0;
    uiKey += (Bits & 0x07);
    uiKey <<= 1;
    Bits >>= 4;

    uiKey += (Bits & 0x01);
    uiKey <<= 1;
    Bits >>= 3;

    uiKey += (Bits & 0x01);
    return ((unsigned int)uiKey);
}

unsigned int getF3SeedKey4ReadLength32(CReadInBits r, int keyWeight)
{
    // Use the suffixLength bits based on the seed pattern (11101001000 11101001000) 1110 100 1000
    // the keyWeight under extended seed is 10 + 5. (Because the maximum weight is 10 add 5)
    if (keyWeight > 0) {
        r.UpperBits >>= 22;
        r.LowerBits >>= 22;

        unsigned int uiKey1 = getF3SeedKey4ReadLength32(r.UpperBits, keyWeight);
        unsigned int uiKey2 = getF3SeedKey4ReadLength32(r.LowerBits, keyWeight);
        unsigned int uiKey = InterleaveBits((unsigned short) uiKey2, (unsigned short)  uiKey1);
        return uiKey;
    } else {
        return(0);
    }
}

////////////////////////////////////////////////////////////////////////////////
inline unsigned int getS1_2SeedHashValue(WORD_SIZE Bits)
{
    // To save the number of CPU instructions, the value encoded bits that doesn't follow the order of reads
    // It still gets the first 3 digit and the fifth digit.. and so on to get total 13 digits
    // (11110010000000)(11110010000000)(111)
    WORD_SIZE hashValue = 0;

    hashValue += (Bits & 0x0f); // Get the first 4 digit
    Bits >>= 6;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the 5th digit
    Bits >>= 8;
    hashValue <<= 4;

    hashValue += (Bits & 0x0f); // Get the first 6-9th digit
    Bits >>= 6;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the 10th digit
    Bits >>= 8;
    hashValue <<= 3;

    hashValue += (Bits & 0x07); // Get the first 11-13 digit
    return ((unsigned int)hashValue);
}

unsigned int getS1_2SeedHashValue(CReadInBits r)
{
    WORD_SIZE hashValue = getS1_2SeedHashValue(r.UpperBits);
    hashValue <<= BITS_FOR_HASHING;
    hashValue += getS1_2SeedHashValue(r.LowerBits);
    return ((unsigned int)hashValue);
}

unsigned int getS1_2SeedKey4ReadLength46_49(WORD_SIZE Bits, int keyWeight)
{
    // 1001
    WORD_SIZE uiKey =  0;
    uiKey = Bits & 0x01;
    if (keyWeight == 1)
        return ((unsigned int)uiKey);
    else {
        uiKey <<= 1;
        Bits >>= 3;
        uiKey += Bits & 0x01;
        return ((unsigned int)uiKey);
    }
}

// EXTEND_SEED
unsigned int getS1_2SeedKey4ReadLength46_49(CReadInBits r, int keyWeight)
{
    // The seed pattern is 11110010000000 11110010000000 111 100100
    // The first 13 care position, that is the first 31 position are used for hash value
    r.UpperBits >>= 31; // The first 21 base are used as hash key (111*1**)(111*1**)(111*1**)1
    r.LowerBits >>= 31;

    unsigned int uiKey1 = getS1_2SeedKey4ReadLength46_49(r.UpperBits, keyWeight);
    unsigned int uiKey2 = getS1_2SeedKey4ReadLength46_49(r.LowerBits, keyWeight);
#ifdef EXTEND_SEED
    unsigned int uiKey = InterleaveBits((unsigned short) uiKey2, (unsigned short)  uiKey1);
#else
    unsigned int uiKey = (uiKey1 << keyWeight) + uiKey2;
#endif
    return uiKey;
}


////////////////////////////////////////////////////////////////////////////////
inline unsigned int getF4SeedHashValue(WORD_SIZE Bits)
{
// To save the number of CPU instructions, the value encoded bits that doesn't follow the order of reads
    //50 - 9 = 41
    // (1100010000)(1100010000)(1100010000)(1100010000) 1 The weight is 13
    WORD_SIZE hashValue = 0;
    hashValue += (Bits & 0x03); // Get the first 2 digit
    Bits >>= 5;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the 3th digit
    Bits >>= 5;
    hashValue <<= 2;
    hashValue += (Bits & 0x03); // Get the 4 and 5th digit
    Bits >>= 5;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the 6th digit
    Bits >>= 5;
    hashValue <<= 2;
    hashValue += (Bits & 0x03); // Get the first 7 and 8th digit
    Bits >>= 5;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the 9th digit
    Bits >>= 5;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the 10th digit
    Bits >>= 1;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the 11th digit
    Bits >>= 4;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the 12th digit
    Bits >>= 5;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the 13th digit
    return ((unsigned int)hashValue);
}

// Get first 13 care bits and concatenate together, with read length = 50
unsigned int getF4SeedHashValue(CReadInBits r)
{
    // The seed length is 50 - (10 - 1) = 41
    // (1100010000)(1100010000)(1100010000) 1100010000. The weight is 13
    const int weight = 13;
    unsigned int hashValue = getF4SeedHashValue(r.UpperBits);
    hashValue <<= weight;
    hashValue += getF4SeedHashValue(r.LowerBits);
    return hashValue;
}

// Get first 12 care bits and concatenate together.
unsigned int getF4SeedHashValue4ReadLength45_49(CReadInBits r)
{
    // The seed length is 45 - (10 - 1) = 36
    // (1100010000)(1100010000)(1100010000) 110001 The weight is 12
    const int eliminatedCarePossitionsNo = 1;
    const int weight = 12;
    unsigned int hashValue = getF4SeedHashValue(r.UpperBits);
    hashValue >>= eliminatedCarePossitionsNo;
    hashValue <<= weight;
    hashValue += (getF4SeedHashValue(r.LowerBits) >> eliminatedCarePossitionsNo);
    return hashValue;
}

// Get first 11 care bits and concatenate together.
unsigned int getF4SeedHashValue4ReadLength41_44(CReadInBits r)
{
    // The seed length is 41 - (10 - 1) = 32
    // (1100010000)(1100010000)(1100010000) 11 The weight is 11
    const int eliminatedCarePossitionsNo = 2;
    const int weight = 11;
    unsigned int hashValue = getF4SeedHashValue(r.UpperBits);
    hashValue >>= eliminatedCarePossitionsNo;
    hashValue <<= weight;
    hashValue += (getF4SeedHashValue(r.LowerBits) >> eliminatedCarePossitionsNo);
    return hashValue;
}

// Get first 10 care bits and concatenate together.
unsigned int getF4SeedHashValue4ReadLength40(CReadInBits r)
{
    // The seed length is 40 - (10 - 1) = 31
    // (1100010000)(1100010000)(1100010000) 1 The weight is 10
    const int eliminatedCarePossitionsNo = 3;
    const int weight = 10;
    unsigned int hashValue = getF4SeedHashValue(r.UpperBits);
    hashValue >>= eliminatedCarePossitionsNo;
    hashValue <<= weight;
    hashValue += (getF4SeedHashValue(r.LowerBits) >> eliminatedCarePossitionsNo);
    return hashValue;
}

inline unsigned int getF4SeedHashValue4ReadLength35_39(WORD_SIZE Bits)
{
    // The seed length is 35 - (10 - 1) = 26; 39 - (10 - 1) = 30
    // (1100010000)(1100010000)(1100010000) The weight is 9
    WORD_SIZE hashValue = 0;
    hashValue += (Bits & 0x03); // Get the first 2 digit
    Bits >>= 5;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the 3th digit
    Bits >>= 5;
    hashValue <<= 2;
    hashValue += (Bits & 0x03); // Get the 4 and 5th digit
    Bits >>= 5;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the 6th digit
    Bits >>= 5;
    hashValue <<= 2;
    hashValue += (Bits & 0x03); // Get the first 7 and 8th digit
    Bits >>= 5;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the 9th digit
    return ((unsigned int)hashValue);
}

// Get first 9 care bits and concatenate together.
unsigned int getF4SeedHashValue4ReadLength35_39(CReadInBits r)
{
    // The seed length is 35 - (10 - 1) = 26; 39 - (10 - 1) = 30
    // (1100010000)(1100010000)(110001) The weight is 9

    const int SeedWeight = 9;
    WORD_SIZE hashValue = getF4SeedHashValue4ReadLength35_39(r.UpperBits);
    hashValue <<= SeedWeight;
    hashValue += getF4SeedHashValue4ReadLength35_39(r.LowerBits);
    return ((unsigned int)hashValue);
}

inline unsigned int getF4SeedHashValue4ReadLength31_34(WORD_SIZE Bits)
{
    // The seed length is 34 - (10 - 1) = 25; 31 - (10 - 1) = 22
    // (1100010000)(1100010000)(11000) The weight is 8
    WORD_SIZE hashValue = 0;
    hashValue += (Bits & 0x03); // Get the first 2 digit
    Bits >>= 5;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the 3th digit
    Bits >>= 5;
    hashValue <<= 2;
    hashValue += (Bits & 0x03); // Get the 4 and 5th digit
    Bits >>= 5;
    hashValue <<= 1;
    hashValue += (Bits & 0x01); // Get the 6th digit
    Bits >>= 5;
    hashValue <<= 2;
    hashValue += (Bits & 0x03); // Get the first 7 and 8th digit
    return ((unsigned int)hashValue);
}

// Get first 8 care bits and concatenate together.
unsigned int getF4SeedHashValue4ReadLength31_34(CReadInBits r)
{
    // The seed length is 34 - (10 - 1) = 25; 31 - (10 - 1) = 22
    // (1100010000)(1100010000)(11000) The weight is 8
    const int SeedWeight = 8;
    WORD_SIZE hashValue = getF4SeedHashValue4ReadLength31_34(r.UpperBits);
    hashValue <<= SeedWeight;
    hashValue += getF4SeedHashValue4ReadLength31_34(r.LowerBits);
    return ((unsigned int)hashValue);
}

ptHashFunc selectF4(int readlength)
{
    if (readlength >= 50) {
        return &getF4SeedHashValue; // weight 13
    } else if (45 <= readlength && readlength <= 49) {
        return &getF4SeedHashValue4ReadLength45_49; // weight 12
    } else if (41 <= readlength && readlength <= 44) {
        return &getF4SeedHashValue4ReadLength41_44; // weight 10
    } else if (readlength == 40) {
        return &getF4SeedHashValue4ReadLength40; // weight 9
    } else if (35 <= readlength && readlength <= 39) {
        return &getF4SeedHashValue4ReadLength35_39; // weight 8
    } else if (31 <= readlength && readlength <= 34) {
        return &getF4SeedHashValue4ReadLength31_34; // weight 8
    } else {
        LOG_INFO("\nInfo %d: No hash function defined for read with length %d\n", WARNING_LOG, readlength);
        return (NULL);
    }
}

unsigned int getNoOfCaredPositions(const char* caSeedRepeat, unsigned int uiReadLength)
{
    unsigned int carePositions = 0;
    unsigned int seedRepeatLength = (unsigned int)strlen(caSeedRepeat);
    for (unsigned int i = 0; i < uiReadLength - seedRepeatLength + 1; i++) {
        if (caSeedRepeat[ i % seedRepeatLength ] == '1')
            carePositions++;
    }
    return(carePositions);
}

unsigned int getNoOfCaredPositions4FullRead(const char* caSeedRepeat, unsigned int uiReadLength)
{
    unsigned int carePositions = 0;
    unsigned int seedRepeatLength = (unsigned int)strlen(caSeedRepeat);
    for (unsigned int i = 0; i < uiReadLength; i++) {
        if (caSeedRepeat[ i % seedRepeatLength ] == '1')
            carePositions++;
    }
    return(carePositions);
}

