/* Copyright (c) 1997-2007
   Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Berlin, Germany)
   http://www.math.tu-berlin.de/polymake,  mailto:polymake@math.tu-berlin.de

   This program 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; either version 2, or (at your option) any
   later version: http://www.gnu.org/licenses/gpl.txt.

   This program 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.
*/

#ifndef _POLYMAKE_CONVERTERS_H
#define _POLYMAKE_CONVERTERS_H "$Project: polymake $$Id: converters.h 7579 2007-01-22 11:34:46Z gawrilow $"

#ifndef _POLYMAKE_CONVERTERS_BASIC_DEFS_H
#  include <converters_basic_defs.h>
#endif
#ifndef _POLYMAKE_OPERATIONS_H
#  include <operations.h>
#endif
#ifndef _POLYMAKE_TRANSFORMED_CONTAINER_H
#  include <TransformedContainer.h>
#endif

#include <cstdlib>
#include <cmath>

namespace pm {

// Everything can be converted to @c nothing.
template <typename T>
struct conv<T,nothing> {
   typedef T argument_type;
   typedef nothing result_type;
   nothing operator() (typename function_argument<T>::type) const { return nothing(); }
};

// conversion from nothing means creation from scratch, i.e. by default constructor
template <typename T>
struct conv<nothing,T> : operations::clear<T> {
   typedef nothing argument_type;
};

// resolving ambiguity
template <>
struct conv<nothing,nothing> {
   typedef nothing argument_type;
   typedef nothing result_type;
   nothing operator() (nothing) const { return nothing(); }
};

// conversion from suppressed data is equvalent to the default construction
template <typename From, typename To>
struct conv< ignore<From>, To > : operations::clear<To> {
   typedef ignore<From> argument_type;
};

template <typename From, typename To>
struct conv< From, ignore<To> > : operations::clear<To> {
   typedef From argument_type;
};

template <typename From, typename To>
struct conv< ignore<From>, ignore<To> > : conv< ignore<From>, To > { };

template <typename From1, typename From2, typename To1, typename To2>
struct conv< pair<From1,From2>, pair<To1,To2> > {
   typedef pair<From1,From2> argument_type;
   typedef pair<To1,To2> result_type;
private:
   conv<typename deref<From1>::type, typename deref<To1>::type> c1;
   conv<typename deref<From2>::type, typename deref<To2>::type> c2;
public:
   result_type operator() (const argument_type& p) const
   {
      return result_type(c1(p.first), c2(p.second));
   }

   template <typename From1_ref, typename From2_ref>
   result_type operator() (const pair<From1_ref,From2_ref>& p) const
   {
      return result_type(c1(p.first), c2(p.second));
   }
};

template <typename Result, typename Container> inline
TransformedContainer<const Container&, conv<typename object_traits<typename Container::value_type>::persistent_type, Result> >
attach_converter(const Container& src)
{
   return src;
}

template <typename Result, typename Container, typename ConverterArg> inline
TransformedContainer<const Container&, conv<typename object_traits<typename Container::value_type>::persistent_type, Result> >
attach_converter(const Container& src, const ConverterArg& conv_arg)
{
   return TransformedContainer<const Container&, conv<typename object_traits<typename Container::value_type>::persistent_type, Result> >
                              (src, conv_arg);
}

template <>
struct conv<const char*, int> {
   typedef const char* argument_type;
   typedef int result_type;

   result_type operator() (argument_type s) const { return std::atoi(s); }
};

template <>
struct conv<const char*, long> {
   typedef const char* argument_type;
   typedef long result_type;

   result_type operator() (argument_type s) const { return std::atol(s); }
};

template <typename T>
struct threshold_test {
   typedef T argument_type;
   typedef bool result_type;

   const T epsilon;
   threshold_test(typename function_argument<T>::type epsilon_arg) : epsilon(epsilon_arg) { }

   result_type operator() (typename function_argument<T>::type x) const
   {
      return std::abs(x) > epsilon;
   }
};

template <>
struct conv<double, bool> : threshold_test<double> {
   static double global_epsilon;
   conv() : threshold_test<double>(global_epsilon) { }
   conv(double epsilon_arg) : threshold_test<double>(epsilon_arg) { }
};

template <>
struct conv<float, bool> : threshold_test<float> {
   conv() : threshold_test<float>(conv<double,bool>::global_epsilon) { }
   conv(float epsilon_arg) : threshold_test<float>(epsilon_arg) { }
};

template <typename From, typename To>
struct conv_to_constant {
   typedef From argument_type;
   typedef typename To::constant_type result_type;

   result_type operator() (const argument_type&) const
   {
      return To::value;
   }
};

} // end namespace pm

namespace polymake {
   using pm::conv;
   using pm::attach_converter;
}

#endif // _POLYMAKE_CONVERTERS_H

// Local Variables:
// mode:C++
// End:
