// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//

#ifndef BALL_STRUCTURE_STRUCTUREMAPPER_H
#define BALL_STRUCTURE_STRUCTUREMAPPER_H

#ifndef BALL_COMMON_H
#	include <BALL/common.h>
#endif

#ifndef BALL_CONCEPT_PROCESSOR_H
#	include <BALL/CONCEPT/processor.h>
#endif

#ifndef BALL_STRUCTURE_GEOMETRICTRANSFORMATIONS_H
#	include <BALL/STRUCTURE/geometricTransformations.h>
#endif

#ifndef BALL_DATATYPE_STRING_H
#	include <BALL/DATATYPE/string.h>
#endif

#ifndef BALL_KERNEL_PROTEIN_H
#	include <BALL/KERNEL/protein.h>
#endif

#ifndef BALL_KERNEL_ATOM_H
#	include <BALL/KERNEL/atom.h>
#endif

#ifndef BALL_MATHS_MATRIX44_H
#	include <BALL/MATHS/matrix44.h>
#endif

#ifndef BALL_STRUCTURE_ATOMBIJECTION_H
#	include <BALL/STRUCTURE/atomBijection.h>
#endif

#include <vector>
#include <map>

namespace BALL 
{

	/**	Structure mapping class.
	\ingroup StructureMapping
	*/
	class BALL_EXPORT StructureMapper
		:	public TransformationProcessor
	{
		public:

		/**	@name	Constructors and Destructors
		*/
		//@{
		
		/**	Default constructor
		*/
		StructureMapper();

		/**	Constructor
		*/
		StructureMapper(AtomContainer& A, AtomContainer& B);

		/**	Destructor
		*/
		virtual ~StructureMapper();

		//@}

		/**	Assign the two objects to be mapped
		*/
		void set(AtomContainer& A, AtomContainer& B);

		/**	Calculate the root mean squared deviation
		*/
		double calculateRMSD();

		/**	Calculate the root mean squared deviation given a AtomBijection
		*/
		double calculateRMSD(const AtomBijection& new_bijection);

		/**	Calculate the transformation to map the first of two isomorphous 
				AtomContainer objects onto the second
		*/
		bool calculateTransformation();

		/**	Calculate a reasonable bijection for the mapping of A and B
		*/
		void calculateDefaultBijection(bool limit_to_selection = false);

		/**	Return the current bijection
		*/
		const AtomBijection& getBijection() const { return bijection_; }

		/**	Calculates a bijection to map two arrays of fragments onto each other.
		*/
		AtomBijection calculateFragmentBijection
			(const vector<Fragment*>& A, const vector<Fragment*>& B);

		/**	Maps two fragments onto each other
		*/
		bool mapFragments
			(const vector<Fragment*>& A, const vector<Fragment*>& B,
			 Matrix4x4* transformation, double upper_bound = 8.0, double lower_bound = 2.5);

		/**	Map three points onto each other.
				Computes a transformation that maps

					- the point <tt>w1</tt> onto the point <tt>v1</tt>,
					- the point <tt>w2</tt> onto the ray that starts in <tt>v1</tt> and goes through <tt>v2</tt>,
					- the point <tt>w3</tt> into the plane generated by <tt>v1</tt>, <tt>v2</tt>, and <tt> v3</tt>.
				
		*/
		static Matrix4x4 matchPoints
			(const Vector3& w1,	const Vector3& w2, const Vector3& w3,	
			 const Vector3& v1,	const Vector3& v2, const Vector3& v3);

		/**	
		*/
		static Matrix4x4 matchBackboneAtoms(const Residue& r1, const Residue& r2);

		/**	
		*/
		Size mapResiduesByBackbone(const list<Residue*>& l1, const list<Residue*>& l2);
	 
		/**
		*/
		vector<vector<Fragment*> >& searchPattern
			(vector<Fragment*>& pattern, AtomContainer& composite,
			 double max_rmsd = 4.0,	   double max_center_tolerance = 2.0,
			 double upper_bound = 8.0, double lower_bound = 4.0);

		/**	Map two proteins onto each other.
		*/
		Matrix4x4 mapProteins
			(Protein& P1, Protein& P2, 
			 std::map<String, Size>&	type_map,
			 Size&							no_matched_ca,
			 double&						rmsd,
			 double							upper_bound = 8.0,
			 double							lower_bound = 4.0,
			 double							tolerance = 0.6);

		protected:
		// Count the fragments in an AtomContainer -- this is not implemented
		// in AtomContainer!
		Size countFragments_(const AtomContainer& ac) const;

		/*_	The first of two composites - the "original" 
		*/
		AtomContainer*	A_;

		/*_	The second composites - the "copy" to be mapped 
		*/
		AtomContainer*	B_;
		
		/*_	The current atom bijection.
				Required for the caclulation of the RMSD.
		*/
		AtomBijection bijection_;
		
		/*_	The rmsd of the last mapping executed 
		*/
		double	rmsd_;
	};

} // namespace BALL

#endif // BALL_STRUCTURE_STRUCTUREMAPPER_H

