// __author__ = Juan Carlos De Abreu (jcabreur@gmail.com)
//
// These class define functors with 0 arguments.
//
// The functor allow have a pointer a function that can be changed when the
// programer wanted.
//
// The class receive one(1) parameter;
//   R : Return type of the function.

#ifndef FUNCTOR_FUNCTOR0_H__
#define FUNCTOR_FUNCTOR0_H__

#include "../../global.h"

BEGIN_TEG_NAMESPACE();

// Definition of the structure that manage a ponter to a function whith 0
// parameters.
template<typename R>
class Functor0 {
public:
  // Functor0 constructor.
  Functor0() { }

  // Functor0 destructor.
  virtual ~Functor0() { }
		
  // Methods.
  virtual R call(void) = 0; // Method to call the function that has the functor.
};

// Specialization of a Functor0 that allow pointer to global function.
template<typename R>
class FunctorGlobal0 : public Functor0<R> {
protected:
  // Attributes.
  R (*pFunc)(void); // Pointer to a function

public:
  // FunctorGlobal0 constructor.
  FunctorGlobal0(R (*_pFunc)(void) = NULL);

  // FunctorGlobal0 destructor.
  ~FunctorGlobal0() { pFunc = NULL; }

  // Methods.
  R call(); // Method to call the function that has the functor
};

// FunctorGlobal0 constructor.
template<typename R>
inline FunctorGlobal0<R>::FunctorGlobal0(R (*_pFunc)(void)): pFunc(_pFunc) {
  // Do anything ...
}

// Method to call the function that has the functor.
template<typename R>
inline R FunctorGlobal0<R>::call() {
  // If I have a function then caller.
  return pFunc == NULL ? R() : pFunc();
}

// Specialization of a Functor0 that allow pointer to global function.
template<typename R, typename B>
class FunctorMember0 : public Functor0<R> {
protected:
  // Attributes.
  R (B::*pFunc)(void); // Pointer to a function.
  B *pClass;           // Pointer to the base class.

public:
  // FunctorMember0 constructor.
  FunctorMember0(R (B::*_pFunc)(void) = NULL, B *_pClass = NULL);

  // FunctorMember0 destructor.
  ~FunctorMember0() { pFunc = NULL; }

  // Methods.
  R call(); // Method to call the function that has the functor
};

// FunctorMember0 constructor.
template<typename R, typename B>
inline FunctorMember0<R,B>::FunctorMember0(R (B::*_pFunc)(void), B *_pClass)
    : pFunc(_pFunc), pClass(_pClass) {
  // Do anything ...
}

// Method to call the function that has the functor.
template<typename R, typename B>
inline R FunctorMember0<R,B>::call() {
  // If I have a function then caller.
  return pFunc == NULL ? R() : (pClass->*pFunc)();
}

// Specialization of a Functor0 that allow pointer to global function.
template<typename R, typename B>
class FunctorMemberConst0 : public Functor0<R> {
protected:
  // Attributes.
  R (B::*pFunc)(void) const; // Pointer to a function.
  B *pClass;                 // Pointer to the base class.

public:
  // FunctorMemberConst0 constructor.
  FunctorMemberConst0(R (B::*_pFunc)(void) const = NULL, B *_pClass = NULL);

  // FunctorMemberConst0 destructor.
  ~FunctorMemberConst0() { pFunc = NULL; }

  // Methods.
  R call(); // Method to call the function that has the functor.
};

// FunctorMemberConst0 constructor.
template<typename R, typename B>
inline FunctorMemberConst0<R,B>::FunctorMemberConst0(
    R (B::*_pFunc)(void) const, B *_pClass) : pFunc(_pFunc), pClass(_pClass) {
  // Do anything ...
}

// Method to call the function that has the functor.
template<typename R, typename B>
inline R FunctorMemberConst0<R,B>::call() {
  // If I have a function then caller.
  return pFunc == NULL ? R() : (pClass->*pFunc)();
}

// Function to create a Functor0 with a global function.
template<typename R>
Functor0<R>* newFunctor0(R (*pFunc)(void)) {
  return new FunctorGlobal0<R> (pFunc);
}

// Function to create a Functor0 with a member function.
template<typename R, typename B>
Functor0<R>* newFunctor0(R (B::*pFunc)(void), B *pClass = NULL) {
  return new FunctorMember0<R,B> (pFunc, pClass);
}

// Function to create a Functor0 with a member const function.
template<typename R, typename B>
Functor0<R>* newFunctor0(R (B::*pFunc)(void) const, B *pClass = NULL) {
  return new FunctorMemberConst0<R,B> (pFunc, pClass);
}

END_TEG_NAMESPACE();

#endif  // FUNCTOR_FUNCTOR0_H__
