#pragma once
#include <memory>
#include "mof/stream/Cascade.hpp"
#include "mof/stream/Cache.hpp"
#include "mof/stream/Constant.hpp"
#include "mof/stream/Offset.hpp"

namespace mof
{
    
    template< typename T , class Cascador = DEFAULT_CASCADOR< T > >
	class TypeStream
    {
	public:
        TypeStream( )
        : m_frameNumber( 0 ) , m_cascade( mof::makeCascadeHandler< T , Cascador >() )
        {}
        

        TypeStream( const typename Manipulator< T >::Handler& handler )
        : m_frameNumber( 0 )  , m_cascade( mof::makeCascadeHandler< T , Cascador >() )
        {
            m_cascade << handler;
        }
        
        TypeStream( const T& value )
        : m_frameNumber( 0 )  , m_cascade( mof::makeCascadeHandler< T , Cascador >() )
        {
            m_cascade << value;
        }

        ~TypeStream( )
        {}
        
        TypeStream< T , Cascador >&
        operator << 
        (
            const typename Manipulator< T >::Handler& b 
        )
        {
            m_cascade->add
            (
                makeOffsetHandler< T >( b , -1 * (int)m_frameNumber)
            );
            return *this;
        }
        
        TypeStream< T , Cascador >&
        operator << 
        (
            const TypeStream< T , Cascador >& obj 
        )
        {
            //m_cascade->add( obj.m_cascade  );
            m_cascade->add( makeCacheHandler<T>(makeOffsetHandler< T >( obj.m_cascade , obj.m_frameNumber - m_frameNumber) ) );
            return *this;
        }


        TypeStream< T , Cascador >&
        operator << 
        (
            const T& b 
        )
        {
            m_cascade->add( mof::makeConstantHandler( b ) );
            return *this;
        }

		T value( ) const
        {
            return m_cascade->value( m_frameNumber );
        }

        typename Manipulator<T>::Handler toManipulator()
        {
            return m_cascade;
        }
    
        void update( )
        {
            m_frameNumber++;
        }

        FrameNumber getCurrentFrameNumber() const
        {
            return m_frameNumber;
        }

    private:
        FrameNumber m_frameNumber;
        typename Cascade< T , Cascador >::Handler m_cascade;
	};

} // namespace mof
