#ifndef _BLASR_ALIGNMENT_UTILS_HPP_
#define _BLASR_ALIGNMENT_UTILS_HPP_

#include <string>

#include <alignment/algorithms/alignment/DistanceMatrixScoreFunction.hpp>
#include <alignment/datastructures/alignment/Alignment.hpp>
#include <pbdata/DNASequence.hpp>

enum AlignmentType
{
    Local,      // Standard Smith-Waterman
    Global,     // Standard Needleman-Wuncsh
    QueryFit,   // No gap penalties from query.
    TargetFit,  // For when the query engulfs the target.
    Overlap,    // No gap penalty at the beginning of
    // query, nor at the end of text **
    // not yet implemented for k-band **,
    FrontAnchored,  // Require the alignment to align
    // pos 0,0 in the matrix
    EndAnchored,  // Require the alignment to align
    // the pos m,n in the matrix
    // Score alignment types solely compute the score
    // of an alignment and do not store the actual
    // alignment itself.  This is fast for filtering
    // potential alignments that may be re-aligned
    // later to store the actual alignment.
    Fit,             // No gap penalties at the beginning nor ends of alignments.
    TSuffixQPrefix,  // Same as overlap
    TPrefixQSuffix,  // so that the order of the alignment does not have to be reversed
    ScoreGlobal,
    ScoreLocal,
    ScoreQueryFit,
    ScoreTargetFit,
    ScoreOverlap,
    ScoreFrontAnchored,
    ScoreEndAnchored,
    ScoreTSuffixQPrefix,
    ScoreTPrefixQSuffix,
    //
    // A LocalBoundaries alignment is in-between a
    // score-only and full-alignment. The full path
    // matrix is computed, but rather
    // than computing an alignment, simply the
    // (qStart, qLength), (tStart, tLength)
    // coordinates of the alignment are returned.
    //
    LocalBoundaries,
    //
    // A SignificanceLimited alignment is a banded
    // alignment that continues alignment until the
    // score drops below a certain threshold below
    // the maximum score.
    //
    SignificanceLimited
};

inline int ComputeAlignmentScore(std::string &queryStr, std::string &textStr, int matchScores[5][5],
                                 int ins, int del);

template <typename T_ScoreFn>
inline int ComputeAlignmentScore(std::string &queryStr, std::string &textStr, T_ScoreFn &scoreFn,
                                 bool useAffineScore = false);

template <typename T_QuerySequence, typename T_TargetSequence, typename T_ScoreFn>
int ComputeAlignmentScore(blasr::Alignment &alignment, T_QuerySequence &query,
                          T_TargetSequence &text, T_ScoreFn &scoreFn,
                          bool useAffinePenalty = false);

template <typename T_QuerySequence, typename T_TargetSequence>
int ComputeAlignmentScore(blasr::Alignment &alignment, T_QuerySequence &query,
                          T_TargetSequence &text, int matchScores[5][5], int ins, int del);

int GetNumberWidth(unsigned int value);

template <typename T_Alignment>
inline void PrintCompareSequencesAlignmentStats(T_Alignment &alignment, std::ostream &out);

template <typename T_Alignment>
inline int ReadCompareSequencesAlignmentStats(std::istream &in, T_Alignment &alignment);

template <typename T_Alignment>
inline int ReadCompSeqAlignment(std::istream &in, T_Alignment &alignment);

/*
 * This should be changed to read any type of alignment, since templates are being
 * used.
 */
inline void ReadCompSeqAlignments(std::string &compSeqAlignmentFileName,
                                  std::vector<blasr::CompSeqAlignment> &alignments);

inline void PrintAlignmentStats(blasr::Alignment &alignment, std::ostream &out);

template <typename T_QuerySequence, typename T_TargetSequence>
void AppendGapCharacters(blasr::Gap &gap, T_QuerySequence &query, T_TargetSequence &text,
                         DNALength &q, DNALength &t, char mismatchChar, char gapChar,
                         std::string &textStr, std::string &alignStr, std::string &queryStr);

template <typename T_Alignment, typename T_QuerySequence, typename T_TargetSequence>
void CreateAlignmentStrings(T_Alignment &alignment, T_QuerySequence &query, T_TargetSequence &text,
                            std::string &textStr, std::string &alignStr, std::string &queryStr,
                            DNALength queryLength = 0, DNALength textLength = 0);

template <typename T_Alignment, typename T_ScoreFn>
void ComputeAlignmentStats(T_Alignment &alignment, Nucleotide *qSeq, Nucleotide *tSeq,
                           T_ScoreFn &scoreFn, bool useAffineScore = false);

template <typename T_Alignment>
void ComputeAlignmentStats(T_Alignment &alignment, Nucleotide *qSeq, Nucleotide *tSeq,
                           int matchMatrix[5][5], int ins, int del);

template <typename T_Alignment>
int ComputeDrift(T_Alignment &alignment);

int ComputeDrift(blasr::Block &cur, blasr::Block &next);

template <typename T_Alignment>
void RemoveAlignmentPrefixGaps(T_Alignment &alignment);

// QVsToCmpH5QVs converts the optional QVs read from a SAM file into something
// that's ready to be written to the HDFArrays of a cmp.h5 file. This involves
// two things: First, it needs to be converted from a std::string to a vector
// of either chars or UChars. Second, it needs to have appropriate gap
// characters inserted. The location of gaps if found using the byteAlignment.
template <typename T>
void QVsToCmpH5QVs(const std::string &fieldName, const std::string &qvs,
                   const std::vector<unsigned char> &byteAlignment, bool isTag,
                   std::vector<T> *gappedQVs);

#include "AlignmentUtilsImpl.hpp"

#endif  // _BLASR_ALIGNMENT_UTILS_HPP_
