#ifndef __ParticleAttribute_H
#define __ParticleAttribute_H

template <class AttributeT, class Func>
/* 
CLASS
  ParticleAttribute
  
  This is a template base class for all the the scoring mechanisms we need on
  various issues of docking or matching schemes.
  

KEYWORDS
  attribute, function, apply operator, similarity/difference, measure

AUTHORS
  Zipi Fligelman (zipo@math.tau.ac.il)

CHANGES LOG
<UL>
<LI>
</UL>

GOALS
  This class defines the attribute that the  function (applicator)
  is measuring what ever you want it to measure between the two attributes.
  You can make the measuring function a simple distance between two vectors, or
  a PAM matrix that measures changes in the protein string etc. 
  This allows you to construct small class that measure similarity between
  objects, difference between objects and so forth
  When creating the appropriate function one must declare only the 
  operator()(const T& val1, const T& val2) that operate as you wish. 
  If your function class has data members you must have an empty and
  a copy constructor in order to initiate a template instantiation.
  

USAGE 
  The usage of the class is quite simple, here is an example of using it to 
  measure various Euclidean measures, and a physical one:
  
  File: "Euclidean .h"
  EXAMPLE
  #include <Vector3.h>
  class VectorDist {
  public:
     float operator()(const Vector3& vec1, const Vector3& vec2) {
     return vec1.dist(vec2);
  };
  
  class VectorProd {
  public:   
     float operator()(const Vector3& vec1, const Vector3& vec2) {
     return vec1*vec2;
  }; 
  
  class  VecSumNorm {
  public:
     float operator()(const Vector3& vec1, const Vector3& vec2) {
     return vec1.norm()+vec2.norm();
  }
  
  class VecSubNorm  {
  public: 
     float operator()(const Vector3& vec1, const Vecotr3& vec2) {
     return vec1.norm()-vec2.norm();
  }
  #endif
  END
  Now anytime you want to measure things on vector all you need to do is:
  EXAMPLE
  #include "ParticleAttribute.h"
  #include "Euclidean.h"
  #include "Vector3.h"
  #include <vector>
  void do_staff_function() {
  ParticleAttribute<Vecotr3, VecSubNorm> diff_in_norm;
  ParticleAttribute<Vector3, VecProduct> prod_vec;
  vector<Vector3> my_vec;
  END 
  
  .... here come a part where you enter info to your vector.
  
  .... Now you want to know the difference in norm and the dot product
  between element i and element j
  
  EXAMPLE
   diff_in_norm(elem_i, elem_j);
   prod_vec(elem_i, elem_j);
  END
  
  Now lets assume we have a particle class that hold mass information 
  and location, and we can get it from the class.
  We want to compute their gravitational attraction according to Newton:
  
  EXAMPLE 
  #include "macros.h"
  #include "ParticleAttribute.h"
  class GravNewt {
  public: 
     operator()(const MassParticle& pr1, const MassParticle& pr2) {
     const float G=6.67e-11;
     return (G*pr1.mass()*pr2.mass()
             / sqr(pr1.location().dist(pr2.location())));
  };
  END
  Assuming we measure the planets place in distance from sun, and of
  a star in the milky way in the distance from the center of the galaxy.
  EXAMPLE
  void GravOfSun(const MassParticle& planet_in_solar_system,
                  const MassParticle& star_in_milky_way) 
  {
    MassParticle Sun(mass_of_sun, Vector3(0,0,0));
    ParticleAttribute<MassParticle, GravNewt> gravity;
    
    cout << "The gravity influence of the sun on a planet in the solar " 
         <<" system is " 
         << gravity(Sun,planet_in_solar_system) << endl;
    
    cout << "The gravity influence of the sun on a star in the"
         << " milky way  is " 
         << gravity(MassParticle(mass_of_sun, dist_of_sun_from_mid_galaxy),
                    star_in_milky_way) 
         << endl;
  END
  
  Copyright: SAMBA group, Tel-Aviv Univ. ISRAEL, 1998.
*/
class ParticleAttribute
{
public:
  //// GROUP: Constructors
  //// empty constructor for future usage with the STL vector constructor
  ParticleAttribute();
  
  //// The regular constructor make sure that AttributeT and Func has
  // copy constructor
  ParticleAttribute(const Func& func);
    
  //// Copy constructor again for vector utils
  ParticleAttribute(const ParticleAttribute& par);
  
  // GROUP: Info and updates 

  //// Returns the measuring function
  Func measure() const
  {
    return fmeasure;
  }
  //// Updating the measuring function
  void updateMeasureFunc(const Func& new_measure);

  // GROUP: Operators

  //// The applying operator.
  float operator()(const AttributeT& att1, const AttributeT& att2);
  
  //// Equivalence measure gives a boolean answer whether the attributes
  //   are the same in a "lexicographic manner" i.e if the attributes aren't
  //   identical it returns false if they are it checks if the
  //   measure functions associated with them is  
  bool operator==(const ParticleAttribute& att);
private:
  Func fmeasure; // the f says its a function (like pnext to indicate pointer)
  
};

template<class AttributeT,class Func>
ParticleAttribute<AttributeT, Func>::ParticleAttribute()
  : fmeasure()
{}

template <class AttributeT,class Func>
ParticleAttribute<AttributeT, Func>::ParticleAttribute(const Func& func) 
  : fmeasure(func)

{}



template <class AttributeT,class Func>
ParticleAttribute<AttributeT, Func>::ParticleAttribute(const ParticleAttribute& par) 
  : fmeasure(par.measure())
{}
  

template <class AttributeT, class Func>
void ParticleAttribute<AttributeT, Func>::updateMeasureFunc(const Func& new_measure)
{
  //  ~fmeasure(); // make sure there are no memory leaks
  fmeasure=new_measure;
}

template <class AttributeT, class Func>
float ParticleAttribute<AttributeT, Func>::operator()(const AttributeT& att1, const AttributeT& att2)
{
  return fmeasure(att1, att2);
}

/*-------------------------------------------------------------------------
  if the attributes aren't the same we return false
  if they are we only return true if the similarity
  measure and the difference mesures are the same
---------------------------------------------------------------------------*/
template <class AttributeT, class Func>
bool ParticleAttribute<AttributeT, Func>::operator==(const  ParticleAttribute& att)
{
  return (fmeasure()==att.measure());
}

#endif 














