
#ifndef INTARNA_PREDICTORMFE2DSEEDEXTENSIONRIBLAST_H_
#define INTARNA_PREDICTORMFE2DSEEDEXTENSIONRIBLAST_H_

#include "IntaRNA/PredictorMfe2d.h"
#include "IntaRNA/SeedHandlerIdxOffset.h"

namespace IntaRNA {

/**
 * Implements seed-based space-efficient interaction prediction following the
 * ideas introduced for the RIblast approach
 * (doi: 10.1093/bioinformatics/btx287).
 *
 * Note, for each seed start (i1,i2) only the mfe seed is considered for the
 * overall interaction computation instead of considering all possible seeds
 * starting at (i1,i2).
 *
 * @author Frank Gelhausen
 * @author Martin Raden
 *
 */
class PredictorMfe2dSeedExtensionRIblast: public PredictorMfe2d {

protected:

	//! matrix type to hold the mfe energies for interaction site starts
	typedef PredictorMfe2d::E2dMatrix E2dMatrix;

public:

	struct ExtendedSeed {
		size_t i1;
		size_t j1;
		size_t i2;
		size_t j2;
		E_type energy;
	};

	const int parallelDropOutLength = 5;
	const int thoroughDropOutLength = 16;

	/**
	 * Constructs a predictor and stores the energy and output handler
	 *
	 * @param energy the interaction energy handler
	 * @param output the output handler to report mfe interactions to
	 * @param predTracker the prediction tracker to be used or NULL if no
	 *         tracking is to be done; if non-NULL, the tracker gets deleted
	 *         on this->destruction.
	 * @param seedHandler the seed handler to be used
	 */
	PredictorMfe2dSeedExtensionRIblast(
			const InteractionEnergy & energy
			, OutputHandler & output
			, PredictionTracker * predTracker
			, SeedHandler * seedHandler );


	/**
	 * data cleanup
	 */
	virtual ~PredictorMfe2dSeedExtensionRIblast();


	/**
	 * Computes the mfe for the given sequence ranges (i1-j1) in the first
	 * sequence and (i2-j2) in the second sequence and reports it to the output
	 * handler.
	 *
	 * Each considered interaction contains a seed according to the seed handler
	 * constraints.
	 *
	 * @param r1 the index range of the first sequence interacting with r2
	 * @param r2 the index range of the second sequence interacting with r1
	 *
	 */
	virtual
	void
	predict( const IndexRange & r1 = IndexRange(0,RnaSequence::lastPos)
			, const IndexRange & r2 = IndexRange(0,RnaSequence::lastPos) );


protected:


	//! access to the interaction energy handler of the super class
	using PredictorMfe2d::energy;

	//! access to the output handler of the super class
	using PredictorMfe2d::output;

	//! the seed handler (with idx offset)
	SeedHandlerIdxOffset seedHandler;

	//! energy of all interaction hybrids that start on the left side of the seed
	E2dMatrix hybridE_left;

	//! energy of all interaction hybrids that start on the right side of the seed
	E2dMatrix hybridE_right;

protected:

	/**
	 * linearly extends given seed to left and right until energy stops improving
	 *
	 * @param seed
	 * @param max_extension1
	 * @param max_extension2
	 */
	virtual
	void
	parallelExtension( ExtendedSeed & seed, const size_t max_extension1, size_t max_extension2 );

	/**
	 * Computes all entries of the hybridE matrix for interactions starting in
	 * i1 and i2 and report all valid interactions to updateOptima()
	 *
	 * @param j1 start of the interaction within seq 1
	 * @param j2 start of the interaction within seq 2
	 *
	 */
	void
	fillHybridE_left( const size_t j1, const size_t j2 );

	/**
	 * Computes all entries of the hybridE matrix for interactions starting in
	 * i1 and i2 and report all valid interactions to updateOptima()
	 *
	 * @param i1 end of the interaction within seq 1
	 * @param i2 end of the interaction within seq 2
	 *
	 */
	void
	fillHybridE_right( const size_t i1, const size_t i2 );

	/**
	 * Fills a given interaction (boundaries given) with the according
	 * hybridizing base pairs using hybridE_seed.
	 * @param interaction IN/OUT the interaction to fill
	 */
	virtual
	void
	traceBack( Interaction & interaction );

	void
	printMatrix( const E2dMatrix & matrix );

};

//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////

inline
void
PredictorMfe2dSeedExtensionRIblast::
printMatrix( const E2dMatrix & matrix )
{
	for (int i = 0; i < matrix.size1(); i++) {
		std::cout << "| ";
		for (int j = 0; j < matrix.size2(); j++) {
			std::cout << matrix(i, j) << " | ";
		}
		std::cout << std::endl;
	}
}

} // namespace

#endif /* INTARNA_PREDICTORMFE2DSEEDEXTENSIONRIBLAST_H_ */
