/*
 * SuffixArrayFactors.h
 *
 *  Created on: 10. 1. 2017
 *      Author: Jan Travnicek
 */

#ifndef SUFFIX_ARRAY_FACTORS_H_
#define SUFFIX_ARRAY_FACTORS_H_

#include <indexes/stringology/SuffixArray.h>
#include <string/LinearString.h>
#include <alib/algorithm>

namespace stringology {

namespace query {

/**
 * Query suffix trie for given string.
 *
 * Source: ??
 */

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

};

template < class SymbolType >
ext::set < unsigned > SuffixArrayFactors::query ( const indexes::stringology::SuffixArray < SymbolType > & suffixArray, const string::LinearString < SymbolType > & string ) {

	auto comparator = [ & ] ( const ext::vector < SymbolType > & first, unsigned firstIndex, const ext::vector < SymbolType > & second, unsigned secondIndex, unsigned limit ) -> int {
			static ext::compare < SymbolType > comp;

			for ( ; firstIndex < first.size ( ) && secondIndex < second.size ( ) && limit > 0; ++ firstIndex, ++ secondIndex, --limit ) {
				int res = comp ( first [ firstIndex ], second [ secondIndex ] );

				if ( res != 0 )
					return res;
			}

			if ( limit == 0 )
				return 0;

			return ( first.size ( ) - firstIndex ) - ( second.size ( ) - secondIndex );
	};

	// The value returned by comparator indicates whether the first argument is considered to go before the second.
	ext::vector < unsigned >::const_iterator low = std::lower_bound ( suffixArray.getData ( ).begin ( ), suffixArray.getData ( ).end ( ), string, [ & ] ( unsigned first, const string::LinearString < SymbolType > & str ) {
			return comparator ( suffixArray.getString ( ).getContent ( ), first, str.getContent ( ), 0, str.getContent ( ).size ( ) ) < 0;
	} );

	// The value returned by comparator indicates whether the first argument is considered to go before the second.
	ext::vector < unsigned >::const_iterator high = std::upper_bound ( suffixArray.getData ( ).begin ( ), suffixArray.getData ( ).end ( ), string, [ & ] ( const string::LinearString < SymbolType > & str, unsigned second ) {
			return comparator ( str.getContent ( ), 0, suffixArray.getString ( ).getContent ( ), second, str.getContent ( ).size ( ) ) < 0;
	} );

	return ext::set < unsigned > ( low, high );
}

} /* namespace query */

} /* namespace stringology */

#endif /* SUFFIX_ARRAY_FACTORS_H_ */
