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

#ifndef FUNCTOR_FUNCTOR1_H__
#define FUNCTOR_FUNCTOR1_H__

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

BEGIN_TEG_NAMESPACE();

// Definition of the structure that manage a ponter to a function whith 1
// parameter.
template<typename R, typename T>
class Functor1 {
public:
  // Functor1 constructor.
  Functor1() { }

  // Functor1 destructor.
  virtual ~Functor1() { }

  // Methods.
  virtual R call(T t) = 0; // Method to call the function that has the functor.
};

template<typename R, typename T>
class FunctorGlobal1 : public Functor1<R, T> {
private:
  // Attributes.
  R (*pFunc)(T); // Pointer to a function.

public:
  // FunctorGlobal1 constructor.
  FunctorGlobal1(R (*pFunc_)(T) = NULL);
  
  // FunctorGlobal1 destructor.
  ~FunctorGlobal1() { pFunc = NULL; }

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

template<typename R, typename T, typename B>
class FunctorMember1 : public Functor1<R, T> {
private:
  // Attributes.
  R (B::*pFunc)(T); // Pointer to a function.
  B *pClass;        // Pointer to the base class.

public:
  // FunctorMember1 constructor.
  FunctorMember1(R (B::*pFunc_)(T) = NULL, B *pClass_ = NULL);
  
  // FunctorMember1 destructor.
  ~FunctorMember1() { pFunc = NULL; }

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

template<typename R, typename T, typename B>
class FunctorMemberConst1 : public Functor1<R, T> {
private:
  // Attributes.
  R (B::*pFunc)(T) const; // Pointer to a function.
  B *pClass;              // Pointer to the base class.

public:
  // FunctorMemberConst1 constructor.
  FunctorMemberConst1(R (B::*pFunc_)(T) const = NULL, B *pClass_ = NULL); 

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

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

// FunctorGlobal1 constructor.
template<typename R, typename T>
inline FunctorGlobal1<R, T>::FunctorGlobal1(R (*pFunc_)(T)) : pFunc(pFunc_) {
  // Do anything ...
}

// FunctorMember1 constructor.
template<typename R, typename T, typename B>
inline FunctorMember1<R, T, B>::FunctorMember1(
    R (B::*pFunc_)(T), B *pClass_) : pFunc(pFunc_), pClass(pClass_) {
  // Do anything ...
}

// FunctorMemberConst1 constructor.
template<typename R, typename T, typename B>
inline FunctorMemberConst1<R, T, B>::FunctorMemberConst1(
    R (B::*pFunc_)(T) const, B *pClass_) : pFunc(pFunc_), pClass(pClass_) {
  // Do anything ...
}

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

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

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

// Function to create a Functor1 with a global function.
template<typename R, typename T>
Functor1<R, T>* newFunctor1(R (*pFunc)(T)) {
	return new FunctorGlobal1<R, T> (pFunc);
}

// Function to create a Functor1 with a member function.
template<typename R, typename T, typename B>
Functor1<R, T>* newFunctor1(R (B::*pFunc)(T), B *pClass = NULL) {
	return new FunctorMember1<R, T, B> (pFunc, pClass);
}

// Function to create a Functor1 with a member const function.
template<typename R, typename T, typename B>
Functor1<R, T>* newFunctor1(R (B::*pFunc)(T) const, B *pClass = NULL) {
	return new FunctorMemberConst1<R, T, B> (pFunc, pClass);
}

END_TEG_NAMESPACE();

#endif  // FUNCTOR_FUNCTOR1_H__
