#include "TestFramework.h"
#include "htio2/Kmer.h"

#include <limits>

using namespace htio2;
using namespace std;

typedef uint64_t KmerType;

void TestFramework::content()
{
    // encode
    EncodedSeq enc;
    encode_nt4("ATGXCATAATGXCATAATGXCATAATGXCATA", enc);
    IS(enc.size(), 32);
    IS(enc[0], ENCODED_NT4_A);
    IS(enc[1], ENCODED_NT4_T);
    IS(enc[2], ENCODED_NT4_G);
    IS(enc[3], ENCODED_ERROR);
    IS(enc[4], ENCODED_NT4_C);
    IS(enc[5], ENCODED_NT4_A);
    IS(enc[6], ENCODED_NT4_T);
    IS(enc[7], ENCODED_NT4_A);
    IS(enc[8], ENCODED_NT4_A);
    IS(enc[9], ENCODED_NT4_T);
    IS(enc[10], ENCODED_NT4_G);
    IS(enc[11], ENCODED_ERROR);
    IS(enc[12], ENCODED_NT4_C);
    IS(enc[13], ENCODED_NT4_A);
    IS(enc[14], ENCODED_NT4_T);
    IS(enc[15], ENCODED_NT4_A);
    IS(enc[16], ENCODED_NT4_A);
    IS(enc[17], ENCODED_NT4_T);
    IS(enc[18], ENCODED_NT4_G);
    IS(enc[19], ENCODED_ERROR);
    IS(enc[20], ENCODED_NT4_C);
    IS(enc[21], ENCODED_NT4_A);
    IS(enc[22], ENCODED_NT4_T);
    IS(enc[23], ENCODED_NT4_A);
    IS(enc[24], ENCODED_NT4_A);
    IS(enc[25], ENCODED_NT4_T);
    IS(enc[26], ENCODED_NT4_G);
    IS(enc[27], ENCODED_ERROR);
    IS(enc[28], ENCODED_NT4_C);
    IS(enc[29], ENCODED_NT4_A);
    IS(enc[30], ENCODED_NT4_T);
    IS(enc[31], ENCODED_NT4_A);

    {
        // generate kmer
        vector<KmerType> kmers;
        OK(gen_kmer_nt4(enc, kmers, 3));
        IS(kmers.size(), 30);
        IS(kmers[0], ENCODED_NT4_A + ENCODED_NT4_T*4 + ENCODED_NT4_G*4*4);
        IS(kmers[1], numeric_limits<KmerType>::max());
        IS(kmers[2], numeric_limits<KmerType>::max());
        IS(kmers[3], numeric_limits<KmerType>::max());
        IS(kmers[4], ENCODED_NT4_C + ENCODED_NT4_A*4 + ENCODED_NT4_T*4*4);
        IS(kmers[5], ENCODED_NT4_A + ENCODED_NT4_T*4 + ENCODED_NT4_A*4*4);
        IS(kmers[6], ENCODED_NT4_T + ENCODED_NT4_A*4 + ENCODED_NT4_A*4*4);
        IS(kmers[7], ENCODED_NT4_A + ENCODED_NT4_A*4 + ENCODED_NT4_T*4*4);
        IS(kmers[8], ENCODED_NT4_A + ENCODED_NT4_T*4 + ENCODED_NT4_G*4*4);
        IS(kmers[9], numeric_limits<KmerType>::max());
        IS(kmers[10], numeric_limits<KmerType>::max());
        IS(kmers[11], numeric_limits<KmerType>::max());
        IS(kmers[12], ENCODED_NT4_C + ENCODED_NT4_A*4 + ENCODED_NT4_T*4*4);
        IS(kmers[13], ENCODED_NT4_A + ENCODED_NT4_T*4 + ENCODED_NT4_A*4*4);
        IS(kmers[14], ENCODED_NT4_T + ENCODED_NT4_A*4 + ENCODED_NT4_A*4*4);
        IS(kmers[15], ENCODED_NT4_A + ENCODED_NT4_A*4 + ENCODED_NT4_T*4*4);
        IS(kmers[16], ENCODED_NT4_A + ENCODED_NT4_T*4 + ENCODED_NT4_G*4*4);
        IS(kmers[17], numeric_limits<KmerType>::max());
        IS(kmers[18], numeric_limits<KmerType>::max());
        IS(kmers[19], numeric_limits<KmerType>::max());
        IS(kmers[20], ENCODED_NT4_C + ENCODED_NT4_A*4 + ENCODED_NT4_T*4*4);
        IS(kmers[21], ENCODED_NT4_A + ENCODED_NT4_T*4 + ENCODED_NT4_A*4*4);
        IS(kmers[22], ENCODED_NT4_T + ENCODED_NT4_A*4 + ENCODED_NT4_A*4*4);
        IS(kmers[23], ENCODED_NT4_A + ENCODED_NT4_A*4 + ENCODED_NT4_T*4*4);
        IS(kmers[24], ENCODED_NT4_A + ENCODED_NT4_T*4 + ENCODED_NT4_G*4*4);
        IS(kmers[25], numeric_limits<KmerType>::max());
        IS(kmers[26], numeric_limits<KmerType>::max());
        IS(kmers[27], numeric_limits<KmerType>::max());
        IS(kmers[28], ENCODED_NT4_C + ENCODED_NT4_A*4 + ENCODED_NT4_T*4*4);
        IS(kmers[29], ENCODED_NT4_A + ENCODED_NT4_T*4 + ENCODED_NT4_A*4*4);

        // decode kmer
        IS(decode_kmer_nt4(kmers[0], 3), "ATG");
        IS(decode_kmer_nt4(kmers[1], 3), "");
        IS(decode_kmer_nt4(kmers[2], 3), "");
        IS(decode_kmer_nt4(kmers[3], 3), "");
        IS(decode_kmer_nt4(kmers[4], 3), "CAT");
        IS(decode_kmer_nt4(kmers[5], 3), "ATA");
        IS(decode_kmer_nt4(kmers[6], 3), "TAA");
        IS(decode_kmer_nt4(kmers[7], 3), "AAT");
        IS(decode_kmer_nt4(kmers[8], 3), "ATG");
        IS(decode_kmer_nt4(kmers[9], 3), "");
        IS(decode_kmer_nt4(kmers[10], 3), "");
        IS(decode_kmer_nt4(kmers[11], 3), "");
        IS(decode_kmer_nt4(kmers[12], 3), "CAT");
        IS(decode_kmer_nt4(kmers[13], 3), "ATA");
        IS(decode_kmer_nt4(kmers[14], 3), "TAA");
        IS(decode_kmer_nt4(kmers[15], 3), "AAT");
        IS(decode_kmer_nt4(kmers[16], 3), "ATG");
        IS(decode_kmer_nt4(kmers[17], 3), "");
        IS(decode_kmer_nt4(kmers[18], 3), "");
        IS(decode_kmer_nt4(kmers[19], 3), "");
        IS(decode_kmer_nt4(kmers[20], 3), "CAT");
        IS(decode_kmer_nt4(kmers[21], 3), "ATA");
        IS(decode_kmer_nt4(kmers[22], 3), "TAA");
        IS(decode_kmer_nt4(kmers[23], 3), "AAT");
        IS(decode_kmer_nt4(kmers[24], 3), "ATG");
        IS(decode_kmer_nt4(kmers[25], 3), "");
        IS(decode_kmer_nt4(kmers[26], 3), "");
        IS(decode_kmer_nt4(kmers[27], 3), "");
        IS(decode_kmer_nt4(kmers[28], 3), "CAT");
        IS(decode_kmer_nt4(kmers[29], 3), "ATA");
    }

    {
        vector<KmerType> kmers;
        OK(gen_kmer_nt4(enc, kmers, 31));
        IS(kmers.size(), 2);

        KmerType kmer =
                ENCODED_NT4_A +
                ENCODED_NT4_T *4L +
                ENCODED_NT4_G *4L*4L +
                ENCODED_NT4_C *4L*4L*4L +
                ENCODED_NT4_A *4L*4L*4L*4L +
                ENCODED_NT4_T *4L*4L*4L*4L*4L +
                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L +
                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L*4L +
                ENCODED_NT4_T *4L*4L*4L*4L*4L*4L*4L*4L +
                ENCODED_NT4_G *4L*4L*4L*4L*4L*4L*4L*4L*4L +
                ENCODED_NT4_C *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
                ENCODED_NT4_T *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
                ENCODED_NT4_T *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
                ENCODED_NT4_G *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
                ENCODED_NT4_C *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
                ENCODED_NT4_T *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
                ENCODED_NT4_T *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
                ENCODED_NT4_G *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
                ENCODED_NT4_C *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
                ENCODED_NT4_T *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L +
                ENCODED_NT4_A *4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L*4L;
        IS(gen_kmer_nt4<KmerType>("ATGCATAATGCATAAATGCATAATGCATAAA"), kmer);
    }

    {
        vector<KmerType> kmers;
        OK(!gen_kmer_nt4(enc, kmers, 32));
        IS(kmers.size(), 0);

        IS(gen_kmer_nt4<KmerType>("ATGCATAATGCATAAAATGCATAATGCATAAA"), numeric_limits<KmerType>::max());
    }

    // decode
    {
        string dec;
        decode_nt4(enc, dec);
        IS(dec, "ATGNCATAATGNCATAATGNCATAATGNCATA");
    }
}
