#pragma once
#include "mof/stream/Manipulator.hpp"
#include "mof/stream/Cache.hpp"

namespace mof
{
	template< typename T , typename K >
	class Joint : public Manipulator< T >
    {
	public:
		typedef typename std::shared_ptr< mof::Joint< T , K > > Handler;

        
        virtual ~Joint( )
        {
        }

		virtual T value( FrameNumber frame ) const
        {
            return m_converter( m_body->value( frame ) );
        }

        
        typename Manipulator< K >::Handler get( ) const { return m_body; }

        void set( const typename Manipulator< K >::Handler& handler )
		{
			m_body = handler; 
			mof::state_changed();
		}

    private:
        typename Manipulator<K>::Handler m_body;
        T (*m_converter)( const K& );

        Joint( const typename Manipulator< K >::Handler& handler , T (*converter)( const K& ) )
        : m_body( handler) , m_converter( converter )
        {
        }

        template< typename T , typename K > friend
        typename Joint< T , K >::Handler makeJointHandler
        ( 
            const typename Manipulator< K >::Handler& handler ,
            T (*converter)( const K& )
        );

	}; // class Joint

    /** 型変換を行わないJoint */
    template< typename T >
	class Joint< T , T > : public Manipulator< T >
    {
	public:
		typedef typename std::shared_ptr< mof::Joint< T , T > > Handler;

        	
		virtual T getValue( mof::FrameNumber frame ) const
        {
            return m_body->getValue( frame );
        }

        typename mof::Manipulator< T >::Handler get( ) const { return m_body; }
        void set( const typename mof::Manipulator< T >::Handler& handler ){ m_body = handler; }
    
    private:
        typename mof::Manipulator< T >::Handler m_body;

        Joint( const typename Manipulator< T >::Handler& handler )
        : m_body( handler)
        {
        }

        template< typename T > friend
        typename Joint< T , T >::Handler makeJointHandler
        ( 
            const typename Manipulator< T >::Handler& handler 
        );

	}; // class Joint 

    
    template< typename T , typename K >
    typename Joint< T , K >::Handler makeJointHandler
    ( 
        const typename Manipulator< K >::Handler& handler  ,
        T (*converter)( const K& )
    )
    {
        return typename Joint< T , K >::Handler( new Joint< T , K >( handler , converter ) );
    }

    /** 型変換を行わないJointの生成 */
    // TODO 型推論が効かない
    template< typename T >
    typename Joint< T , T >::Handler makeJointHandler
    ( 
        const typename Manipulator< T >::Handler& handler 
    )
    {
        return typename Joint< T , T >::Handler( new Joint< T , T >( handler ) );
    }

    
} // namespace mof
