//
// LDASTools frameCPP - A library implementing the LIGO/Virgo frame
// specification
//
// Copyright (C) 2018 California Institute of Technology
//
// LDASTools frameCPP is free software; you may redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 (GPLv2) of the
// License or at your discretion, any later version.
//
// LDASTools frameCPP is distributed in the hope that it will be useful, but
// without any warranty or even the implied warranty of merchantability
// or fitness for a particular purpose. See the GNU General Public
// License (GPLv2) for more details.
//
// Neither the names of the California Institute of Technology (Caltech),
// The Massachusetts Institute of Technology (M.I.T), The Laser
// Interferometer Gravitational-Wave Observatory (LIGO), nor the names
// of its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// You should have received a copy of the licensing terms for this
// software included in the file LICENSE located in the top-level
// directory of this package. If you did not, you can view a copy at
// http://dcc.ligo.org/M1500244/LICENSE
//

#include "framecpp/Common/MemoryBuffer.hh"

namespace FrameCPP
{
    namespace Common
    {
        //===================================================================
        //-------------------------------------------------------------------
        ///
        //-------------------------------------------------------------------
        template < typename BT >
        MemoryBufferT< BT >::Seeder::Seeder( )
        {
        }

        template < typename BT >
        MemoryBufferT< BT >::Seeder::~Seeder( )
        {
        }

        template < typename BT >
        void
        MemoryBufferT< BT >::Seeder::operator( )( buffer_type& Buffer )
        {
            output = &Buffer;
        }

        //===================================================================
        //-------------------------------------------------------------------
        ///
        //-------------------------------------------------------------------

        template < typename BT >
        MemoryBufferT< BT >::BufferSeeder::BufferSeeder( )
        {
        }

        template < typename BT >
        bool
        MemoryBufferT< BT >::BufferSeeder::operator( )( void )
        {
            return false;
        }

        //===================================================================
        //-------------------------------------------------------------------
        /// The default constructor will initialize all the parts used
        /// in the general case.
        //-------------------------------------------------------------------
        template < typename BT >
        MemoryBufferT< BT >::MemoryBufferT( std::ios::openmode Mode,
                                            bool ParentAutoDelete )
            : buffer_type( Mode ), buffer_user_supplied( false )
        {
            AutoDelete( ParentAutoDelete );
        }

        //-------------------------------------------------------------------
        /// The default constructor will initialize all the parts used
        /// in the general case.
        //-------------------------------------------------------------------
        template < typename BT >
        MemoryBufferT< BT >::MemoryBufferT( Seeder& Seed,
                                            bool    ParentAutoDelete )
            : buffer_type( std::ios::in ), buffer_user_supplied( false )

        {
            Seed( *this ); // Give the seed routine the destination buffer
            while ( Seed( ) ) // Process input till have a full frame file
            {
                ;
            }
            AutoDelete( ParentAutoDelete );
        }

        //-------------------------------------------------------------------
        /// Be careful to release all the resources that were created
        /// for this object.
        //-------------------------------------------------------------------
        template < typename BT >
        MemoryBufferT< BT >::~MemoryBufferT( )
        {
        }

        //-------------------------------------------------------------------
        /// Filtering currently is not optimized at the this layer so
        /// this method will always return false.
        //-------------------------------------------------------------------
        template < typename BT >
        bool
        MemoryBufferT< BT >::FilterInternally( ) const
        {
            return false;
        }

        template < typename BT >
        std::string
        MemoryBufferT< BT >::str( )
        {
            INT_4U size = buffer_type::pubseekoff(
                0, std::ios_base::cur, std::ios_base::out );

            if ( size < buffer_type::str( ).length( ) )
            {
                return buffer_type::str( ).substr( 0, size );
            }
            return buffer_type::str( );
        }

        template < typename BT >
        void
        MemoryBufferT< BT >::str( const std::string& S )
        {
            buffer_user_supplied = true;
            buffer_type::str( S );
        }

        template < typename BT >
        MemoryBufferT< BT >*
        MemoryBufferT< BT >::setbuf( char_type* S, std::streamsize N )
        {
            if ( N != std::streamsize( M_BUFFER_SIZE_SYSTEM ) )
            {
                buffer_user_supplied = true;
                buffer_type::setbuf( S, N );
            }
            return this;
        }

        template < typename BT >
        void
        MemoryBufferT< BT >::buffer( )
        {
            //-----------------------------------------------------------------
            // There is no special initialization that needs to happen
            //-----------------------------------------------------------------
            if ( buffer_user_supplied == false )
            {
                //---------------------------------------------------------------
                // Allocation of the default buffer
                //---------------------------------------------------------------
                buffer_cache.reset( new char_type[ M_BUFFER_SIZE_DEFAULT ] );
                buffer_type::setbuf( buffer_cache.get( ),
                                     M_BUFFER_SIZE_DEFAULT );
            }
        }

        //-------------------------------------------------------------------
        /// \brief Perform filtering operations on the stream
        //-------------------------------------------------------------------
        template < typename BT >
        void
        MemoryBufferT< BT >::filter( const char_type* Begin,
                                     const char_type* End )
        {
        }

        template class MemoryBufferT<>;

    } // namespace Common

} // namespace FrameCPP
