/*
 * BWTAuxiliaryData.h
 *
 *  Created on: 13. 02. 2021
 *      Author: Martin Prokopic
 */

#pragma once

#include <alib/vector>
#include <alib/map>
#include <alib/set>
#include <alphabet/common/SymbolCompare.h>

namespace indexes {

namespace stringology {

enum BWTAuxiliaryDataType {
    M_OCC_PREFIX_SUM = 1,
    V_REVERSE_DECODE = 2,
    W_FORWARD_DECODE = 4,
    HR_TEXT_TO_FIRST = 8,
    I_FIRST_TO_TEXT = 16,
    ALL = 255
};

template < class SymbolType = DefaultSymbolType >
class BWTAuxiliaryData {
    /** bitmask of present data types */
    unsigned m_dataTypeBitmask = 0;

    /** alphabet in the correct order (terminating symbol is first) */
    ext::set < SymbolType, alphabet::SymbolCompare < SymbolType > > m_orderedAlphabet;
    /** index of terminating symbol in encoded string */
    unsigned m_terminatingSymbolIndex;

    // counting arrays
    /** # of occurrences of str[i] in str[0..i-1] */
    ext::vector < unsigned > m_cPrefixOcc;
    /** # of occurrences of \sigma_i in text */
    ext::map < SymbolType, unsigned > m_kOcc;
    /** prefix sum of m_kOcc, m_mOccPrefixSum[i] = m_kOcc[0] + ... + m_kOcc[i-1], m_mOccPrefixSum[0] = 0 */
    ext::map < SymbolType, unsigned > m_mOccPrefixSum;

    // decoding arrays
    /** steps through the encoded string in reverse direction */
    ext::vector < unsigned > m_vReverseDecode;
    /** steps through the encoded string in forward direction */
    ext::vector < unsigned > m_wForwardDecode;

    // random access maps
    /** maps indices in original text to indices in transformed text */
    ext::vector < unsigned > m_hrTextToFirst;
    /** maps indices in transformed text to indices in original text */
    ext::vector < unsigned > m_iFirstToText;

public:
    unsigned getDataTypeBitmask ( ) const {
        return m_dataTypeBitmask;
    }

    void setDataTypeBitmask ( unsigned dataTypeBitmask ) {
        m_dataTypeBitmask = dataTypeBitmask;
    }

    bool isDataTypePresent ( BWTAuxiliaryDataType type ) const {
        return m_dataTypeBitmask & type;
    }

    void setDataTypePresent ( BWTAuxiliaryDataType type ) {
        m_dataTypeBitmask |= type;
    }

    const ext::set < SymbolType, alphabet::SymbolCompare < SymbolType > > & getOrderedAlphabet ( ) const {
        return m_orderedAlphabet;
    }

    void
    setOrderedAlphabet ( const ext::set < SymbolType, alphabet::SymbolCompare < SymbolType > > & orderedAlphabet ) {
        m_orderedAlphabet = orderedAlphabet;
    }

    unsigned getTerminatingSymbolIndex ( ) const {
        return m_terminatingSymbolIndex;
    }

    void setTerminatingSymbolIndex ( unsigned terminatingSymbolIndex ) {
        m_terminatingSymbolIndex = terminatingSymbolIndex;
    }

    const ext::vector < unsigned > & getCPrefixOcc ( ) const {
        return m_cPrefixOcc;
    }

    void setCPrefixOcc ( const ext::vector < unsigned > & cPrefixOcc ) {
        m_cPrefixOcc = cPrefixOcc;
    }

    const ext::map < SymbolType, unsigned > & getKOcc ( ) const {
        return m_kOcc;
    }

    void setKOcc ( const ext::map < SymbolType, unsigned > & kOcc ) {
        m_kOcc = kOcc;
    }

    const ext::map < SymbolType, unsigned > & getMOccPrefixSum ( ) const {
        return m_mOccPrefixSum;
    }

    void setMOccPrefixSum ( const ext::map < SymbolType, unsigned > & mOccPrefixSum ) {
        m_mOccPrefixSum = mOccPrefixSum;
    }

    const ext::vector < unsigned > & getVReverseDecode ( ) const {
        return m_vReverseDecode;
    }

    void setVReverseDecode ( const ext::vector < unsigned > & vReverseDecode ) {
        m_vReverseDecode = vReverseDecode;
    }

    const ext::vector < unsigned > & getWForwardDecode ( ) const {
        return m_wForwardDecode;
    }

    void setWForwardDecode ( const ext::vector < unsigned > & wForwardDecode ) {
        m_wForwardDecode = wForwardDecode;
    }

    const ext::vector < unsigned > & getHrTextToFirst ( ) const {
        return m_hrTextToFirst;
    }

    void setHrTextToFirst ( const ext::vector < unsigned > hrTextToFirst ) {
        m_hrTextToFirst = hrTextToFirst;
    }

    const ext::vector < unsigned > & getIFirstToText ( ) const {
        return m_iFirstToText;
    }

    void setIFirstToText ( const ext::vector < unsigned > iFirstToText ) {
        m_iFirstToText = iFirstToText;
    }

    friend std::ostream & operator << ( std::ostream & out, const BWTAuxiliaryData & instance ) {
        out << "(BWTAuxiliaryData";
        out << " DataTypeBitmask = " << instance.m_dataTypeBitmask;
        out << " OrderedAlphabet = " << instance.m_orderedAlphabet;
        out << " TerminatingSymbolIndex = " << instance.m_terminatingSymbolIndex;
        out << " CPrefixOcc = " << instance.m_cPrefixOcc;
        out << " KOcc = " << instance.m_kOcc;
        out << " MOccPrefixSum = " << instance.m_mOccPrefixSum;
        out << " VReverseDecode = " << instance.m_vReverseDecode;
        out << " WForwardDecode = " << instance.m_wForwardDecode;
        out << " HrTextToFirst = " << instance.m_hrTextToFirst;
        out << " IFirstToText = " << instance.m_iFirstToText;
        out << ")";
        return out;
    }

    auto operator <=> ( const BWTAuxiliaryData & other ) const = default;

    bool operator == ( const BWTAuxiliaryData & other ) const = default;

    explicit operator std::string ( ) const;
};

template < class SymbolType >
BWTAuxiliaryData < SymbolType >::operator std::string ( ) const {
    std::stringstream ss;
    ss << *this;
    return ss.str ( );
}

} /* stringology */

} /* indexes */



