#pragma once
#include <boost/function/function0.hpp>

namespace mof
{
    //TODO タイプリストとかで、そのままのインタフェースでより汎用的にする
    //非const参照を渡したい場合は？(constructorにそれはありえない)


//{{{ FactoryMethod
    template < class T > 
    class FactoryMethod
    {
    public: 
        FactoryMethod( const boost::function<T* (void)>& factory)
            : m_factory(factory){}

        T* operator() () const{ return m_factory(); }
        
        template<class T>
        operator FactoryMethod<T>( ) const
        {
            return FactoryMethod<T>(m_factory); 
        }



    private: 
        boost::function<T* (void)> m_factory;
    };

        
//}}}
//{{{ Constructor0
    template < class T > 
    class Constructor0
    {
    public: 
        T* operator() ( ) const {return new T();}
    };
//}}}
//{{{ Constructor1
    template <class T , class P1> 
    class Constructor1 : protected Constructor0<T>
    {
    protected:
        P1 p1;
    public: 
        Constructor1(const P1& p1_)
            : p1(p1_)
        {}

        T* operator() ( ) const {return new T(p1);}
    };
//}}}
//{{{ Constructor2
    template <class T , class P1 , class P2> 
    class Constructor2 : protected Constructor1<T , P1>
    {
    protected:
        P2 p2;
    public: 
        Constructor2(const P1& p1_ , const P2& p2_)
            : Constructor1(p1_) , p2(p2_)
        {}

        T* operator() ( ) const {return new T(p1 , p2);}
    };
//}}}
//{{{ Constructor3
    template <class T , class P1 , class P2 , class P3> 
    class Constructor3 : protected Constructor2<T , P1 , P2>
    {
    protected:
        P3 p3;
    public: 
        Constructor3(const P1& p1_ , const P2& p2_ , const P3& p3_)
            : Constructor2(p1_ , p2_) , p3(p3_)
        {}

        T* operator() ( ) const {return new T(p1 , p2 , p3);}
    };
//}}}
//{{{ Constructor4
    template <class T , class P1 , class P2 , class P3 , class P4> 
    class Constructor4 : protected Constructor3<T , P1 , P2 , P3>
    {
    protected:
        P4 p4;
    public: 
        Constructor4(const P1& p1_ , const P2& p2_ , const P3& p3_ , const P4& p4_)
            : Constructor3(p1_ , p2_ , p3_) , p4(p4_)
        {}

        T* operator() ( ) const {return new T(p1 , p2 , p3 , p4);}
    };
//}}}
//{{{ Constructor5
    template <class T , class P1 , class P2 , class P3 , class P4, class P5> 
    class Constructor5 : protected Constructor4<T , P1 , P2 , P3, P4>
    {
    protected:
        P5 p5;
    public: 
        Constructor5(const P1& p1_ , const P2& p2_ , const P3& p3_ , const P4& p4_, const P5& p5_)
            : Constructor4(p1_ , p2_ , p3_, p4_), p5(p5_)
        {}

        T* operator() ( ) const {return new T(p1 , p2 , p3 , p4, p5);}
    };
//}}}
 
//{{{ makeFactoryMethod
    template<class T>
    FactoryMethod<T>
    makeFactoryMethod()
    {
        return FactoryMethod<T>( Constructor0<T>() );
    }
        
    template<class T , class P1>
    FactoryMethod<T>
    makeFactoryMethod(const P1& p1)
    {
        return FactoryMethod<T>( Constructor1<T , P1>(p1) );
    }
    
    template<class T , class P1 , class P2>
    FactoryMethod<T>
    makeFactoryMethod(const P1& p1 , const P2& p2)
    {
        return FactoryMethod<T>( Constructor2<T , P1 , P2>(p1 , p2) );
    }
    
    template<class T , class P1 , class P2 , class P3>
    FactoryMethod<T>
    makeFactoryMethod(const P1& p1 , const P2& p2 , const P3& p3)
    {
        return FactoryMethod<T>( Constructor3<T , P1 , P2 , P3>(p1 , p2 , p3) );
    }
        
    template<class T , class P1 , class P2 , class P3 , class P4>
    FactoryMethod<T>
    makeFactoryMethod(const P1& p1 , const P2& p2 , const P3& p3 , const P4& p4)
    {
        return FactoryMethod<T>( Constructor4<T , P1 , P2 , P3 , P4>(p1 , p2 , p3 , p4) );
    }
	
	template<class T , class P1 , class P2 , class P3 , class P4, class P5>
    FactoryMethod<T>
    makeFactoryMethod(const P1& p1 , const P2& p2 , const P3& p3 , const P4& p4, const P5& p5)
    {
        return FactoryMethod<T>( Constructor5<T , P1 , P2 , P3 , P4 , P5>(p1 , p2 , p3 , p4, p5) );
    }

//}}}


}
