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

#include <limits>

using namespace htio2;
using namespace std;

typedef uint32_t KmerType;

void TestFramework::content()
{
    // encode
    EncodedSeq enc;
    encode_nt5("ATGXCNTAATGXCNTA", enc);
    IS(enc.size(), 16);
    IS(enc[0], ENCODED_NT5_A);
    IS(enc[1], ENCODED_NT5_T);
    IS(enc[2], ENCODED_NT5_G);
    IS(enc[3], ENCODED_ERROR);
    IS(enc[4], ENCODED_NT5_C);
    IS(enc[5], ENCODED_NT5_N);
    IS(enc[6], ENCODED_NT5_T);
    IS(enc[7], ENCODED_NT5_A);
    IS(enc[8], ENCODED_NT5_A);
    IS(enc[9], ENCODED_NT5_T);
    IS(enc[10], ENCODED_NT5_G);
    IS(enc[11], ENCODED_ERROR);
    IS(enc[12], ENCODED_NT5_C);
    IS(enc[13], ENCODED_NT5_N);
    IS(enc[14], ENCODED_NT5_T);
    IS(enc[15], ENCODED_NT5_A);

    {
        // generate kmer
        vector<KmerType> kmers;
        OK(gen_kmer_nt5(enc, kmers, 3));
        IS(kmers.size(), 14);
        IS(kmers[0], ENCODED_NT5_A + ENCODED_NT5_T*5 + ENCODED_NT5_G*5*5);
        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_NT5_C + ENCODED_NT5_N*5 + ENCODED_NT5_T*5*5);
        IS(kmers[5], ENCODED_NT5_N + ENCODED_NT5_T*5 + ENCODED_NT5_A*5*5);
        IS(kmers[6], ENCODED_NT5_T + ENCODED_NT5_A*5 + ENCODED_NT5_A*5*5);
        IS(kmers[7], ENCODED_NT5_A + ENCODED_NT5_A*5 + ENCODED_NT5_T*5*5);
        IS(kmers[8], ENCODED_NT5_A + ENCODED_NT5_T*5 + ENCODED_NT5_G*5*5);
        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_NT5_C + ENCODED_NT5_N*5 + ENCODED_NT5_T*5*5);
        IS(kmers[13], ENCODED_NT5_N + ENCODED_NT5_T*5 + ENCODED_NT5_A*5*5);

        // decode kmer
        IS(decode_kmer_nt5(kmers[0], 3), "ATG");
        IS(decode_kmer_nt5(kmers[1], 3), "");
        IS(decode_kmer_nt5(kmers[2], 3), "");
        IS(decode_kmer_nt5(kmers[3], 3), "");
        IS(decode_kmer_nt5(kmers[4], 3), "CNT");
        IS(decode_kmer_nt5(kmers[5], 3), "NTA");
        IS(decode_kmer_nt5(kmers[6], 3), "TAA");
        IS(decode_kmer_nt5(kmers[7], 3), "AAT");
        IS(decode_kmer_nt5(kmers[8], 3), "ATG");
        IS(decode_kmer_nt5(kmers[9], 3), "");
        IS(decode_kmer_nt5(kmers[10], 3), "");
        IS(decode_kmer_nt5(kmers[11], 3), "");
        IS(decode_kmer_nt5(kmers[12], 3), "CNT");
        IS(decode_kmer_nt5(kmers[13], 3), "NTA");
    }

    {
        vector<KmerType> kmers;
        OK(gen_kmer_nt5(enc, kmers, 13));
        IS(kmers.size(), 4);

        KmerType kmer =
                ENCODED_NT5_A +
                ENCODED_NT5_T *5 +
                ENCODED_NT5_G *5*5 +
                ENCODED_NT5_C *5*5*5 +
                ENCODED_NT5_N *5*5*5*5 +
                ENCODED_NT5_T *5*5*5*5*5 +
                ENCODED_NT5_A *5*5*5*5*5*5 +
                ENCODED_NT5_T *5*5*5*5*5*5*5 +
                ENCODED_NT5_G *5*5*5*5*5*5*5*5 +
                ENCODED_NT5_C *5*5*5*5*5*5*5*5*5 +
                ENCODED_NT5_N *5*5*5*5*5*5*5*5*5*5 +
                ENCODED_NT5_T *5*5*5*5*5*5*5*5*5*5*5 +
                ENCODED_NT5_A *5*5*5*5*5*5*5*5*5*5*5*5;
        IS(gen_kmer_nt5<KmerType>("ATGCNTATGCNTA"), kmer);
    }

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

        IS(gen_kmer_nt5<KmerType>("ATGCNTTATGCNTT"), numeric_limits<KmerType>::max());
    }
}
