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

#ifndef BIT_PARALLELISM_FACTORS_H_
#define BIT_PARALLELISM_FACTORS_H_

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

#include <alib/foreach>

namespace stringology {

namespace query {

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

class BitParallelismFactors {
public:
	/**
	 * Query a suffix trie
	 * @param suffix trie to query
	 * @param string string to query by
	 * @return occurences of factors
	 */
	template < class SymbolType >
	static ext::set < unsigned > query ( const indexes::stringology::BitParallelIndex < SymbolType > & bitParallelIndex, const string::LinearString < SymbolType > & string );

};

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

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

	auto symbolIter = string.getContent ( ).begin ( );
	typename ext::map < SymbolType, ext::vector < bool > >::const_iterator symbolVectorIter = bitParallelIndex.getData ( ).find ( * symbolIter );
	if ( symbolVectorIter == bitParallelIndex.getData ( ).end ( ) )
		return { };

	ext::vector < bool > indexVector = symbolVectorIter->second;

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

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

	ext::set < unsigned > res;
	for ( unsigned i = 0; i < indexVector.size ( ); i++ )
		if ( indexVector [ i ] )
			res.insert ( i - string.getContent ( ).size ( ) + 1 );

	return res;
}

} /* namespace query */

} /* namespace stringology */

#endif /* BIT_PARALLELISM_FACTORS_H_ */
