ifndef Rice__Module_impl__hpp_ define Rice__Module_impl__hpp_

include “detail/Exception_Handler_defn.hpp” include “detail/ruby.hpp” include “Object_defn.hpp” include “Address_Registration_Guard_defn.hpp” include “Arg.hpp”

namespace Rice {

class Module; class Class; template<typename T> class Data_Type;

! Holds all member data of Module_impl so it only exists in one place
  in the hierarchy.

class Module_base

: public Object

{ public:

Module_base(VALUE v = rb_cObject);
Module_base(Module_base const & other);

Module_base & operator=(Module_base const & other);

void swap(Module_base & other);

protected:

template<typename Exception_T, typename Functor_T>
void add_handler(Functor_T functor);

Object handler() const;

private:

Object mutable handler_;
Address_Registration_Guard handler_guard_;

};

/*! An intermediate base class so we can always return the most-derived

  type (Module, Class, Data_Type, ...) without having to re-implement
  each function for each derived class.
/

template<typename Base_T, typename Derived_T> class Module_impl

: public Base_T

{ public:

Module_impl();

template<typename T>
Module_impl(T const & arg);

//! Define an exception handler.
/*! Whenever an exception of type Exception_T is thrown from a
    function defined on this class, functor will be called to
    translate the exception into a ruby exception.
    \param Exception_T a template parameter indicating the type of
    exception to be translated.
    \param functor a functor to be called to translate the exception
    into a ruby exception.  This functor should re-throw the exception
    as an Exception.
    Example:
    \code
      class MyException : public std::exception { };
      Data_Type<MyException> rb_cMyException;
      Class rb_cFoo;

      void translate_my_exception(MyException const & ex)
      {
        Data_Object<MyException> ex_(
            new MyException(ex),
            rb_cMyException);
        throw Exception(ex_);
      }

      extern "C"
      void Init_MyExtension()
      {
        rb_cMyException = define_class("MyException");
        rb_cFoo = define_class("Foo")
          .add_handler<MyException>(translate_my_exception);
      }
    \endcode
  /
template<typename Exception_T, typename Functor_T>
Derived_T & add_handler(
    Functor_T functor);

//! Define an instance method.
/*! The method's implementation can be any function or member
    function.  A wrapper will be generated which will use from_ruby<>
    to convert the arguments from ruby types to C++ types before
    calling the function.  The return value will be converted back to
    ruby by using to_ruby().
    \param name the name of the method
    \param func the implementation of the function, either a function
    pointer or a member function pointer.
    \param arguments the list of arguments of this function, used for
    defining default parameters (optional)
    \return *this
  /
template<typename Func_T>
Derived_T & define_method(
    Identifier name,
    Func_T func,
    Arguments* arguments = 0);

// FIXME There's GOT to be a better way to
// do this. Handles the case where there is a single
// argument defined for this method
template<typename Func_T>
Derived_T & define_method(
    Identifier name,
    Func_T func,
    Arg const& arg);

//! Define a singleton method.
/*! The method's implementation can be any function or member
    function.  A wrapper will be generated which will use from_ruby<>
    to convert the arguments from ruby types to C++ types before
    calling the function.  The return value will be converted back to
    ruby by using to_ruby().
    \param name the name of the method
    \param func the implementation of the function, either a function
    pointer or a member function pointer.
    \param arguments the list of arguments of this function, used for
    defining default parameters (optional)
    \return *this
  /
template<typename Func_T>
Derived_T & define_singleton_method(
    Identifier name,
    Func_T func,
    Arguments* arguments = 0);

// FIXME: See define_method with Arg above
template<typename Func_T>
Derived_T & define_singleton_method(
    Identifier name,
    Func_T func,
    Arg const& arg);

//! Define a module function.
/*! A module function is a function that can be accessed either as a
    singleton method or as an instance method.
    The method's implementation can be any function or member
    function.  A wrapper will be generated which will use from_ruby<>
    to convert the arguments from ruby types to C++ types before
    calling the function.  The return value will be converted back to
    ruby by using to_ruby().
    \param name the name of the method
    \param func the implementation of the function, either a function
    pointer or a member function pointer.
    \param arguments the list of arguments of this function, used for
    defining default parameters (optional)
    \return *this
  /
template<typename Func_T>
Derived_T & define_module_function(
    Identifier name,
    Func_T func,
    Arguments* arguments = 0);

// FIXME: See define_method with Arg above
template<typename Func_T>
Derived_T & define_module_function(
    Identifier name,
    Func_T func,
    Arg const& arg);

//! Define an iterator.
/*! Essentially this is a conversion from a C++-style begin/end
    iterator to a Ruby-style \#each iterator.
    \param begin a member function pointer to a function that returns
    an iterator to the beginning of the sequence.
    \param end a member function pointer to a function that returns an
    iterator to the end of the sequence.
    \param name the name of the iterator.
    \return *this
  /
template<typename T, typename Iterator_T>
Derived_T & define_iterator(
    Iterator_T (T::*begin)(),
    Iterator_T (T::*end)(),
    Identifier name = "each");

//! Include a module.
/*! \param inc the module to be included.
    \return *this
  /
Derived_T & include_module(
    Module const & inc);

//! Set a constant.
/*! \param name the name of the constant to set.
    \param value the value of the constant.
    \return *this
  /
Derived_T & const_set(
    Identifier name,
    Object value);

//! Get a constant.
/*! \param name the name of the constant to get.
    \return the value of the constant.
  /
Object const_get(
    Identifier name) const;

//! Determine whether a constant is defined.
/*! \param name the name of the constant to check.
    \return true if the constant is defined in this module or false
    otherwise.
  /
bool const_defined(
    Identifier name) const;

//! Remove a constant.
/*! \param name the name of the constant to remove.
  /
void remove_const(
    Identifier name);

//! Define a module under this module.
/*! \param name the name of the module.
    \return the new class.
  /
Module define_module(
    char const * name);

//! Define a class under this module.
/*! \param name the name of the class.
    \param superclass the base class to use.
    \return the new class.
  /
Class define_class(
    char const * name,
    Object superclass = rb_cObject);

//! Define a new data class under this module.
/*! The class will have a base class of Object.
    \param T the C++ type of the wrapped class.
    \return the new class.
  /
// This function needs to be defined inline to work around a bug in
// g++ 3.3.3.
template<typename T>
Data_Type<T>
define_class(
    char const * name)
{
  return this->define_class_with_object_as_base<T>(name);
}

//! Define a new data class under this module.
/*! The class with have a base class determined by Base_T (specifically,
    Data_Type<Base_T>::klass).  Therefore, the type Base_T must already
    have been registered using define_class<> or define_class_under<>.
    \param T the C++ type of the wrapped class.
    \return the new class.
  /
template<typename T, typename T_Base_T>
Data_Type<T>
define_class(
    char const * name);

private:

// Workaround for g++ 3.3.3 (see above).
template<typename T>
Data_Type<T>
define_class_with_object_as_base(
    char const * name);

};

} // namespace Rice

endif // Rice__Module_impl__hpp_