#pragma once
#include <sstream>
#include <boost/type_traits.hpp>

//------------------------------------------------------------------------------
// Compile-time assertions
//------------------------------------------------------------------------------
template<bool> struct static_assert;
template<> struct static_assert<true> { };

//------------------------------------------------------------------------------
// Unused variable (remove compilation warnings)
//------------------------------------------------------------------------------
template<class T> void unused(const T&) { }

//------------------------------------------------------------------------------
// Static selector
//------------------------------------------------------------------------------
template<bool Cond, class TrueType, class FalseType> struct static_if_else;

template<class TrueType, class FalseType>
struct static_if_else<true,TrueType,FalseType>  { typedef TrueType type; };

template<class TrueType, class FalseType>
struct static_if_else<false,TrueType,FalseType> { typedef FalseType type; };

//------------------------------------------------------------------------------
// Boolean type wrappers
//------------------------------------------------------------------------------
struct true_type { enum { value = true }; };
struct false_type { enum { value = false }; };

//------------------------------------------------------------------------------
// Compare two types (use boost::is_same instead)
//------------------------------------------------------------------------------
//template<class T, class U>
//struct boost::is_same : false_type { };
//
//template<class T>
//struct boost::is_same<T,T> : true_type { };

//------------------------------------------------------------------------------
// Templated empty class (with a lot of useless generic constructors!)
//------------------------------------------------------------------------------
template <class T>
struct empty
{
  empty(){}
  template <class T1> empty(const T1&) {}
  template <class T1, class T2> empty(const T1&, const T2&) {}
  template <class T1, class T2, class T3> empty(const T1&, const T2&, const T3&) {}
  template <class T1, class T2, class T3, class T4> empty(const T1&, const T2&, const T3&, const T4&) {}
  template <class T1, class T2, class T3, class T4, class T5> empty(const T1&, const T2&, const T3&, const T4& t4, const T5&) {}
};

//------------------------------------------------------------------------------
// Prevents taking the size of a pointer type
//------------------------------------------------------------------------------
// Use (sizeof array_size(a)) instead of (sizeof a / sizeof *a)
template<typename T, size_t N> size_t array_size(T(&)[N])
{
  return N;
}

//------------------------------------------------------------------------------
// Converts an object to string
//------------------------------------------------------------------------------

namespace detail
{
  struct PrintObjectDescriptionIfReferenceType
  {
    template <class T>
    static std::string toString(const T& object)
    {
      std::stringstream out;
      out << object;
      return out.str();
    }
  };

  struct PrintObjectDescriptionIfPointerType
  {
    template <class T>
    static std::string toString(const T& object)
    {
      // Assuming there is only one dereference needed
      return ::detail::PrintObjectDescriptionIfReferenceType::toString(*object);
    }
  };
};

/**
 * @brief Converts an object or pointer to a string representation, by inserting said object on a stream.
 *
 * @param object The object (possibly a pointer) to get a string representation of.
 * @return A string representation of the specified object.
 */
template<class T>
std::string toString(const T& object)
{
  return static_if_else<boost::is_pointer<T>::value, 
                        ::detail::PrintObjectDescriptionIfPointerType, 
                        ::detail::PrintObjectDescriptionIfReferenceType>::type::toString(object);
}

/**
 * @brief Returns true if a sequence respects the ordering supplied by the comparator.
 *
 * @tparam Iterator The type of iterator.
 * @tparam Comparator The type of comparator that specifies the ordering.
 * @param begin The beginning of the sequence.
 * @param end The end of the sequence.
 * @param comparator The comparator to use.
 * @return Whether the sequence respects the ordering.
 */
template <class Iterator, class Comparator>
bool sequenceRespectsComparator(Iterator begin, Iterator end, Comparator comparator = Comparator())
{
  typedef typename Iterator::value_type value_type;
  bool respects = true;
  if (begin != end)
  {
    value_type previous = *begin;
    ++begin;
    for (; respects && begin != end; ++begin)
    {
      const value_type current = *begin;
      respects = comparator(previous, current);
      previous = current;
    }
  }
  return respects;
}
