/*
 * SimpleFMIndexConstructTest.cpp
 *
 *  Created on: 21. 02. 2021
 *      Author: Martin Prokopic
 */

#include <catch2/catch.hpp>

#include <string/String.h>
#include <string/LinearStringTerminatingSymbolBWT.h>
#include <stringology/indexing/SimpleFMIndexConstruct.h>

using string::LinearString;
using string::LinearStringTerminatingSymbolBWT;
using stringology::indexing::BWTAuxiliaryDataConstruct;
using indexes::stringology::BWTAuxiliaryDataType;
using stringology::indexing::SimpleFMIndexConstruct;

TEST_CASE ( "Simple FM Index Construct", "[unit][stringology][indexing][fmindex]" ) {
    SECTION ( "occurrence arrays and buckets" ) {
        LinearStringTerminatingSymbolBWT < char > input ( '$', string::stringFrom ( "banana$" ));
        auto index = SimpleFMIndexConstruct::construct ( input, 4, 2, 0 );

        REQUIRE ( index.getSuperBucketSize ( ) == 4 );
        REQUIRE ( index.getBucketSize ( ) == 2 );

        REQUIRE ( index.getKOcc ( ) == ext::map < char, unsigned >{
                { '$', 1 },
                { 'a', 3 },
                { 'b', 1 },
                { 'n', 2 },
        } );
        REQUIRE( index.getMOccPrefixSum ( ) == ext::map < char, unsigned >{
                { '$', 0 },
                { 'a', 1 },
                { 'b', 4 },
                { 'n', 5 },
        } );

        auto superBucketOcc = index.getSuperBucketOcc ( );
        INFO( superBucketOcc ); // bana na$
        REQUIRE ( superBucketOcc.size ( ) == 2 );
        REQUIRE ( superBucketOcc[ 0 ] == ext::map < char, unsigned > ( ));
        REQUIRE ( superBucketOcc[ 1 ] == ext::map < char, unsigned >{
                { 'a', 2 },
                { 'b', 1 },
                { 'n', 1 }
        } );

        auto bucketOcc = index.getBucketOcc ( );
        INFO( bucketOcc ); // ba na | na $
        REQUIRE ( bucketOcc.size ( ) == 4 );
        REQUIRE ( bucketOcc[ 0 ] == ext::map < char, unsigned > ( ));
        REQUIRE ( bucketOcc[ 1 ] == ext::map < char, unsigned >{
                { 'a', 1 },
                { 'b', 1 }
        } );
        REQUIRE ( bucketOcc[ 2 ] == ext::map < char, unsigned > ( ));
        REQUIRE ( bucketOcc[ 3 ] == ext::map < char, unsigned >{
                { 'a', 1 },
                { 'n', 1 }
        } );
    }

    SECTION ( "marks and sparseFirstToText" ) {
        LinearStringTerminatingSymbolBWT < char > input ( '$', string::stringFrom ( "aaabbbb$" ));

        auto data = BWTAuxiliaryDataConstruct::construct ( input, BWTAuxiliaryDataType::M_OCC_PREFIX_SUM );
        data.setIFirstToText ( ext::vector < unsigned >{ 100, 101, 102, 103, 104, 105, 106, 107 } );
        data.setDataTypePresent ( BWTAuxiliaryDataType::I_FIRST_TO_TEXT );

        auto index = SimpleFMIndexConstruct::construct ( input, 4, 2, 50, data );

        REQUIRE( index.getMarkedSymbol ( ) == 'b' );
        REQUIRE( index.getSparseFirstToText ( ) == ext::vector < unsigned >{ 103, 104, 105, 106 } );
    }

    SECTION ( "checks bucket sizes & ftt" ) {
        LinearStringTerminatingSymbolBWT < char > input ( '$', string::stringFrom ( "banana$" ));

        REQUIRE_THROWS_AS( SimpleFMIndexConstruct::construct ( input, 100, 0, 1 ), exception::CommonException );
        REQUIRE_THROWS_AS( SimpleFMIndexConstruct::construct ( input, 2, 4, 1 ), exception::CommonException );
        REQUIRE_THROWS_AS( SimpleFMIndexConstruct::construct ( input, 5, 4, 1 ), exception::CommonException );
        REQUIRE_THROWS_AS( SimpleFMIndexConstruct::construct ( input, 4, 2, 101 ), exception::CommonException );
    }

    SECTION ( "checks if auxiliary data is valid" ) {
        LinearStringTerminatingSymbolBWT < char > input ( '$', string::stringFrom ( "banana$" ));

        auto data = BWTAuxiliaryDataConstruct::construct ( input, BWTAuxiliaryDataType::M_OCC_PREFIX_SUM );
        REQUIRE_THROWS_AS( SimpleFMIndexConstruct::construct ( input, 4, 2, 1, data ), exception::CommonException );

        auto data2 = BWTAuxiliaryDataConstruct::construct ( input, 0 );
        REQUIRE_THROWS_AS( SimpleFMIndexConstruct::construct ( input, 4, 2, 0, data2 ), exception::CommonException );
    }

    SECTION ( "superBucket same size as bucket" ) {
        LinearStringTerminatingSymbolBWT < char > input ( '$', string::stringFrom ( "banana$" ));
        auto index = SimpleFMIndexConstruct::construct ( input, 2, 2, 0 );

        REQUIRE ( index.getSuperBucketSize ( ) == 2 );
        REQUIRE ( index.getBucketSize ( ) == 2 );
    }

}
