#include <pbdata/FASTQReader.hpp>

#include <climits>
#include <cmath>
#include <cstdio>

FASTQReader::FASTQReader() : FASTAReader() { endOfReadDelim = '\n'; }

int FASTQReader::GetNext(FASTASequence &seq) { return ((FASTAReader *)this)->GetNext(seq); }

unsigned char FASTQReader::phredQVtoPacbioQV(unsigned char phredQV)
{
    int qual = floor(100.0 * log10(pow(10.0, phredQV / 10.0) - 1.0) + 0.5);
    qual = qual > 250 ? 250 : qual;
    qual = qual < 1 ? 1 : qual;
    return (unsigned char)qual;
}

int FASTQReader::GetNext(FASTQSequence &seq)
{
    seq.Free();  // Free seq before being reused.
    char c;
    while (curPos < fileSize and
           ((c = filePtr[curPos]) == ' ' or c == '\t' or c == '\n' or c == '\r')) {
        curPos++;
    }

    if (curPos >= fileSize) {
        return false;
    }
    GenomeLength p = curPos;
    AdvanceToTitleStart(p, '@');
    CheckValidTitleStart(p, '@');
    ReadTitle(p, seq);
    // Title ends on '\n', consume that;
    p++;
    GenomeLength p2;
    p2 = p;
    while (p2 < fileSize and filePtr[p2] != '\n') {
        p2++;
    }
    if (p2 - p > UINT_MAX) {
        std::cout
            << "ERROR! Reading sequences stored in more than 4Gbytes of space is not supported."
            << std::endl;
        std::exit(EXIT_FAILURE);
    }

    seq.length = p2 - p;
    GenomeLength seqPos;
    if (seq.length > 0) {
        seq.seq = ProtectedNew<Nucleotide>(seq.length);
        p2 = p;
        seqPos = 0;
        while (p2 < fileSize and filePtr[p2] != '\n') {
            seq.seq[seqPos] = filePtr[p2];
            p2++;
            seqPos++;
        }
    } else {
        seq.seq = 0;
    }
    p = p2;

    AdvanceToTitleStart(p, '+');
    CheckValidTitleStart(p, '+');
    while (p < fileSize and filePtr[p] != '\n') {
        p++;
    }
    p++;  // skip '\n'
    p2 = p;
    while (p2 < fileSize and filePtr[p2] != '\n') {
        p2++;
    }
    seq.length = p2 - p;
    if (seq.length > 0) {
        seq.qual.Allocate(seq.length);
        p2 = p;
        GenomeLength seqPos = 0;
        while (p2 < fileSize and filePtr[p2] != '\n') {
            seq.qual[seqPos] = filePtr[p2] - FASTQSequence::charToQuality;
            p2++;
            seqPos++;
        }
    } else {
        seq.qual.data = NULL;
    }
    curPos = p2;
    seq.deleteOnExit = true;
    return 1;
}

int FASTQReader::Advance(int nSteps)
{
    // An advance of a FASTQ file is simply twice the number of
    // advances of FASTA, since each nucleotide sequence has a quality
    // sequence.
    return ((FASTAReader *)this)->Advance(nSteps * 2);
}
