/*
 * CompressedBitParallelismFactors.h
 *
 *  Created on: 2. 1. 2017
 *      Author: Jan Travnicek
 */

#pragma once

#include <indexes/stringology/CompressedBitParallelIndex.h>
#include <string/LinearString.h>
#include <global/GlobalData.h>

#include <alib/foreach>

namespace stringology {

namespace query {

/**
 * Query compressed bit parallel index for given string.
 *
 */

class CompressedBitParallelismFactors {

public:
	/**
	 * Query a compressed bit parallel index
	 * @param compressedBitParallelIndex the index to query
	 * @param string the string to query with
	 * @return occurences of factors
	 */
	template < class SymbolType >
	static ext::set < unsigned > query ( const indexes::stringology::CompressedBitParallelIndex < SymbolType > & compressedBitParallelIndex, const string::LinearString < SymbolType > & string );
};

template < class SymbolType >
ext::set < unsigned > CompressedBitParallelismFactors::query ( const indexes::stringology::CompressedBitParallelIndex < SymbolType > & compressedBitParallelIndex, const string::LinearString < SymbolType > & string ) {
	if ( string.getContent ( ).empty ( ) ) {
		if ( compressedBitParallelIndex.getData ( ).begin ( ) == compressedBitParallelIndex.getData ( ).end ( ) )
			return { };

		return { ext::sequence < unsigned > ( 0 ).begin ( ), ext::sequence < unsigned > ( compressedBitParallelIndex.getData ( ).begin ( )->second.size ( ) ).end ( ) };
	}

	auto symbolIter = string.getContent ( ).begin ( );
	typename ext::map < SymbolType, common::SparseBoolVector >::const_iterator symbolVectorIter = compressedBitParallelIndex.getData ( ).find ( * symbolIter );

	if ( symbolVectorIter == compressedBitParallelIndex.getData ( ).end ( ) )
		return { };

	common::SparseBoolVector indexVector = symbolVectorIter->second;

	for ( ++ symbolIter; symbolIter != string.getContent ( ).end ( ); ++ symbolIter ) {
		symbolVectorIter = compressedBitParallelIndex.getData ( ).find ( * symbolIter );
		if ( symbolVectorIter == compressedBitParallelIndex.getData ( ).end ( ) )
			return { };

		indexVector = ( indexVector << 1 ) & symbolVectorIter->second;
	}

	ext::set < unsigned > res;

	for ( unsigned i : indexVector )
		res.insert ( i - string.getContent ( ).size ( ) + 1 );

	return res;
}

} /* namespace query */

} /* namespace stringology */

