#pragma once

#include "stdafx.h"
#include "Filename.h"
#include "FileInputBuffer.h"
#include <iostream>
using namespace std;
const char SolexaScoreEncodingShift = 64;
const char Phred_SCALE_QUAL_SHIFT = 33;
const int READ_ID_LENGTH = 260;

struct CReadID {
    char id[READ_ID_LENGTH];
};

class CReadsQualScores
{
public:
    CReadsQualScores(void);
    CReadsQualScores(unsigned int readLength, unsigned int numOfReads);
    ~CReadsQualScores(void);
    void clear(void);
    void reserve(unsigned int numOfReads);
    bool openQUALfile(const char* Filename);
    unsigned int getQualityScoresFromQUAL(vector<CReadID>* pReadsID);

    inline void  addQSs(const char* QSs);
    inline char* qScores(unsigned int readId);
    inline char  baseQS4SOLiD(unsigned int readId, unsigned int possition);
    inline char  qs(unsigned int readId, unsigned int possition);
    unsigned int readLength;
    unsigned int numOfReads;
    unsigned int load; // number of reads has been loaded.
    char scoreType; // The type of the score system I=illumina S=SOLiD
private:
    ifstream ifile;
    FileInputBuffer IBuf;
    char* QSarray;
    unsigned int size; // The memory allocated, qScore capacity in bases
    void initialization(unsigned int readLength, unsigned int numOfReads);
    // return the ID that the tag aligned to, so store the quality scores
    int alignReadId4QScores(char* tag, unsigned int searchPoint, vector<CReadID>* pReadsID);
};
inline void formatReadId(char* readIdStr, char sep = ',')
{
    for (int i = 0; readIdStr[i] != '\0'; i++) {
        char c = readIdStr[i];
        if ( iscntrl(c) || isspace(c) || c == sep) {
            readIdStr[i] = '\0';
            break;
        }
    }
}

inline void  CReadsQualScores::addQSs(const char* QSs)
{
    unsigned int qsIndex = this->load  * this->readLength;
    if (qsIndex + this->readLength <= this->size ) {
        for (unsigned int i = 0; i < this->readLength; i++) {
            this->QSarray[qsIndex + i] = QSs[i];
        }
        this->load ++;
    } else {
        LOG_INFO("\nInfo %d: Quality scores out of capacity .\n", WARNING_LOG);
    }
}

inline bool isValidSolexaQScore(char qscore)
{
    const char maxScore = 40;
    const char minScore = -5;
    return (minScore <= qscore && qscore <= maxScore);
};

inline bool isValidSolidQScore(char qscore)
{
    const char maxScore = 80;
    const char minScore = 0;
    return (minScore <= qscore && qscore <= maxScore);
};

inline char getSolexaQScore(char qscore)
{
    const char minScore = -5;
    qscore = qscore - SolexaScoreEncodingShift;
    if (isValidSolexaQScore(qscore)) {
        return(qscore);
    } else {
        return(minScore);
    }
};

void trQScores(unsigned int readLength, char qShift, const char* oldQSs, char* newQSs);
inline void fillDummyQScores(unsigned int readLength, char score, char* QSs)
{
    memset(QSs, (int)readLength*sizeof(char), score);
    QSs[readLength] = '\0';
}

// return pointers of the quality scores for a read
inline char* CReadsQualScores::qScores(unsigned int readId)
{
    unsigned int qsId = readId * this->readLength;
    if (qsId < size)
        return(&this->QSarray[qsId]);
    else
        printf("\rAccess qscore out of bound!");
    return(NULL); // dummy quality score
}

// return the quality score of a base signal or a color signal in SOLiD system
inline char CReadsQualScores::qs(unsigned int readId, unsigned int possition)
{
    unsigned int qsId = readId * this->readLength + possition;
    if (qsId < size)
        return(this->QSarray[qsId]);
    else
        printf("\rAccess qscore out of bound!");
    return(0); // dummy quality score
}

// return the quality score of a base by average the two color signal quality score
inline char CReadsQualScores::baseQS4SOLiD(unsigned int readId, unsigned int possition)
{
    unsigned int qsId = readId * this->readLength + possition;
    if (qsId < size) {
        char qScore = this->QSarray[qsId];
        // The first and the last base may have less accuracy
        if (possition != 0 && possition != this->readLength - 1) {
            qScore += this->QSarray[qsId + 1];
        }
        return(qScore / 2); // Return the average
    } else
        printf("\rAccess qscore out of bound!");
    return(0); //dummy quality score
}

// return sum of the quality score for mismatched bases.
int alignmentScore(char* str1, char* str2, unsigned int readLength, const char* sc);
double getAverageQualityScores(CReadsQualScores& Qscores);

// preint comma separate scores string on qScoresStr
void printCommaSepScoresStr(unsigned int readlength, const char* qScores, char* qScoresStr);


