// Boost.Signals library
//
// Copyright (C) 2001-2002 Doug Gregor (gregod@cs.rpi.edu)
//
// Permission to copy, use, sell and distribute this software is granted
// provided this copyright notice appears in all copies.
// Permission to modify the code and to distribute modified code is granted
// provided this copyright notice appears in all copies, and a notice
// that the code was modified is included with the copyright notice.
//
// This software is provided "as is" without express or implied warranty,
// and with no claim as to its suitability for any purpose.
 
// For more information, see http://www.boost.org

#ifndef BOOST_SIGNALS_COMMON_HEADER
#define BOOST_SIGNALS_COMMON_HEADER

#ifndef BOOST_SIGNALS_NAMESPACE
#  define BOOST_SIGNALS_NAMESPACE signals
#endif

/*****************************************************************************
 *
 *  Set up dll import/export options:
 *
 ****************************************************************************/
#if defined(_MSC_VER) && defined(_DLL)
#  define BOOST_SIGNALS_HAS_DLL_RUNTIME
#endif

#if defined(BOOST_SIGNALS_HAS_DLL_RUNTIME) && !defined(BOOST_SIGNALS_STATIC_LINK)
#   if defined(BOOST_SIGNALS_IN_LIBRARY_SOURCE)
#       define BOOST_SIGNALS_DECL __declspec(dllexport)
#       define BOOST_SIGNALS_BUILD_DLL
#   else
#       define BOOST_SIGNALS_DECL __declspec(dllimport)
#  endif
#endif

#ifndef BOOST_SIGNALS_DECL
#  define BOOST_SIGNALS_DECL
#endif

/*****************************************************************************
 ****************************************************************************/

#include <boost/type_traits/conversion_traits.hpp>
#include <boost/ref.hpp>

namespace boost {
  namespace BOOST_SIGNALS_NAMESPACE {
    namespace detail {
      // The unusable class is a placeholder for unused function arguments
      // It is also completely unusable except that it constructable from
      // anything. This helps compilers without partial specialization
      // handle slots returning void.  
      struct unusable {
        unusable() {}
      };

      // Determine the result type of a slot call
      template<typename R>
      struct slot_result_type {
        typedef R type;
      };

      template<>
      struct slot_result_type<void> {
        typedef unusable type;
      };

      // Determine if the given type T is a signal
      class signal_base;

      template<typename T>
      struct is_signal {
        BOOST_STATIC_CONSTANT(bool, 
          value = (is_convertible<T*, signal_base*>::value));
      };

      /*
       * The IF implementation is temporary code. When a Boost metaprogramming
       * library is introduced, Boost.Signals will use it instead. 
       */
      namespace intimate {
        struct SelectThen 
        {       
          template<typename Then, typename Else>
          struct Result
          {       
            typedef Then type;
          };
        };
 
        struct SelectElse
        {
          template<typename Then, typename Else>
          struct Result
          { 
            typedef Else type;
          };
        };
 
        template<bool Condition>
        struct Selector
        {
          typedef SelectThen type;
        };
 
        template<>
        struct Selector<false>
        {
          typedef SelectElse type;
        };
      } // end namespace intimate 
 
      template<bool Condition, typename Then, typename Else>
      struct IF
      {
        typedef typename intimate::Selector<Condition>::type select;
        typedef typename select::template Result<Then,Else>::type type;
      };

      // Determine if the incoming argument is a reference_wrapper
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
      template<typename T>
      struct is_ref
      {
        BOOST_STATIC_CONSTANT(bool, value = false); 
      };

      template<typename T>
      struct is_ref<reference_wrapper<T> >
      {
        BOOST_STATIC_CONSTANT(bool, value = true);
      };
#else // no partial specialization
      typedef char yes_type;
      typedef double no_type;
      
      no_type is_ref_tester(...);

      template<typename T>
      yes_type is_ref_tester(reference_wrapper<T>*);

      template<typename T>
      struct is_ref
      {
        static T* t;
        BOOST_STATIC_CONSTANT(bool, 
          value = (sizeof(is_ref_tester(t)) == sizeof(yes_type)));
      };
#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION

      // A slot can be a signal, a reference to a function object, or a 
      // function object.
      struct signal_tag {};
      struct reference_tag {};
      struct value_tag {};

      // Classify the given slot as a signal, a reference-to-slot, or a 
      // standard slot
      template<typename S>
      class get_slot_tag {
        typedef typename IF<(is_signal<S>::value),
                            signal_tag,
                            value_tag>::type signal_or_value;

      public:   
        typedef typename IF<(is_ref<S>::value),
                            reference_tag,
                            signal_or_value>::type type;
      };

      // Forward declaration needed in lots of places
      class signal_base_impl;
      class bound_objects_visitor;
      class slot_base;
    } // end namespace detail
  } // end namespace BOOST_SIGNALS_NAMESPACE
} // end namespace boost

#endif // BOOST_SIGNALS_COMMON_HEADER
