/* Copyright (c) 1997-2010
   Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Darmstadt, Germany)
   http://www.polymake.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.
--------------------------------------------------------------------------------
   $Project: polymake $$Id: converters.h 9991 2010-12-12 23:36:28Z gawrilow $
*/

#ifndef POLYMAKE_INTERNAL_CONVERTERS_H
#define POLYMAKE_INTERNAL_CONVERTERS_H

#include "polymake/internal/converters_basic_defs.h"
#include "polymake/internal/operations.h"
#include "polymake/TransformedContainer.h"

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 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;
   using pm::local_epsilon;
}

#endif // POLYMAKE_INTERNAL_CONVERTERS_H

// Local Variables:
// mode:C++
// c-basic-offset:3
// indent-tabs-mode:nil
// End:
