/* Copyright (c) 1997-2006
   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_COMPARATORS_H
#define _POLYMAKE_COMPARATORS_H "$Project: polymake $$Id: comparators.h 7481 2006-11-30 21:47:36Z gawrilow $"

#ifndef _POLYMAKE_COMPARATORS_OPS_H
#  include <comparators_ops.h>
#endif
#ifndef _POLYMAKE_TRANSFORMED_CONTAINER_H
#  include <TransformedContainer.h>
#endif

namespace pm {
namespace operations {

template <typename Comparator, typename T, int dim=object_traits<T>::dimension>
struct cmp_lex_containers : cmp_common<T> {
   using cmp_common<T>::operator();

   template <typename Container1, typename Container2>
   cmp_value operator() (const Container1& a, const Container2& b) const
   {
      cmp_lex_containers<Comparator, typename object_traits<Container1>::serialized> cmp_op;
      return cmp_op(object_traits<Container1>::serialize(a), object_traits<Container2>::serialize(b));
   }
};

template <typename Comparator, typename T>
struct cmp_lex_containers<Comparator, T, 1> : cmp_common<T> {
   using cmp_common<T>::operator();

protected:
   template <typename Iterator> static
   bool at_end1(const Iterator& it, end_sensitive*)
   {
      return static_cast<const typename Iterator::first_type&>(it).at_end();
   }
   template <typename Iterator> static
   bool at_end1(const Iterator&, void*)
   {
      return false;
   }
   template <typename Iterator> static
   bool at_end2(const Iterator& it, end_sensitive*)
   {
      return it.second.at_end();
   }
   template <typename Iterator> static
   bool at_end2(const Iterator&, void*)
   {
      return false;
   }

   template <typename Iterator, typename _end1, typename _end2> static
   cmp_value _do(Iterator it, _end1*, _end2*)
   {
      for (;;) {
	 if (at_end1(it, (_end1*)0))
	    return at_end2(it, (_end2*)0) ? cmp_eq : cmp_lt;
	 if (at_end2(it, (_end2*)0))
	    return cmp_gt;
	 cmp_value result=*it;
	 if (result != cmp_eq)
	    return result;
	 ++it;
      }
   }

   template <typename Container1, typename Container2> static
   cmp_value _do(const Container1& a, const Container2& b, False)
   {
      typedef typename if_else<object_classifier::what_is<Container1>::value==object_classifier::is_constant,
	                       void, end_sensitive>::type
	 feature1;
      typedef typename if_else<object_classifier::what_is<Container2>::value==object_classifier::is_constant,
	                       void, end_sensitive>::type
	 feature2;
      typedef TransformedContainerPair< masquerade_add_features<const Container1&, feature1>,
	                                masquerade_add_features<const Container2&, feature2>, Comparator > TP;
      return _do(entire(TP(a,b)), (feature1*)0, (feature2*)0);
   }

   template <typename Container1, typename Container2> static
   cmp_value _do(const Container1& a, const Container2& b, True)
   {
      cmp_value result=first_nonzero(entire(attach_operation(a,b,Comparator())));
      return result!=cmp_eq ? result : pm::sign(get_dim(a)-get_dim(b));
   }

public:
   template <typename Container1, typename Container2>
   cmp_value operator() (const Container1& a, const Container2& b) const
   {
      return _do(a, b, bool2type<(check_container_feature<Container1,sparse>::value ||
		                  check_container_feature<Container2,sparse>::value)>());
   }
};

template <typename Comparator, typename T>
struct cmp_lex<Comparator, T, is_container> : cmp_lex_containers<Comparator,T> { };

template <typename Comparator, typename T>
struct cmp_lex<Comparator, T, is_composite> : cmp_common<T> {
   using cmp_common<T>::operator();

protected:
   static const int last=list_length<typename object_traits<T>::elements>::value-1;

   cmp_value _do(const T& a, const T& b, int2type<last>) const
   {
      typename build_comparator_for_refs<Comparator, typename n_th<typename object_traits<T>::elements, last>::type>::operation cmp_op;
      return cmp_op(visit_n_th(a,int2type<last>()), visit_n_th(b,int2type<last>()));
   }

   template <int i>
   cmp_value _do(const T& a, const T& b, int2type<i>) const
   {
      typename build_comparator_for_refs<Comparator, typename n_th<typename object_traits<T>::elements, i>::type>::operation cmp_op;
      cmp_value result=cmp_op(visit_n_th(a,int2type<i>()), visit_n_th(b,int2type<i>()));
      if (result==cmp_eq) result=_do(a,b,int2type<i+1>());
      return result;
   }
public:
   cmp_value operator() (const T& a, const T& b) const
   {
      return _do(a,b,int2type<0>());
   }
};

} // end namespace operations

namespace operators {

template <typename Left, typename Right> inline
bool operator!= (const Left& l, const Right& r)
{
   return !(l==r);
}

template <typename Left, typename Right> inline
bool operator> (const Left& l, const Right& r)
{
   return r<l;
}

template <typename Left, typename Right> inline
bool operator<= (const Left& l, const Right& r)
{
   return !(r<l);
}

template <typename Left, typename Right> inline
bool operator>= (const Left& l, const Right& r)
{
   return !(l<r);
}

} // end namespace operators

template <typename T, bool _is_max> inline
bool operator== (const T&, const extremal<T,_is_max>&) { return false; }
template <typename T, bool _is_max> inline
bool operator!= (const T&, const extremal<T,_is_max>&) { return true; }
template <typename T, bool _is_max> inline
bool operator< (const T&, const extremal<T,_is_max>&) { return _is_max; }
template <typename T, bool _is_max> inline
bool operator<= (const T&, const extremal<T,_is_max>&) { return _is_max; }
template <typename T, bool _is_max> inline
bool operator> (const T&, const extremal<T,_is_max>&) { return !_is_max; }
template <typename T, bool _is_max> inline
bool operator>= (const T&, const extremal<T,_is_max>&) { return !_is_max; }
template <typename T, bool _is_max> inline
bool operator== (const extremal<T,_is_max>&, const T&) { return false; }
template <typename T, bool _is_max> inline
bool operator!= (const extremal<T,_is_max>&, const T&) { return true; }
template <typename T, bool _is_max> inline
bool operator< (const extremal<T,_is_max>&, const T&) { return !_is_max; }
template <typename T, bool _is_max> inline
bool operator<= (const extremal<T,_is_max>&, const T&) { return !_is_max; }
template <typename T, bool _is_max> inline
bool operator> (const extremal<T,_is_max>&, const T&) { return _is_max; }
template <typename T, bool _is_max> inline
bool operator>= (const extremal<T,_is_max>&, const T&) { return _is_max; }

template <typename T, bool _is_max1, bool _is_max2> inline
bool operator== (const extremal<T,_is_max1>&, const extremal<T,_is_max2>&) { return _is_max1==_is_max2; }
template <typename T, bool _is_max1, bool _is_max2> inline
bool operator!= (const extremal<T,_is_max1>&, const extremal<T,_is_max2>&) { return _is_max1!=_is_max2; }
template <typename T, bool _is_max1, bool _is_max2> inline
bool operator< (const extremal<T,_is_max1>&, const extremal<T,_is_max2>&) { return _is_max1<_is_max2; }
template <typename T, bool _is_max1, bool _is_max2> inline
bool operator<= (const extremal<T,_is_max1>&, const extremal<T,_is_max2>&) { return _is_max1<=_is_max2; }
template <typename T, bool _is_max1, bool _is_max2> inline
bool operator> (const extremal<T,_is_max1>&, const extremal<T,_is_max2>&) { return _is_max1>_is_max2; }
template <typename T, bool _is_max1, bool _is_max2> inline
bool operator>= (const extremal<T,_is_max1>&, const extremal<T,_is_max2>&) { return _is_max1>=_is_max2; }

} // end namespace pm

namespace polymake {
   using pm::sign;
   using pm::assign_max;
   using pm::assign_min;
   using pm::assign_min_max;
   using pm::maximal;
   using pm::minimal;

   namespace operations {
      typedef BuildUnary<pm::operations::positive> positive;
      typedef BuildUnary<pm::operations::negative> negative;

      typedef pm::operations::cmp<> cmp;
      typedef pm::operations::cmp_epsilon<> cmp_epsilon;
      typedef BuildBinary<pm::operations::eq> eq;
      typedef BuildBinary<pm::operations::ne> ne;
      typedef BuildBinary<pm::operations::lt> lt;
      typedef BuildBinary<pm::operations::le> le;
      typedef BuildBinary<pm::operations::gt> gt;
      typedef BuildBinary<pm::operations::ge> ge;
      typedef BuildBinary<pm::operations::max> max;
      typedef BuildBinary<pm::operations::min> min;
      typedef BuildUnary<pm::operations::abs> abs;
   }
}

#endif // _POLYMAKE_COMPARATORS_H

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