#ifndef _universal_
#define _universal_

#include<memory>


#include"../../mod10/code/functor_type.h"

template<typename FT> class AbstractFunctionHolder ;
template<typename FT,typename F> class FunctionHolder;

template<typename FT> class Function:
public  functor_traits<FT>::f_type {

  typedef typename functor_traits<FT>::result_type res_type;
  typedef typename functor_traits<FT>::arg1_type   arg1_type;
  typedef typename functor_traits<FT>::arg2_type   arg2_type;
 public:  

    Function() {};

  template<typename F>  Function(F fun):
    _fun(new FunctionHolder<FT,F>(fun)){};

  Function(const Function& f):_fun(f._fun->Clone()) {};
  Function &operator=(const Function &f) {
    _fun.reset(f._fun->Clone());
    //_fun=f._fun->Clone();
  }
  
  res_type operator()() {return (*_fun)();};
  res_type operator()(arg1_type x) {return (*_fun)(x);};
  res_type operator()(arg1_type x,arg2_type y) {return (*_fun)(x,y);};

  


 private:
  std::auto_ptr<AbstractFunctionHolder<FT> > _fun;
  //AbstractFunctionHolder<FT>  *_fun;
};


#if 0
template<typename R,typename A1,typename A2> 
class AbstractFunctionHolder<R (*)(A1,A2)> {
 public:
  virtual R operator()(A1 x, A2 y) = 0;
  virtual  AbstractFunctionHolder* Clone()=0;
  virtual ~AbstractFunctionHolder() {};  
  
} ;

template<typename R,typename A1> 
class AbstractFunctionHolder<R (*)(A1)> {
 public:
  virtual R operator()(A1 x) = 0;  
  virtual  AbstractFunctionHolder* Clone()=0;
  virtual ~AbstractFunctionHolder() {};
} ;

template<typename R> 
class AbstractFunctionHolder<R (*)()> {
 public:
  virtual R operator()() = 0;  
  virtual  AbstractFunctionHolder* Clone()=0;
  virtual ~AbstractFunctionHolder() {};
} ;
#else
template<typename FT> 
class AbstractFunctionHolder {

  typedef typename functor_traits<FT>::result_type res_type;
  typedef typename functor_traits<FT>::arg1_type arg1_type;
  typedef typename functor_traits<FT>::arg2_type arg2_type;

 public:
  virtual res_type operator()() = 0;
  virtual res_type operator()(arg1_type x) = 0;
  virtual res_type operator()(arg1_type x,arg2_type y)=0;

  virtual  AbstractFunctionHolder* Clone()=0;
  virtual ~AbstractFunctionHolder() {};  
  
} ;

#endif



template<typename FT,typename F> 
class FunctionHolder: public AbstractFunctionHolder<FT> {

  typedef typename functor_traits<FT>::result_type res_type;
  typedef typename functor_traits<FT>::arg1_type arg1_type;
  typedef typename functor_traits<FT>::arg2_type arg2_type;
  
 public:
  
  res_type operator()() {return _fun();};
  res_type operator()(arg1_type x) {return _fun(x);};
  res_type operator()(arg1_type x,arg2_type y) {return _fun(x,y);};
  
  FunctionHolder(F fun):_fun(fun) {}; 
  FunctionHolder*Clone() {return new FunctionHolder(*this);}
 private:
  F _fun;
};



#endif