#ifndef REG_H
#define REG_H
#include <vector>
#include <map>
#include <typeinfo>
#include <iostream>

namespace hub {
  
// ---------------------------------------------------------------------------
//	list of registered functions, 3 params
// ---------------------------------------------------------------------------    
template <
typename RtnType,
typename ParType1,
typename ParType2,
typename ParType3 
>
class StatRegistry3 {
public:
    typedef RtnType (*ExecFunc) (ParType1, ParType2, ParType3);
    int Enlist (ExecFunc);
    int Enlist (ExecFunc, int);
    RtnType Perform (ParType1, ParType2, ParType3);
    RtnType Perform (int, ParType1, ParType2, ParType3);
private:
    std::vector <ExecFunc>* reg;
};

// ---------------------------------------------------------------------------
//	list of registered functions, 2 params
// ---------------------------------------------------------------------------
template <
typename RtnType,
typename ParType1,
typename ParType2
>
class StatRegistry2 {
public:
    typedef RtnType (*ExecFunc) (ParType1, ParType2);
    int Enlist (ExecFunc);
    int Enlist (ExecFunc, int);
    RtnType Perform (ParType1, ParType2);
    RtnType Perform (int, ParType1, ParType2);
private:
    std::vector <ExecFunc>*  reg;
};

// ---------------------------------------------------------------------------
//	list of registered functions, 1 param
// ---------------------------------------------------------------------------
template <
typename RtnType,
typename ParType1
>
class StatRegistry1 {
public:
    typedef RtnType (*ExecFunc) (ParType1);
    int Enlist (ExecFunc);
    int Enlist (ExecFunc, int);
    RtnType Perform (ParType1);
    RtnType Perform (int, ParType1);
private:
    std::vector <ExecFunc>*  reg;
};
// ---------------------------------------------------------------------------
//	list of multifunctor objects - static only version (no ctor)
// ---------------------------------------------------------------------------
template <
class Functor
>
class StatFtorRegistry {
public:
    int Enlist (Functor*);
    int Enlist (Functor*, int);

    template <
	typename RtnType, 
        typename ParType1, 
	RtnType (Functor:: *Member)(ParType1)
    > 
    RtnType Perform (ParType1);

    template <
	typename RtnType, 
        typename ParType1, 
        typename ParType2, 
	RtnType (Functor:: *Member)(ParType1, ParType2)
    > 
    RtnType Perform (ParType1, ParType2);

    template <
	typename RtnType, 
        typename ParType1, 
        typename ParType2, 
        typename ParType3, 
	RtnType (Functor:: *Member)(ParType1, ParType2, ParType3)
    > 
    RtnType Perform (ParType1, ParType2, ParType3);
    
    template <
	typename RtnType, 
        typename ParType1, 
        typename ParType2, 
        typename ParType3, 
        typename ParType4, 
	RtnType (Functor:: *Member)(ParType1, ParType2, ParType3, ParType4)
    > 
    RtnType Perform (ParType1, ParType2, ParType3, ParType4);

private:
    std::vector <Functor*>*  reg;
};
// ---------------------------------------------------------------------------
//	list of multifunctor objects - works only after initialization
// ---------------------------------------------------------------------------
template <
class Functor
>
class FtorRegistry {
public:
    int Enlist (Functor*);
    int Enlist (Functor*, int);

    template <
	typename RtnType, 
        typename ParType1, 
	RtnType (Functor:: *Member)(ParType1)
    > 
    RtnType Perform (ParType1);

    template <
	typename RtnType, 
        typename ParType1, 
        typename ParType2, 
	RtnType (Functor:: *Member)(ParType1, ParType2)
    > 
    RtnType Perform (ParType1, ParType2);

    template <
	typename RtnType, 
        typename ParType1, 
        typename ParType2, 
        typename ParType3, 
	RtnType (Functor:: *Member)(ParType1, ParType2, ParType3)
    > 
    RtnType Perform (ParType1, ParType2, ParType3);

    template <
	typename RtnType, 
        typename ParType1, 
        typename ParType2, 
        typename ParType3, 
        typename ParType4, 
	RtnType (Functor:: *Member)(ParType1, ParType2, ParType3, ParType4)
    > 
    RtnType Perform (ParType1, ParType2, ParType3, ParType4);
    
private:
    std::vector <Functor*>  reg;
};
// ---------------------------------------------------------------------------
//	a simple double dispatcher (bimenthods)
//	!!! type comparison done by comparing type_info*
// ---------------------------------------------------------------------------
template <
typename RtnType,
typename ParType1,
typename ParType2
>
class StatDoubleReg {
public:

    typedef RtnType (*ExecFunc) (ParType1, ParType2);
    template <
        typename ActualType1, 
        typename ActualType2,
	RtnType (*callback) (ActualType1, ActualType2)
    >
    int Enlist (void);
    RtnType Perform (ParType1, ParType2);
    int size (void) { return reg? reg->size() : -1; } 

private:
    typedef std::pair<const std::type_info*, const std::type_info*> KeyType;
    typedef std::map<KeyType, ExecFunc> MapType;
    MapType* reg;
    
};

#include "reg.tcc"
}
#endif
