/**
 * @file
 * $Id$
 * $Revision$
 * $Author$
 * $Date$
 *
 * This file is part of The iWear Framework.
 *
 * The iWear Framework is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by the
 * Free Software Foundation as in version 2 of the License.

 * 
 * The iWear Framework is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * The iWear Framework; if not, write to the Free Software Foundation, Inc., 59
 * Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifndef __IWEAR_IWM_H
#define __IWEAR_IWM_H

#ifndef __IWEAR_IWEAR_H
#include <iwear/iwear.h>
#endif

#include <cmath>
#include <map>

using std::binary_function;


#ifdef IW_SOLARIS
#define fabsf fabs
#endif

namespace iwear
{
    namespace math
    {

template<class T>
class Help
{
public:
    static T neutral_addition( const T& t );
    static T neutral_subtraction( const T& t );
    static T neutral_multiplication( const T& t );
    static T neutral_division( const T& t );
};

#define constant_neutrals(T,na,ns,nm,nd) \
\
template<> \
inline T Help<T>::neutral_addition( const T& t ) \
{ \
    (void)t; \
    return na; \
} \
\
template<> \
inline T Help<T>::neutral_subtraction( const T& t ) \
{ \
    (void)t; \
    return ns; \
} \
\
template<> \
inline T Help<T>::neutral_multiplication( const T& t ) \
{ \
    (void)t; \
    return nm; \
} \
\
template<> \
inline T Help<T>::neutral_division( const T& t ) \
{ \
    (void)t; \
    return nd; \
}

constant_neutrals(float,0.0f,0.0f,1.0f,1.0f)
constant_neutrals(double,0.0,0.0,1.0,1.0)
constant_neutrals(long double,0.0,0.0,1.0,1.0)
constant_neutrals(int,0,0,1,1)
constant_neutrals(unsigned int,0,0,1,1)
constant_neutrals(long,0,0,1,1)
constant_neutrals(unsigned long,0,0,1,1)

template<class T>
inline T Help<T>::neutral_addition( const T& t )
{
    return t.neutral_addition( );
}

template<class T>
inline T Help<T>::neutral_subtraction( const T& t )
{
    return t.neutral_subtraction( );
}

template<class T>
inline T Help<T>::neutral_multiplication( const T& t )
{
    return t.neutral_multiplication( );
}

template<class T>
inline T Help<T>::neutral_division( const T& t )
{
    return t.neutral_division( );
}

template<class T>
class epsilon
{
public:
    static T pos( void );
    static T neg( void );
    static void set_pos( const T& );
    static void set_neg( const T& );
};

extern float epsilon_pos_float;
extern float epsilon_neg_float;

template<> 
inline float epsilon<float>::pos( void )
{
    return epsilon_pos_float;
}

template<> 
inline float epsilon<float>::neg( void )
{
    return epsilon_neg_float;
}

template<> 
inline void epsilon<float>::set_pos( const float& p )
{
    epsilon_pos_float = p;
}

template<> 
inline void epsilon<float>::set_neg( const float& p )
{
    epsilon_neg_float = p;
}

extern double epsilon_pos_double;
extern double epsilon_neg_double;

template<> 
inline double epsilon<double>::pos( void )
{
    return epsilon_pos_double;
}

template<> 
inline double epsilon<double>::neg( void )
{
    return epsilon_neg_double;
}

template<> 
inline void epsilon<double>::set_pos( const double& p )
{
    epsilon_pos_double = p;
}

template<> 
inline void epsilon<double>::set_neg( const double& p )
{
    epsilon_neg_double = p;
}

template <class _Tp>
struct equals : public binary_function<_Tp,_Tp,bool>
{
    bool operator()(const _Tp& __x, const _Tp& __y) const { return __x == __y; }
};

template <>
struct equals<float> : public binary_function<float,float,bool>
{
    bool operator()(const float& __x, const float& __y) const 
    { 
	return ( fabsf(__x-__y) <= math::epsilon<float>::pos() );
    }
};

template <>
struct equals<double> : public binary_function<double,double,bool>
{
    bool operator()(const double& __x, const double& __y) const 
    { 
	return ( fabs(__x-__y) <= math::epsilon<double>::pos() );
    }
};

template<class T> 
inline T absolute( const T& t );

inline float absolute( const float& t )
{
    return fabsf(t);
}

inline double absolute( const double& t )
{
    return fabs(t);
}

template<class T> 
inline T absolute( const T& t )
{
    return t;
}

template <class _Tp>
struct absolute_greater : public std::binary_function<_Tp,_Tp,bool>
{
    bool operator()(const _Tp& __x, const _Tp& __y) const 
    { 
	return absolute(__x) > absolute(__y); 
    }
};

} // of namespace math
}

#endif
