//
// 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_config.h>

#include <cassert>

#include <iomanip>
#include <sstream>
#include <stdexcept>

#include <boost/pointer_cast.hpp>

#include "ldastoolsal/gpstime.hh"
#include "ldastoolsal/SimpleLogger.hh"
#include "ldastoolsal/System.hh"

#include "framecpp/Common/Description.hh"
#include "framecpp/Common/Dictionary.hh"
#include "framecpp/Common/FrameCPPServices.hh"
#include "framecpp/Common/IOStream.hh"
#include "framecpp/Common/FrameStream.hh"
#include "framecpp/Common/StreamRef.hh"
#include "framecpp/Common/Verify.hh"

#include "framecpp/Common/FrHeader.hh"
#include "framecpp/Common/FrameH.hh"
#include "framecpp/Common/FrDetector.hh"
#include "framecpp/Common/FrEndOfFile.hh"
#include "framecpp/Common/FrSH.hh"
#include "framecpp/Common/FrStatData.hh"
#include "framecpp/Common/FrTOC.hh"
#include "framecpp/Common/FrVect.hh"

#define ERROR_HANDLER( )                                                       \
    try                                                                        \
    {                                                                          \
        throw;                                                                 \
    }                                                                          \
    catch ( const std::exception& Exception )                                  \
    {                                                                          \
        setLastError( Exception.what( ) );                                     \
        throw;                                                                 \
    }                                                                          \
    catch ( ... )                                                              \
    {                                                                          \
        setLastError( "Unknwon exception" );                                   \
        throw;                                                                 \
    } //

using LDASTools::System::ErrnoMessage;

namespace
{
    //=======================================================================
    // Static logger for recursive resolver operations
    //=======================================================================
    static SimpleLogger* resolver_logger()
    {
        static SimpleLogger* instance = get_channel_logger("framecpp.resolver");
        return instance;
    }
} // anonymous namespace

#if 0
template < typename T, typename... Args >
std::unique_ptr< T >
make_unique( Args&&... args )
{
    return std::unique_ptr< T >( new T( std::forward< Args >( args )... ) );
}
#endif /* 0 */

template < typename To, typename From, typename Deleter >
std::unique_ptr< To, Deleter >
dynamic_unique_cast( std::unique_ptr< From, Deleter >&& p )
{
    if ( To* cast = dynamic_cast< To* >( p.get( ) ) )
    {
        std::unique_ptr< To, Deleter > result( cast,
                                               std::move( p.get_deleter( ) ) );
        p.release( );
        return result;
    }
    return std::unique_ptr< To, Deleter >(
        nullptr ); // or throw std::bad_cast() if you prefer
}

namespace FrameCPP
{
    namespace Common
    {
        //===================================================================
        //===================================================================
        FrameStream::FrameStream( version_type Version, bool AllowZeroVersion )
            : m_closed_state( false ), m_memory_version( Version )
        {
            if ( ( m_memory_version == 0 ) && ( !AllowZeroVersion ) )
            {
                std::ostringstream msg;

                msg << "The value of " << m_memory_version
                    << " is an invalid or unsupported frame version.";
                throw std::out_of_range( msg.str( ) );
            }

            if ( ( m_memory_version ) || ( !AllowZeroVersion ) )
            {
                frameSpecInfo( FrameSpec::SpecInfo( m_memory_version ) );
            }
        }

        void
        IFrameStream::VerifyHeader( Verify& Verifier )
        {
            if ( m_file_header.get( ) )
            {
                FrameSpec::Object* obj( dynamic_cast< FrameSpec::Object* >(
                    m_file_header.get( ) ) );

                if ( obj )
                {
                    obj->VerifyObject( Verifier, *this );
                }
            }
        }

        void
        FrameStream::frameSpecInfo( const FrameSpec::Info* Spec )
        {
            //-----------------------------------------------------------------
            // Initialize the base class information
            //-----------------------------------------------------------------
            StreamBase::frameSpecInfo( Spec );
            //-----------------------------------------------------------------
            // Initialize local information
            //-----------------------------------------------------------------
            m_dictionary.m_stream_ref = ReferenceStreamRef( );
            m_stream_ref = ReferenceStreamRef( );
        }


        void
        FrameStream::reset( )
        {
            setLastError( "" );
        }

        std::unique_ptr< FrHeader >
        IFrameStream::loadFrHeader( )
        {
            //-----------------------------------------------------------------
            // Save current stream position for restoration
            //-----------------------------------------------------------------
            const std::streampos    original_position = tellg( );
            const std::ios::iostate original_state = rdstate( );

            try
            {
                //-----------------------------------------------------------------
                // Read the first bytes to get a basic understanding of the
                // frame spec used to write the file.
                //-----------------------------------------------------------------

                // Debug logging: Track stream state before operations
                if ( logger( ) )
                {
                    // Check actual file size first
                    std::streampos current = tellg( );
                    seekg( 0, std::ios::end );
                    std::streampos fileSize = tellg( );
                    seekg( current );

                    // Investigate buffer state (FrameBufferInterface, not
                    // std::streambuf)
                    buffer_type* buf = rdbuf( );
                    bool         hasBuffer = ( buf != nullptr );

                    logger_log_debug(
                        logger( ),
                        25,
                        "loadFrHeader() initial state - position: ",
                        tellg( ),
                        ", good(): ",
                        good( ),
                        ", fail(): ",
                        fail( ),
                        ", bad(): ",
                        bad( ),
                        ", eof(): ",
                        eof( ),
                        ", file size: ",
                        fileSize,
                        ", has buffer: ",
                        hasBuffer );

                    // Additional buffer state investigation
                    if ( hasBuffer )
                    {
                        logger_log_debug(
                            logger( ),
                            25,
                            "loadFrHeader() buffer state - buffer address: ",
                            (void*)buf,
                            ", buffer type: ",
                            typeid( *buf ).name( ) );
                    }
                }

                seekg( 0 ); // To go the beginning of the file.

                // Debug logging: Track stream state after seekg(0)
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ),
                        25,
                        "loadFrHeader() after seekg(0) - position: ",
                        tellg( ),
                        ", good(): ",
                        good( ),
                        ", fail(): ",
                        fail( ),
                        ", bad(): ",
                        bad( ),
                        ", eof(): ",
                        eof( ) );
                }

                clear( ); // Clear flags

                // Debug logging: Track stream state after clear()
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ),
                        25,
                        "loadFrHeader() after clear() - position: ",
                        tellg( ),
                        ", good(): ",
                        good( ),
                        ", fail(): ",
                        fail( ),
                        ", bad(): ",
                        bad( ),
                        ", eof(): ",
                        eof( ) );
                }

                char           peekBuf[ 20 ];
                std::streampos savePos = tellg( );

                // Debug logging: Track saved position
                if ( logger( ) )
                {
                    logger_log_debug( logger( ),
                                      25,
                                      "loadFrHeader() savePos captured: ",
                                      savePos );
                }

                // Phase 1: Detailed read operation analysis
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ),
                        25,
                        "loadFrHeader() before read(20 bytes) - position: ",
                        tellg( ),
                        ", good(): ",
                        good( ),
                        ", fail(): ",
                        fail( ),
                        ", bad(): ",
                        bad( ),
                        ", eof(): ",
                        eof( ) );
                }

                read( peekBuf, 20 );

                // Debug logging: Track stream state after read()
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ),
                        25,
                        "loadFrHeader() after read(20 bytes) - position: ",
                        tellg( ),
                        ", good(): ",
                        good( ),
                        ", fail(): ",
                        fail( ),
                        ", bad(): ",
                        bad( ),
                        ", eof(): ",
                        eof( ),
                        ", gcount(): ",
                        gcount( ) );

                    // Phase 1: Check buffer state after failed read
                    buffer_type* buf = rdbuf( );
                    if ( buf )
                    {
                        logger_log_debug( logger( ),
                                          25,
                                          "loadFrHeader() buffer after read - "
                                          "buffer address: ",
                                          (void*)buf,
                                          ", buffer type: ",
                                          typeid( *buf ).name( ) );
                    }
                }

                seekg( savePos ); // Restore position

                // Debug logging: Track stream state after seekg(savePos)
                if ( logger( ) )
                {
                    std::streampos currentPos = tellg( );
                    logger_log_debug(
                        logger( ),
                        25,
                        "loadFrHeader() after seekg(savePos) - position: ",
                        currentPos,
                        ", savePos: ",
                        savePos,
                        ", positions match: ",
                        ( currentPos == savePos ),
                        ", good(): ",
                        good( ),
                        ", fail(): ",
                        fail( ),
                        ", bad(): ",
                        bad( ),
                        ", eof(): ",
                        eof( ) );
                }

                clear( ); // Clear any flags from the peek

                // Debug logging: Track final stream state before FrHeader
                // construction
                if ( logger( ) )
                {
                    std::streampos finalPos = tellg( );
                    logger_log_debug( logger( ),
                                      25,
                                      "loadFrHeader() final state before "
                                      "FrHeader() - position: ",
                                      finalPos,
                                      ", good(): ",
                                      good( ),
                                      ", fail(): ",
                                      fail( ),
                                      ", bad(): ",
                                      bad( ),
                                      ", eof(): ",
                                      eof( ) );

                    // Special warning if position is not 0
                    if ( finalPos != 0 )
                    {
                        logger_log_debug(
                            logger( ),
                            10,
                            "WARNING: Stream position is not 0 before FrHeader "
                            "construction! Position: ",
                            finalPos );
                    }
                }

                // Log the first 20 bytes for debugging
                if ( logger( ) )
                {
                    std::stringstream hex_stream;
                    for ( int i = 0; i < 20; ++i )
                    {
                        hex_stream
                            << std::hex << std::setfill( '0' ) << std::setw( 2 )
                            << ( static_cast< unsigned char >( peekBuf[ i ] ) &
                                 0xFF )
                            << " ";
                    }
                    logger_log_debug( logger( ),
                                      40,
                                      "loadFrHeader() first 20 bytes (hex): ",
                                      hex_stream.str( ) );
                }

                // Robust fix: Ensure stream is at position 0 and in good state
                // before FrHeader construction
                std::streampos currentPos = tellg( );
                if ( currentPos != 0 || !good( ) )
                {
                    if ( logger( ) )
                    {
                        logger_log_debug( logger( ),
                                          20,
                                          "loadFrHeader() fixing stream state "
                                          "- current position: ",
                                          currentPos,
                                          ", good(): ",
                                          good( ),
                                          " - forcing seek to 0" );
                    }

                    // Clear any error flags first
                    clear( );

                    // Force seek to position 0
                    seekg( 0 );

                    // Clear flags again in case seekg set any error flags
                    clear( );

                    // Verify we're now at position 0
                    std::streampos verifyPos = tellg( );
                    if ( logger( ) )
                    {
                        logger_log_debug(
                            logger( ),
                            20,
                            "loadFrHeader() after fix - position: ",
                            verifyPos,
                            ", good(): ",
                            good( ),
                            ", fail(): ",
                            fail( ),
                            ", bad(): ",
                            bad( ),
                            ", eof(): ",
                            eof( ) );
                    }

                    // If we still can't get to position 0, throw an explicit
                    // error
                    if ( verifyPos != 0 )
                    {
                        std::ostringstream msg;
                        msg << "loadFrHeader() failed to position stream at "
                               "beginning. "
                            << "Position: " << verifyPos
                            << ", good(): " << good( )
                            << ", fail(): " << fail( ) << ", bad(): " << bad( )
                            << ", eof(): " << eof( );
                        throw std::runtime_error( msg.str( ) );
                    }
                }

                //-----------------------------------------------------------------
                // Capture raw header bytes BEFORE FrHeader construction
                // The header is exactly 40 bytes, and we need the raw bytes
                // before any byte-swapping occurs for checksum seeding.
                //-----------------------------------------------------------------
                m_raw_header_bytes.reset( new char[ 40 ] );
                read( m_raw_header_bytes.get( ), 40 );

                if ( logger( ) )
                {
                    logger_log_debug( logger( ), 25,
                        "loadFrHeader() captured 40 raw header bytes for checksum seeding" );
                }

                // Seek back to beginning for FrHeader construction
                seekg( 0 );
                clear( );

                FrHeader base( *this );

                // Log FrHeader details and byte swapping detection
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ),
                        40,
                        "loadFrHeader() FrHeader created - version: ",
                        base.GetVersion( ),
                        ", byteSwapping: ",
                        base.ByteSwapping( ),
                        ", isValid: ",
                        base.IsValid( ) );
                }

                if ( !base.IsValid( ) )
                {
                    throw std::runtime_error(
                        "Not a frame file (Invalid FrHeader)." );
                }

                //-----------------------------------------------------------------
                // If we're in auto-detect mode (version 0), set up frame spec
                // from the version we just read from the file header
                //-----------------------------------------------------------------
                if ( memoryVersion( ) == 0 )
                {
                    // Set up frame specification using version from the file
                    // header
                    frameSpecInfo( FrameSpec::SpecInfo( base.GetVersion( ) ) );
                    version_stream( base.GetVersion( ) );
                    if ( logger( ) )
                    {
                        logger_log_debug(
                            logger( ),
                            40,
                            "loadFrHeader() set stream byteSwapping to: ",
                            base.ByteSwapping( ),
                            ", frameLibrary: ",
                            base.GetFrameLibraryName( ) );
                    }

                    if ( logger( ) )
                    {
                        logger_log_debug( logger( ),
                                          30,
                                          "auto-detected version ",
                                          base.GetVersion( ),
                                          " from file header" );
                    }
                }

                //-----------------------------------------------------------------
                // Read version specific portion of FrHeader
                //-----------------------------------------------------------------
                FrameSpec::ObjectInterface::unique_object_type o(
                    frameSpecInfo( )
                        .FrameObject( FrameSpec::Info::FSI_FR_HEADER )
                        ->Create( *this ) );
                std::unique_ptr< FrHeader > fr_header_object(
                    dynamic_cast< FrHeader* >( o.release( ) ) );

                //-----------------------------------------------------------------
                // Validate the header was created properly
                //-----------------------------------------------------------------

                if ( fr_header_object )
                {
                    auto           expected_bytes = fr_header_object->Bytes( );
                    std::streampos expected_pos =
                        std::streampos( expected_bytes );

                    if ( logger( ) )
                    {
                        logger_log_debug( logger( ),
                                          40,
                                          "loadFrHeader() FrHeader object "
                                          "created - expected_bytes: ",
                                          expected_bytes,
                                          ", current_position: ",
                                          tellg( ) );
                    }
                }
                else
                {
                    if ( logger( ) )
                    {
                        logger_log_debug( logger( ),
                                          40,
                                          "loadFrHeader() ERROR: failed to "
                                          "create FrHeader object" );
                    }
                }

                if ( ( !fr_header_object ) ||
                     ( tellg( ) !=
                       std::streampos( fr_header_object->Bytes( *this ) ) ) )
                {
                    std::ostringstream msg;

                    msg << "Failed to properly read the FrHeader structure.";
                    throw std::runtime_error( msg.str( ) );
                }

                //-----------------------------------------------------------------
                // Copy base header information into the version-specific header
                //-----------------------------------------------------------------
                fr_header_object->operator=( base );

                //-----------------------------------------------------------------
                // Verify the header information
                //-----------------------------------------------------------------
#if WORKING
                {
                    Verify v;
                    fr_header_object->VerifyObject( v, *this );
                }
#endif /* WORKING */

                //-----------------------------------------------------------------
                // Update internal stream properties
                //-----------------------------------------------------------------
                frameSpecInfo(
                    FrameSpec::SpecInfo( fr_header_object->GetVersion( ) ) );
                version_stream( fr_header_object->GetVersion( ) );
                byteSwapping( fr_header_object->ByteSwapping( ) );
                frameLibrary( base.GetFrameLibrary( ) );
                libraryRevision( base.GetLibraryRevision( ) );

                // Log FrHeader details and byte swapping detection
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ),
                        40,
                        "loadFrHeader() FrHeader created - version: ",
                        fr_header_object->GetVersion( ),
                        ", byteSwapping: ",
                        fr_header_object->ByteSwapping( ),
                        ", isValid: ",
                        fr_header_object->IsValid( ) );
                }

                //-----------------------------------------------------------------
                // Clear any error flags but leave stream positioned after
                // header (checksum verification expects stream at end of
                // header)
                //-----------------------------------------------------------------
                clear( );
                return fr_header_object;
            }
            catch ( ... )
            {
                //-----------------------------------------------------------------
                // Restore original stream position and state on any exception
                //-----------------------------------------------------------------
                clear( );
                seekg( original_position );
                setstate( original_state );
                throw;
            }
        }

        void
        IFrameStream::init( )
        {
            if ( logger( ) )
            {
                logger_log_debug( logger( ), 20, "IFrameStream::init() entry" );

                // Phase 2: Trace buffer initialization state
                buffer_type* buf = rdbuf( );
                if ( buf )
                {
                    std::streampos initPos = tellg( );
                    logger_log_debug( logger( ),
                                      25,
                                      "IFrameStream::init() before buffer() "
                                      "call - position: ",
                                      initPos,
                                      ", good(): ",
                                      good( ),
                                      ", fail(): ",
                                      fail( ),
                                      ", bad(): ",
                                      bad( ),
                                      ", eof(): ",
                                      eof( ),
                                      ", buffer address: ",
                                      (void*)buf,
                                      ", buffer type: ",
                                      typeid( *buf ).name( ) );
                }
            }

            //-----------------------------------------------------------------
            // Ensure buffering on the stream - THIS MIGHT BE THE ROOT CAUSE
            //-----------------------------------------------------------------
            if ( logger( ) )
            {
                logger_log_debug( logger( ),
                                  20,
                                  "IFrameStream::init() calling "
                                  "rdbuf()->buffer() - THIS IS CRITICAL" );
            }

            rdbuf( )->buffer( );

            if ( logger( ) )
            {
                // Phase 2: Check state after buffer() call - CRITICAL ANALYSIS
                std::streampos afterBufferPos = tellg( );
                logger_log_debug(
                    logger( ),
                    20,
                    "IFrameStream::init() after buffer() call - position: ",
                    afterBufferPos,
                    ", good(): ",
                    good( ),
                    ", fail(): ",
                    fail( ),
                    ", bad(): ",
                    bad( ),
                    ", eof(): ",
                    eof( ) );

                // CRITICAL: Check if the buffer() call caused EOF positioning
                if ( eof( ) || afterBufferPos == std::streampos( -1 ) )
                {
                    logger_log_debug( logger( ),
                                      10,
                                      "CRITICAL: buffer() call caused "
                                      "EOF/invalid position! Position: ",
                                      afterBufferPos );
                }
            }

            if ( logger( ) )
            {
                logger_log_debug( logger( ), 30, "calling loadFrHeader()" );
            }

            //-----------------------------------------------------------------
            // Use the new loadFrHeader() method to read the complete header
            //-----------------------------------------------------------------
            m_file_header = loadFrHeader( );

            if ( logger( ) )
            {
                logger_log_debug(
                    logger( ),
                    20,
                    "IFrameStream::init() loaded FrHeader, version=",
                    m_file_header ? m_file_header->GetVersion( ) : -1 );
            }

            if ( logger( ) )
            {
                logger_log_debug(
                    logger( ),
                    20,
                    "IFrameStream::init() complete - frameSpecInfo version=",
                    frameSpecInfo( ).Version( ),
                    ", header version=",
                    m_file_header->GetVersion( ) );
            }

            //-----------------------------------------------------------------
            // Check if we need to read FrSH structures to build class mappings
            // This is necessary when FrTOC is absent (version 3 or optional in 4-9)
            // We check by looking for FrameH registration in the stream ID map
            //-----------------------------------------------------------------

            if ( logger( ) )
            {
                logger_log_debug( logger(), 25,
                                 "IFrameStream::init() Checking if FrSH reading needed, m_stream_id_to_fsi_id size=",
                                 m_stream_id_to_fsi_id.size() );
            }

            // Find the stream class ID that should map to FSI_FRAME_H
            bool frameh_registered = false;
            for ( const auto& mapping : m_stream_id_to_fsi_id )
            {
                if ( logger( ) )
                {
                    logger_log_debug( logger(), 30,
                                     "IFrameStream::init() Mapping entry: stream class ID ",
                                     mapping.first, " -> FSI ID ", mapping.second );
                }
                if ( mapping.second == FrameSpec::Info::FSI_FRAME_H )
                {
                    frameh_registered = true;
                    break;
                }
            }

            if ( logger( ) )
            {
                logger_log_debug( logger(), 25,
                                 "IFrameStream::init() frameh_registered=", frameh_registered );
            }

            if ( !frameh_registered )
            {
                cmn_streamsize_type header_size = m_file_header->Bytes( *this );

                if ( logger( ) )
                {
                    logger_log_debug( logger(), 25,
                                     "IFrameStream::init() FrameH not registered - reading FrSH structures at position ",
                                     header_size, " (after header) to build class mappings" );
                }

                std::streampos saved_pos = tellg();

                try
                {
                    seekg( header_size ); // Position after header

                    // Read FrSH structures until we find FrameH or hit an error
                    bool found_frameh = false;
                    int max_attempts = 100; // Safety limit
                    int attempts = 0;

                    while ( attempts < max_attempts )
                    {
                        attempts++;

                        // Read the StreamRef
                        streamref_type streamref = readStreamRef();
                        if ( !streamref )
                        {
                            break;
                        }

                        // Check stream class directly - can't use GetFSIId() yet because
                        // the mappings haven't been built yet (that's why we're here!)
                        INT_2U stream_class = streamref->GetStreamClass();

                        if ( stream_class == FrameSpec::Info::FSI_FR_SH )
                        {
                            object_type obj = readObject( streamref.get() );
                            boost::shared_ptr< FrSH > frsh(
                                boost::dynamic_pointer_cast< FrSH >( obj ) );

                            if ( frsh )
                            {
                                const INT_2U id = GetClassId( frsh->name( ) );
                                if ( id )
                                {
                                    logger_log_debug( logger(), 35,
                                                     "IFrameStream::init() Registering FrSH - stream class ID ",
                                                     frsh->classId(), " -> FSI ID ", id,
                                                     " for class '", frsh->name(), "'" );
                                    m_stream_id_to_fsi_id[ frsh->classId( ) ] = id;

                                    // Check if we found FrameH (keep reading to get all FrSH entries)
                                    if ( id == FrameSpec::Info::FSI_FRAME_H )
                                    {
                                        found_frameh = true;
                                    }
                                }
                            }
                        }
                        else if ( stream_class == FrameSpec::Info::FSI_FR_SE )
                        {
                            // Skip FrSE structures
                            seekg( streamref->GetLength() - ReferenceStreamRef()->Bytes(*this), std::ios::cur );
                        }
                        else
                        {
                            // Hit a non-FrSH/FrSE structure, stop reading
                            break;
                        }
                    }

                    if ( logger( ) )
                    {
                        logger_log_debug( logger(), 25,
                                         "IFrameStream::init() Finished reading FrSH structures, found_frameh=",
                                         found_frameh, " attempts=", attempts );
                    }

                    // Restore position
                    seekg( saved_pos );
                }
                catch ( ... )
                {
                    // If reading fails, just restore position and continue
                    if ( logger( ) )
                    {
                        logger_log_debug( logger(), 20,
                                         "IFrameStream::init() Failed to read FrSH structures, continuing anyway" );
                    }
                    seekg( saved_pos );
                }
            }
        }

        //-------------------------------------------------------------------
        /// If possible, this method will load the table of contents
        /// from the stream.
        /// One example of not being able to load the table of contents
        /// is the case where the stream does not have a table of
        /// contents structure.
        //-------------------------------------------------------------------
        void
        IFrameStream::load_toc( )
        {
            if ( logger( ) )
            {
                logger_log_debug( logger( ),
                                  20,
                                  "IFrameStream::load_toc() entry, toc_loaded=",
                                  m_toc_loaded );
            }
            if ( m_toc_loaded )
            {
                if ( logger( ) )
                {
                    logger_log_debug( logger( ), 30, "loaded, returning" );
                }
                return;
            }
            //-----------------------------------------------------------------
            // One chance to do this
            //-----------------------------------------------------------------
            m_toc_loaded = true;
            if ( logger( ) )
            {
                logger_log_debug(
                    logger( ), 30, "loaded, attempting to load from stream" );
            }
            //-----------------------------------------------------------------
            // See if TOC is supported by stream frame spec
            //-----------------------------------------------------------------
            try
            {
                if ( frameSpecInfo( ).FrameObject(
                         FrameSpec::Info::FSI_FR_TOC ) ==
                     (FrameSpec::Object*)NULL )
                {
                    // Phase 3: Stream recovery state debugging after failed TOC
                    // read
                    if ( logger( ) )
                    {
                        logger_log_debug(
                            logger( ),
                            50,
                            "frame spec (expected for version 3)" );
                    }
                    if ( logger( ) )
                    {
                        logger_log_debug(
                            logger( ),
                            50,
                            "IFrameStream::load_toc() frame spec version: ",
                            GetFrHeader( ).GetVersion( ) );
                    }
                    if ( logger( ) )
                    {
                        logger_log_debug(
                            logger( ), 50, "returning from load_toc" );
                    }
                    if ( logger( ) )
                    {
                        logger_log_debug(
                            logger( ),
                            50,
                            "IFrameStream::load_toc() stream position: ",
                            static_cast< long >( tellg( ) ) );
                    }
                    if ( logger( ) )
                    {
                        logger_log_debug(
                            logger( ),
                            50,
                            "IFrameStream::load_toc() stream state good(): ",
                            good( ) );
                    }
                    if ( logger( ) )
                    {
                        logger_log_debug(
                            logger( ), 50, "state before return" );
                    }
                    return;
                }
            }
            catch ( const std::range_error& e )
            {
                //---------------------------------------------------------------
                // The frame spec does not support table of contents so just
                // return to the caller.
                //---------------------------------------------------------------
                if ( logger( ) )
                {
                    logger_log_debug( logger( ), 50, "does not support TOC" );
                }
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ),
                        50,
                        "IFrameStream::load_toc() exception message: ",
                        e.what( ) );
                }
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ), 50, "after exception, good(): ", good( ) );
                }
                if ( logger( ) )
                {
                    logger_log_debug( logger( ), 50, "exception handler" );
                }
                return;
            }
            //-----------------------------------------------------------------
            // Record the current position within the stream
            //-----------------------------------------------------------------
            const std::streampos here( tellg( ) );

            // Suspend file checksum accumulation before seeking to EOF
            // We must disable the file checksum filter during EOF operations
            // because seeking directly to EOF skips most of the file content,
            // making file checksum validation impossible.
            ChecksumState saved_file_checksum = SuspendFileChecksum( );
            if ( saved_file_checksum.had_filter && saved_file_checksum.state && logger( ) )
            {
                logger_log_debug(
                    logger( ), 25,
                    "load_toc: Suspended file checksum at state: ",
                    saved_file_checksum.state->PrettyPrint( ),
                    " (stream position: ", here, ")" );
            }

            try
            {
                //---------------------------------------------------------------
                // :TODO: Determine if the stream is rewindable
                //---------------------------------------------------------------
                //---------------------------------------------------------------
                // Get the number of bytes for the FrEndOfFile structure
                //---------------------------------------------------------------
                const std::streampos offset(
                    frameSpecInfo( )
                        .FrameObject( FrameSpec::Info::FSI_FR_END_OF_FILE )
                        ->Bytes( *this ) +
                    frameSpecInfo( )
                        .FrameObject( FrameSpec::Info::FSI_COMMON_ELEMENTS )
                        ->Bytes( *this ) );

                seekg( -offset,
                       std::ios_base::end ); // Seek to the beginning of struct
                //---------------------------------------------------------------
                // Read the common elements.
                //---------------------------------------------------------------
                FrameSpec::ObjectInterface::unique_object_type cmn_obj(
                    frameSpecInfo( )
                        .FrameObject( FrameSpec::Info::FSI_COMMON_ELEMENTS )
                        ->Create( *this ) );
                const StreamRefInterface* sri(
                    dynamic_cast< const StreamRefInterface* >(
                        cmn_obj.get( ) ) );

                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ),
                        25,
                        "load_toc: offset calculated: ",
                        static_cast< long >( offset ) );
                }
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ),
                        25,
                        "load_toc: sri pointer: ",
                        static_cast< const void* >( sri ) );
                }
                if ( sri && logger( ) )
                {
                    logger_log_debug(
                        logger( ),
                        25,
                        "load_toc: sri->GetLength(): ",
                        sri->GetLength( ) );
                }

                if ( ( sri == NULL ) ||
                     ( sri->GetLength( ) !=
                       ( StreamRefInterface::length_type )( offset ) ) )
                {
                    //-------------------------------------------------------------
                    // This file appears to be corrupted.
                    //-------------------------------------------------------------
                    if ( logger( ) )
                    {
                        logger_log_debug(
                            logger( ),
                            25,
                            "load_toc: VALIDATION FAILED - sri==NULL: ",
                            ( sri == NULL ),
                            ", sri->GetLength()=",
                            ( sri ? sri->GetLength( ) : 0 ),
                            ", offset=",
                            static_cast< long >( offset ) );
                    }
                    throw std::runtime_error( "Missing FrEndOfFile structure" );
                }
                //---------------------------------------------------------------
                // Create object and place into smart pointer for auto cleanup
                //---------------------------------------------------------------
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ), 25, "load_toc: creating FrEndOfFile object" );
                }

                FrameSpec::ObjectInterface::unique_object_type eof_obj;
                try
                {
                    eof_obj.reset(
                        frameSpecInfo( )
                            .FrameObject( FrameSpec::Info::FSI_FR_END_OF_FILE )
                            ->Create( *this ) );
                }
                catch ( const VerifyException& e )
                {
                    // Checksum errors can occur when loading FrEndOfFile for TOC access
                    // because the file checksum validation fails when most of the file content
                    // is skipped during TOC-based seeking. We'll read seekTOC directly and continue.
                    if ( e.ErrorCode( ) == VerifyException::CHECKSUM_ERROR )
                    {
                        if ( logger( ) )
                        {
                            logger_log_debug(
                                logger( ),
                                25,
                                "load_toc: FrEndOfFile Create() threw checksum error (reading seekTOC directly): ",
                                e.what( ) );
                        }
                        // Re-seek to start of FrEndOfFile data (after StreamRef)
                        seekg( -offset, std::ios_base::end );
                        // Read common elements again to skip past them
                        FrameSpec::ObjectInterface::unique_object_type cmn_obj2(
                            frameSpecInfo( )
                                .FrameObject( FrameSpec::Info::FSI_COMMON_ELEMENTS )
                                ->Create( *this ) );

                        // Read FrEndOfFile fields directly to get seekTOC
                        // Format depends on version
                        unsigned int vers = GetFrHeader( ).GetVersion( );

                        // Read nFrames (INT_4U, always present)
                        INT_4U nframes_val;
                        *this >> nframes_val;

                        // Read nBytes (INT_8U for v5+, INT_4U for v3-4)
                        INT_8U nbytes_val;
                        if ( vers >= 5 )
                        {
                            *this >> nbytes_val;
                        }
                        else
                        {
                            INT_4U nbytes_v3;
                            *this >> nbytes_v3;
                            nbytes_val = nbytes_v3;
                        }

                        // Read seekTOC (INT_8U for v5+, INT_4U for v4, not present for v3)
                        INT_8U seekTOC_val = 0;
                        if ( vers >= 5 )
                        {
                            *this >> seekTOC_val;
                        }
                        else if ( vers >= 4 )
                        {
                            INT_4U seekTOC_v4;
                            *this >> seekTOC_v4;
                            seekTOC_val = seekTOC_v4;
                        }

                        if ( logger( ) )
                        {
                            logger_log_debug(
                                logger( ),
                                25,
                                "load_toc: Read seekTOC directly: ",
                                seekTOC_val );
                        }

                        // Now seek to TOC if seekTOC is non-zero
                        if ( seekTOC_val )
                        {
                            seekg( -static_cast< std::streamoff >( seekTOC_val ),
                                   std::ios::end );
                            // Continue with TOC loading (fall through to TOC reading code below)
                            // We need to jump to the TOC reading section, so we'll duplicate it here
                            FrameSpec::ObjectInterface::unique_object_type ref_obj(
                                frameSpecInfo( )
                                    .FrameObject(
                                        FrameSpec::Info::FSI_COMMON_ELEMENTS )
                                    ->Create( *this ) );
                            auto frame_object = frameSpecInfo( ).FrameObject(
                                FrameSpec::Info::FSI_FR_TOC );
                            if ( logger( ) )
                            {
                                logger_log_debug(
                                    logger( ),
                                    20,
                                    "load_toc: FrameObject factory returned=",
                                    static_cast< const void* >( frame_object ) );
                            }
                            FrameSpec::ObjectInterface::unique_object_type toc_obj(
                                frame_object->Create( *this ) );
                            if ( toc_obj )
                            {
                                m_toc.reset( dynamic_cast< FrTOC* >( toc_obj.release( ) ) );
                            }
                        }
                        // Restore stream position before returning
                        seekg( here );
                        if ( logger( ) )
                        {
                            logger_log_debug(
                                logger( ),
                                25,
                                "load_toc: Restored stream position after checksum error to: ",
                                tellg( ) );
                        }
                        return; // Exit load_toc after handling checksum error
                    }
                    else
                    {
                        throw;
                    }
                }
                catch ( const std::exception& e )
                {
                    if ( logger( ) )
                    {
                        logger_log_debug(
                            logger( ),
                            25,
                            "load_toc: FrEndOfFile Create() threw exception: ",
                            e.what( ) );
                    }
                    throw;
                }
                seekg(here);  // Restore stream position after reading FrEndOfFile

                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ),
                        25,
                        "load_toc: FrEndOfFile object created, address=",
                        static_cast< const void* >( eof_obj.get( ) ) );
                }
                //---------------------------------------------------------------
                // Transform into a form that can be used by generic interface
                //---------------------------------------------------------------
                const FrEndOfFile* eof(
                    dynamic_cast< const FrEndOfFile* >( eof_obj.get( ) ) );
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ),
                        25,
                        "load_toc: FrEndOfFile cast result, eof=",
                        static_cast< const void* >( eof ) );
                }
                if ( eof )
                {
                    if ( logger( ) )
                    {
                        logger_log_debug(
                            logger( ), 25, "load_toc: eof->SeekTOC()=", eof->SeekTOC( ) );
                    }
                    if ( eof->SeekTOC( ) )
                    {
                        seekg( -( eof->SeekTOC( ) ), std::ios::end );
                        //-----------------------------------------------------------
                        // Read the reference
                        //-----------------------------------------------------------
                        FrameSpec::ObjectInterface::unique_object_type ref_obj(
                            frameSpecInfo( )
                                .FrameObject(
                                    FrameSpec::Info::FSI_COMMON_ELEMENTS )
                                ->Create( *this ) );
                        // Enhanced TOC object lifecycle tracing
                        if ( logger( ) )
                        {
                            logger_log_debug(
                                logger( ),
                                15,
                                "via frameSpecInfo().FrameObject()" );
                        }
                        auto frame_object = frameSpecInfo( ).FrameObject(
                            FrameSpec::Info::FSI_FR_TOC );
                        if ( logger( ) )
                        {
                            logger_log_debug(
                                logger( ),
                                20,
                                "load_toc: FrameObject factory returned=",
                                static_cast< const void* >( frame_object ) );
                        }

                        if ( logger( ) )
                        {
                            logger_log_debug(
                                logger( ), 20, "Create(*this) on factory" );
                        }
                        FrameSpec::ObjectInterface::unique_object_type toc_obj(
                            frame_object->Create( *this ) );
                        if ( logger( ) )
                        {
                            logger_log_debug(
                                logger( ),
                                15,
                                "load_toc: TOC object created, address=",
                                static_cast< void* >( toc_obj.get( ) ) );
                        }

                        if ( toc_obj )
                        {
                            if ( logger( ) )
                            {
                                auto const& toc_obj_ref = *toc_obj.get( );
                                logger_log_debug(
                                    logger( ),
                                    15,
                                    "load_toc: Created object type=",
                                    typeid( toc_obj_ref ).name( ) );
                            }

                            // Check if it's a FrTOC before dynamic_cast
                            FrTOC* raw_toc_check =
                                dynamic_cast< FrTOC* >( toc_obj.get( ) );
                            if ( logger( ) )
                            {
                                logger_log_debug(
                                    logger( ),
                                    15,
                                    "load_toc: Pre-cast FrTOC check result=",
                                    static_cast< void* >( raw_toc_check ) );
                            }

                            if ( raw_toc_check )
                            {
                                if ( logger( ) )
                                {
                                    logger_log_debug(
                                        logger( ),
                                        10,
                                        "nFrame()=",
                                        raw_toc_check->nFrame( ) );
                                }

                                // Use available Common::FrTOC methods for
                                // debugging
                                if ( logger( ) )
                                {
                                    logger_log_debug(
                                        logger( ),
                                        15,
                                        "load_toc: RAW TOC validation - nSH()=",
                                        raw_toc_check->nSH( ),
                                        " dt().size()=",
                                        raw_toc_check->dt( ).size( ) );
                                }
                                if ( logger( ) )
                                {
                                    logger_log_debug(
                                        logger( ),
                                        15,
                                        "load_toc: RAW TOC object address=",
                                        static_cast< const void* >(
                                            raw_toc_check ) );
                                }
                            }
                        }

                        if ( logger( ) )
                        {
                            logger_log_debug(
                                logger( ),
                                20,
                                "load_toc: About to call m_toc.reset()" );
                        }
                        m_toc.reset( dynamic_cast< FrTOC* >( toc_obj.release( ) ) );
                        if ( logger( ) )
                        {
                            logger_log_debug(
                                logger( ), 15, "completed, checking result" );
                        }

                        if ( m_toc )
                        {
                            if ( logger( ) )
                            {
                                logger_log_debug( logger( ),
                                                  10,
                                                  "successfully - nFrame()=",
                                                  m_toc->nFrame( ) );
                            }

                            // Use available Common::FrTOC methods for debugging
                            if ( logger( ) )
                            {
                                logger_log_debug(
                                    logger( ),
                                    15,
                                    "load_toc: M_TOC validation - nSH()=",
                                    m_toc->nSH( ),
                                    " dt().size()=",
                                    m_toc->dt( ).size( ) );
                            }
                            if ( logger( ) )
                            {
                                logger_log_debug(
                                    logger( ),
                                    15,
                                    "load_toc: M_TOC object address=",
                                    static_cast< const void* >(
                                        m_toc.get( ) ) );
                            }

                            // Verify the data is the same as what we saw in
                            // raw_toc_check
                            if ( logger( ) )
                            {
                                logger_log_debug(
                                    logger( ), 20, "raw and m_toc" );
                            }

                            //---------------------------------------------------------
                            // Successful with the dynamic cast so m_toc is now
                            // responsible for releasing the memory resouces.
                            //---------------------------------------------------------
                            if ( logger( ) )
                            {
                                logger_log_debug(
                                    logger( ), 20, "toc_obj ownership" );
                            }
                            toc_obj.release( );
                            //---------------------------------------------------------
                            // Extract mapping information
                            //---------------------------------------------------------
                            for ( INT_4U cur = 0, last = m_toc->nSH( );
                                  cur != last;
                                  ++cur )
                            {
                                const INT_2U fsi_id =
                                    GetClassId( m_toc->SHname( cur ) );
                                if ( fsi_id )
                                {
                                    m_stream_id_to_fsi_id[ m_toc->SHid(
                                        cur ) ] = fsi_id;
                                }
                            }
                        }
                    }
                }
            }
            catch ( ... )
            {
                seekg( here );
                throw;
            }
            //-----------------------------------------------------------------
            // Restore file position and file checksum state
            //-----------------------------------------------------------------
            seekg( here );
            if ( logger( ) )
            {
                logger_log_debug(
                    logger( ), 20, "successfully, restored file position" );
            }

            // Resume file checksum accumulation from saved state
            ResumeFileChecksum( std::move( saved_file_checksum ) );

            CheckSumFilter* resumed_filter = GetCheckSumFile();
            if ( resumed_filter && resumed_filter->GetChecksum() && logger( ) )
            {
                logger_log_debug(
                    logger( ), 25,
                    "load_toc: Resumed file checksum at: ",
                    resumed_filter->GetChecksum()->PrettyPrint( ),
                    " (stream position: ", here, ")" );
            }

            // Phase 1b: Frame count debug logging to trace nframe propagation
            if ( m_toc )
            {
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ),
                        20,
                        "IFrameStream::load_toc() TOC frame count: nFrame()=",
                        m_toc->nFrame( ) );
                }
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ),
                        30,
                        "IFrameStream::load_toc() TOC object address: ",
                        static_cast< const void* >( m_toc.get( ) ) );
                }
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ),
                        30,
                        "IFrameStream::load_toc() TOC validation: nSH=",
                        m_toc->nSH( ),
                        ", dt.size()=",
                        m_toc->dt( ).size( ) );
                }
            }
            else
            {
                if ( logger( ) )
                {
                    logger_log_debug( logger( ), 20, "is null after loading!" );
                }
            }
        }

        void
        IFrameStream::reset( )
        {
            Cleanup( );
            FrameStream::reset( );
        }

        //-------------------------------------------------------------------

        //===================================================================
        //===================================================================
        IFrameStream::IFrameStream( buffer_type* Buffer, INT_2U Version )
            : FrameStream( Version, true /* AllowZeroVersion */ ),
              IStream( Buffer ), m_toc_loaded( false ),
              m_reading_frame_subset( false ),
              m_next_frame_index( 0 )
        {
            if ( logger( ) )
            {
                logger_log_debug(
                    logger( ),
                    10,
                    "IFrameStream::IFrameStream() constructor entry, version=",
                    Version );

                // Phase 2: Trace initial buffer state in constructor
                buffer_type* buf = rdbuf( );
                if ( buf )
                {
                    std::streampos constructorPos = tellg( );
                    logger_log_debug( logger( ),
                                      25,
                                      "IFrameStream constructor - initial "
                                      "buffer state - position: ",
                                      constructorPos,
                                      ", good(): ",
                                      good( ),
                                      ", fail(): ",
                                      fail( ),
                                      ", bad(): ",
                                      bad( ),
                                      ", eof(): ",
                                      eof( ),
                                      ", buffer address: ",
                                      (void*)buf,
                                      ", buffer type: ",
                                      typeid( *buf ).name( ) );
                }
            }
            try
            {
                init( );
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ), 10, "initialized successfully" );
                }
            }
            catch ( ... )
            {
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ), 10, "during init - cleaning up" );
                }
                Cleanup( );
                throw;
            }
        }

        IFrameStream::IFrameStream( bool         AutoDelete,
                                    buffer_type* Buffer,
                                    INT_2U       Version )
            : FrameStream( Version, true /* AllowZeroVersion */ ),
              IStream( Buffer, AutoDelete ), m_toc_loaded( false ),
              m_reading_frame_subset( false ),
              m_next_frame_index( 0 )
        {
            if ( logger( ) )
            {
                logger_log_debug( logger( ),
                                  10,
                                  "entry, autoDelete=",
                                  AutoDelete,
                                  " version=",
                                  Version );
            }
            try
            {
                init( );
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ), 10, "initialized successfully" );
                }
            }
            catch ( ... )
            {
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ), 10, "during init - cleaning up" );
                }
                Cleanup( );
                throw;
            }
        }

        void
        IFrameStream::Cleanup( )
        {
            IStream::Cleanup( );
        }

        IFrameStream::ptr_struct_base_type
        IFrameStream::Next( object_type::element_type* Obj )
        {
            ptr_struct_base_type next( IStream::Next( Obj ) );

            if ( m_logNextPtr && next )
            {
                addRecursiveDependant( next );
            }
            return next;
        }

        IFrameStream::object_type
        IFrameStream::Read( )
        {
            object_type retval;

            //-----------------------------------------------------------------
            // Establish that the stream is in a good state.
            //-----------------------------------------------------------------
            if ( !good( ) )
            {
                return retval;
            }

            //-----------------------------------------------------------------
            // Establish the start of the object being read
            //-----------------------------------------------------------------
            boost::shared_ptr< StreamRefInterface > streamref;
            while ( 1 )
            {
                streamref = readStreamRef( );
                if ( !streamref )
                {
                    // Reached the end of file.
                    return retval;
                }
                //---------------------------------------------------------------
                /// \todo Check if read goes beyond the end of the file
                //---------------------------------------------------------------
                //---------------------------------------------------------------
                // Transform from stream class to FSI class id
                //---------------------------------------------------------------
                const INT_2U sid = streamref->GetStreamClass( );

                try
                {
                    // Testing for exception
                    GetFSIId( sid );
                }
                catch ( ... )
                {
                    //-------------------------------------------------------------
                    // Seek to the end of this unknown class
                    //-------------------------------------------------------------

                    seekg( streamref->GetLength( ) -
                               ReferenceStreamRef( )->Bytes( *this ),
                           std::ios::cur );
                    //-------------------------------------------------------------
                    // Rethrow the exception
                    //-------------------------------------------------------------
                    throw;
                }
                //---------------------------------------------------------------
                // Add information to the appropriate databases.
                //---------------------------------------------------------------
                retval = readObject( streamref.get( ) );
                if ( retval )
                {
                    if ( ( retval->GetClass( ) ==
                           FrameSpec::Info::FSI_FR_SH ) ||
                         ( retval->GetClass( ) == FrameSpec::Info::FSI_FR_SE ) )
                    {
                        continue;
                    }
                    m_dictionary.Ref( streamref, retval );
                }
                break;
            }

            //-----------------------------------------------------------------
            // Report back to the caller
            //-----------------------------------------------------------------
            return retval;
        }

        IFrameStream::object_type
        IFrameStream::ReadDetector( const std::string& Name )
        {
            static const char* method =
                "FrameCPP::Common::IFrameStream::ReadDetector";

            //-----------------------------------------------------------------
            // Ensure the table of contents is a usable.
            //-----------------------------------------------------------------
            const FrTOC* toc = GetTOC( );

            if ( toc == (FrTOC*)NULL )
            {
                std::ostringstream msg;

                msg << "The method " << method
                    << " requires a non-NULL table of contents";

                throw std::runtime_error( msg.str( ) );
            }
            //-----------------------------------------------------------------
            // Locate it in the table of contents
            //-----------------------------------------------------------------
            const FrTOC::cmn_position_type p( toc->positionDetector( Name ) );

            if ( p <= 0 )
            {
                std::ostringstream msg;

                msg << "The detector named " << Name
                    << " is not indexed in the table of contents for random "
                       "access";
                throw std::runtime_error( msg.str( ) );
            }
            //-----------------------------------------------------------------
            // Read the object off the stream
            //-----------------------------------------------------------------
            seekg( p, std::ios::beg );
            object_type retval( Read( ) );

            return retval;
        }

        IFrameStream::object_type
        IFrameStream::ReadFrameN( INT_4U FrameIndex, bool Decompress )
        try
        {
            if ( logger( ) )
            {
                logger_log_debug(
                    logger( ),
                    20,
                    "IFrameStream::ReadFrameN() entry, frameIndex=",
                    FrameIndex,
                    " decompress=",
                    Decompress );
            }
            //-----------------------------------------------------------------
            // Prep for errors
            //-----------------------------------------------------------------
            reset( );

            //-----------------------------------------------------------------
            // Advance to the requested frame within the stream
            //-----------------------------------------------------------------
            object_type retval;

            if ( logger( ) )
            {
                logger_log_debug(
                    logger( ),
                    30,
                    "IFrameStream::ReadFrameN() advancing to frame" );
            }
            retval = advanceToFrame( FrameIndex );
            if ( logger( ) )
            {
                logger_log_debug(
                    logger( ),
                    30,
                    "IFrameStream::ReadFrameN() advanced to frame, result: ",
                    ( retval ? "valid" : "null" ) );
            }
            //-----------------------------------------------------------------
            // Read until all references are resolved or until FrEndOfFrame
            //   is reached
            //-----------------------------------------------------------------
            if ( logger( ) )
            {
                logger_log_debug( logger( ), 30, "recursive dependencies" );
            }
            readRecursive( FrameSpec::Info::FSI_FR_END_OF_FRAME, Decompress );
            //-----------------------------------------------------------------
            // Resolve all PTR_STRUCT pointers
            //-----------------------------------------------------------------
            if ( logger( ) )
            {
                logger_log_debug( logger( ), 30, "resolving PTR_STRUCT pointers" );
            }
            Resolve();
            //-----------------------------------------------------------------
            // Return the results
            //-----------------------------------------------------------------
            if ( logger( ) )
            {
                logger_log_debug(
                    logger( ),
                    20,
                    "IFrameStream::ReadFrameN() completed successfully" );
            }
            return retval;
        }
        catch ( ... )
        {
            if ( logger( ) )
            {
                logger_log_debug( logger( ), 10, "exception, handling error" );
            }
            ERROR_HANDLER( );
        }

        IFrameStream::object_type
        IFrameStream::ReadFrStatData( INT_8U Position )
        {
            //-----------------------------------------------------------------
            // Read the FrStatData structure
            //-----------------------------------------------------------------
            seekg( Position, std::ios::beg );

            object_type retval( Read( ) );

            if ( ( !retval ) ||
                 ( retval->GetClass( ) != FrameSpec::Info::FSI_FR_STAT_DATA ) )
            {
                //---------------------------------------------------------------
                // This is the case where no FrStatData structure existed
                //---------------------------------------------------------------
                if ( retval )
                {
                    GetDictionary( ).Remove( retval );
                    retval.reset( );
                }
                return retval;
            }
            //-----------------------------------------------------------------
            /// \todo Need to add support for reading the FrDetector for
            ///       FrStatData structures where the FrStatData is before
            ///       any FrameH structures.
            //-----------------------------------------------------------------
            //-----------------------------------------------------------------
            // Back up to the beginning of the frame
            //-----------------------------------------------------------------
            INT_4U       cur = 0;
            const FrTOC* toc = GetTOC( );

            for ( INT_4U last = toc->nFrame( );
                  ( cur != last ) && ( Position < toc->positionH( cur ) );
                  ++cur )
                ;
            if ( cur > 0 )
            {
                --cur;
            }
            seekg( toc->positionH( cur ), std::ios::beg );
            //-----------------------------------------------------------------
            // Read the additional pieces needed
            //-----------------------------------------------------------------
            readRecursive( FrameSpec::Info::FSI_FR_NULL );
            //-----------------------------------------------------------------
            // Link the pieces
            //-----------------------------------------------------------------
            Resolve( );
            //-----------------------------------------------------------------
            //  Give the user the the information.
            //-----------------------------------------------------------------
            return retval;
        }

        INT_4U
        IFrameStream::ReadFrStatData( const std::string& NamePattern,
                                      const std::string& DetectorPattern,
                                      const LDASTools::AL::GPSTime& StartTime,
                                      const LDASTools::AL::GPSTime& EndTime,
                                      const INT_4U                  Version,
                                      FrStatData::Query& QueryResults )
        {
            QueryResults.Reset( *this );
            QueryResults.Add( NamePattern, StartTime, EndTime, Version );
            return QueryResults.size( );
        }

        IFrameStream::object_type
        IFrameStream::readFrameHSubset( INT_4U Frame, INT_4U ElementMask )
        try
        {
            //-----------------------------------------------------------------
            // Prep for errors
            //-----------------------------------------------------------------
            reset( );
            //-----------------------------------------------------------------
            // Advance to the requested frame within the stream
            //-----------------------------------------------------------------
            object_type retval;

            retval = advanceToFrame( Frame );
            //-----------------------------------------------------------------
            // Pair down what should be read for the FrameH structure
            //-----------------------------------------------------------------
            {
                boost::shared_ptr< FrameH > frameh(
                    boost::dynamic_pointer_cast< FrameH >( retval ) );
                if ( frameh )
                {
                    frameh->readSubset( *this, ElementMask );
                }
            }
            //-----------------------------------------------------------------
            // Read until all references are resolved or until FrEndOfFrame
            //   is reached
            //-----------------------------------------------------------------
            m_reading_frame_subset = true;
            readRecursive( FrameSpec::Info::FSI_FR_END_OF_FRAME );
            m_reading_frame_subset = false;
            //-----------------------------------------------------------------
            // Return the results
            //-----------------------------------------------------------------
            return retval;
        }
        catch ( ... )
        {
            ERROR_HANDLER( );
        }

        IFrameStream::object_type
        IFrameStream::readFrAdcData( INT_4U Frame, const std::string& Channel )
        {
            return read_fr_struct< FrameSpec::Info::FSI_FR_ADC_DATA,
                                   const std::string& >( Frame, Channel, true );
        }

        IFrameStream::object_type
        IFrameStream::readFrAdcData( INT_4U Frame, INT_4U Channel )
        {
            return read_fr_struct< FrameSpec::Info::FSI_FR_ADC_DATA >(
                Frame, Channel, true );
        }

        IFrameStream::object_type
        IFrameStream::readFrAdcStruct( INT_4U             Frame,
                                       const std::string& Channel )
        {
            return read_fr_struct< FrameSpec::Info::FSI_FR_ADC_DATA >(
                Frame, Channel, false );
        }

        std::unique_ptr< FrEndOfFile >
        IFrameStream::readFrEndOfFile( )
        {
            //---------------------------------------------------------------
            // Get the number of bytes for the FrEndOfFile structure
            //---------------------------------------------------------------
            const std::streampos offset(
                frameSpecInfo( )
                    .FrameObject( FrameSpec::Info::FSI_FR_END_OF_FILE )
                    ->Bytes( *this ) +
                frameSpecInfo( )
                    .FrameObject( FrameSpec::Info::FSI_COMMON_ELEMENTS )
                    ->Bytes( *this ) );

            seekg( -offset,
                   std::ios_base::end ); // Seek to the beginning of struct
            //---------------------------------------------------------------
            // Read the common elements.
            //---------------------------------------------------------------
            FrameSpec::ObjectInterface::unique_object_type cmn_obj(
                frameSpecInfo( )
                    .FrameObject( FrameSpec::Info::FSI_COMMON_ELEMENTS )
                    ->Create( *this ) );
            const StreamRefInterface* sri(
                dynamic_cast< const StreamRefInterface* >( cmn_obj.get( ) ) );

            if ( ( sri == NULL ) ||
                 ( sri->GetLength( ) !=
                   ( StreamRefInterface::length_type )( offset ) ) )
            {
                //-------------------------------------------------------------
                // This file appears to be corrupted.
                //-------------------------------------------------------------
                throw std::runtime_error( "Missing FrEndOfFile structure" );
            }
            //---------------------------------------------------------------
            // Create object and place into smart pointer for auto cleanup
            //---------------------------------------------------------------
            FrameSpec::ObjectInterface::unique_object_type eof_obj(
                frameSpecInfo( )
                    .FrameObject( FrameSpec::Info::FSI_FR_END_OF_FILE )
                    ->Create( *this ) );
            std::unique_ptr< FrEndOfFile > retval;
            FrEndOfFile*                   eof_ptr =
                dynamic_cast< FrEndOfFile* >( eof_obj.get( ) );
            if ( eof_ptr )
            {
                retval.reset( eof_ptr );
                eof_obj.release( );
            }
            return retval;
        }

        IFrameStream::object_type
        IFrameStream::readFrAdcStruct( INT_4U Frame, INT_4U Channel )
        {
            return read_fr_struct< FrameSpec::Info::FSI_FR_ADC_DATA >(
                Frame, Channel, false );
        }

        IFrameStream::object_type
        IFrameStream::readFrEvent( INT_4U Frame, const std::string& Channel )
        {
            return read_fr_struct< FrameSpec::Info::FSI_FR_EVENT >(
                Frame, Channel, true );
        }

        IFrameStream::object_type
        IFrameStream::readFrEventStruct( INT_4U             Frame,
                                         const std::string& Channel )
        {
            return read_fr_struct< FrameSpec::Info::FSI_FR_EVENT >(
                Frame, Channel, false );
        }

        IFrameStream::object_type
        IFrameStream::readFrEvent( const std::string&   EventType,
                                   fr_event_offset_type Index )
        {
            return read_indexed_fr_struct< FrameSpec::Info::FSI_FR_EVENT >(
                EventType, Index, true );
        }

        IFrameStream::object_type
        IFrameStream::readFrProcData( INT_4U Frame, const std::string& Channel )
        {
            return read_fr_struct< FrameSpec::Info::FSI_FR_PROC_DATA >(
                Frame, Channel, true );
        }

        IFrameStream::object_type
        IFrameStream::readFrProcData( INT_4U Frame, INT_4U Channel )
        {
            return read_fr_struct< FrameSpec::Info::FSI_FR_PROC_DATA >(
                Frame, Channel, true );
        }

        IFrameStream::object_type
        IFrameStream::readFrProcStruct( INT_4U             Frame,
                                        const std::string& Channel )
        {
            return read_fr_struct< FrameSpec::Info::FSI_FR_PROC_DATA >(
                Frame, Channel, false );
        }

        IFrameStream::object_type
        IFrameStream::readFrProcStruct( INT_4U Frame, INT_4U Channel )
        {
            return read_fr_struct< FrameSpec::Info::FSI_FR_PROC_DATA >(
                Frame, Channel, false );
        }

        IFrameStream::object_type
        IFrameStream::readFrSerData( INT_4U Frame, const std::string& Channel )
        {
            return read_fr_struct< FrameSpec::Info::FSI_FR_SER_DATA >(
                Frame, Channel, true );
        }

        IFrameStream::object_type
        IFrameStream::readFrSerStruct( INT_4U             Frame,
                                       const std::string& Channel )
        {
            return read_fr_struct< FrameSpec::Info::FSI_FR_SER_DATA >(
                Frame, Channel, false );
        }

        IFrameStream::object_type
        IFrameStream::readFrSimData( INT_4U Frame, const std::string& Channel )
        {
            return read_fr_struct< FrameSpec::Info::FSI_FR_SIM_DATA >(
                Frame, Channel, true );
        }

        IFrameStream::object_type
        IFrameStream::readFrSimEvent( INT_4U Frame, const std::string& Channel )
        {
            return read_fr_struct< FrameSpec::Info::FSI_FR_SIM_EVENT >(
                Frame, Channel, true );
        }

        IFrameStream::object_type
        IFrameStream::readFrSimEventStruct( INT_4U             Frame,
                                            const std::string& Channel )
        {
            return read_fr_struct< FrameSpec::Info::FSI_FR_SIM_EVENT >(
                Frame, Channel, false );
        }

        IFrameStream::object_type
        IFrameStream::readFrSimEvent( const std::string&   EventType,
                                      fr_event_offset_type Index )
        {
            return read_indexed_fr_struct< FrameSpec::Info::FSI_FR_SIM_EVENT >(
                EventType, Index, true );
        }

        std::unique_ptr< FrTOC >
        IFrameStream::readFrTOCHeader( FrEndOfFile::seekTOC_cmn_type Offset )
        {
            if ( !Offset )
            {
                return ( std::unique_ptr< FrTOC >( ) );
            }
            seekg( -( Offset ), std::ios::end );
            //-----------------------------------------------------------
            // Read the reference
            //-----------------------------------------------------------
            FrameSpec::ObjectInterface::unique_object_type ref_obj(
                frameSpecInfo( )
                    .FrameObject( FrameSpec::Info::FSI_COMMON_ELEMENTS )
                    ->Create( *this ) );
            FrameSpec::ObjectInterface::unique_object_type toc_obj(
                frameSpecInfo( )
                    .FrameObject( FrameSpec::Info::FSI_FR_TOC )
                    ->Create( ) );
            FrTOC* toc_ptr = dynamic_cast< FrTOC* >( toc_obj.get( ) );
            if ( toc_ptr )
            {
                toc_obj.release( );
            }
            auto retval = std::unique_ptr< FrTOC >( toc_ptr );
            retval->loadHeader( *this );
            return retval;
        }

        IFrameStream::object_type
        IFrameStream::readNextFrame( )
        try
        {
            //-----------------------------------------------------------------
            // Prep for errors
            //-----------------------------------------------------------------
            reset( );
            //-----------------------------------------------------------------
            // Advance to the requested frame within the stream
            //-----------------------------------------------------------------
            object_type retval;

            retval = advanceToFrame( m_next_frame_index );
            //-----------------------------------------------------------------
            // Read until all references are resolved or until FrEndOfFrame
            //   is reached
            //-----------------------------------------------------------------
            readRecursive( FrameSpec::Info::FSI_FR_END_OF_FRAME );
            ++m_next_frame_index;
            //-----------------------------------------------------------------
            // Return the results
            //-----------------------------------------------------------------
            return retval;
        }
        catch ( ... )
        {
            ERROR_HANDLER( );
        }

        IFrameStream::object_type
        IFrameStream::readFrSimStruct( INT_4U             Frame,
                                       const std::string& Channel )
        {
            return read_fr_struct< FrameSpec::Info::FSI_FR_SIM_DATA >(
                Frame, Channel, false );
        }

        IFrameStream::object_type
        IFrameStream::advanceToFrame( INT_4U Frame )
        {
            object_type retval;

            const FrTOC* toc = (const FrTOC*)NULL;

            try
            {
                toc = dynamic_cast< const FrTOC* >( GetTOC( ) );
            }
            catch ( const std::runtime_error& Error )
            {
                /* Ignore runtime error of no TOC */
            }

            //-----------------------------------------------------------------
            // Position within the file where the frame starts
            //-----------------------------------------------------------------
            if ( toc )
            {
                //---------------------------------------------------------------
                // Fast seek implementation via table of contents.
                //---------------------------------------------------------------
                const std::streampos offset = toc->positionH( Frame );

                seekg( offset, std::ios::beg );
                retval = Read( );
                while (
                    good( ) && retval &&
                    ( ( retval->GetClass( ) == FrameSpec::Info::FSI_FR_SE ) ||
                      ( retval->GetClass( ) == FrameSpec::Info::FSI_FR_SH ) ) )
                {
                    //-------------------------------------------------------------
                    // Ignore structure definition components
                    //-------------------------------------------------------------
                    retval = Read( );
                }
                if ( retval->GetClass( ) != FrameSpec::Info::FSI_FRAME_H )
                {
                    std::ostringstream msg;

                    msg << "The object at location " << offset
                        << " is not a FrameH structure";
                    throw std::runtime_error( msg.str( ) );
                }
            }
            else
            {
                if ( Frame > m_next_frame_index )
                {
                    std::ostringstream msg;

                    msg << "Unable to rewind to frame from "
                        << m_next_frame_index << " to " << Frame << std::endl;
                    throw std::range_error( msg.str( ) );
                }

                boost::shared_ptr< StreamRefInterface > streamref;

                while ( m_next_frame_index <= Frame )
                {
                    streamref = readStreamRef( );

                    if ( !streamref )
                    {
                        std::ostringstream msg;

                        msg << "Request for frame " << Frame
                            << " exceeds the range of 0 through "
                            << ( m_next_frame_index - 1 );
                        throw std::out_of_range( msg.str( ) );
                    }
                    else
                    {
                        if ( GetFSIId( streamref->GetStreamClass( ) ) ==
                             FrameSpec::Info::FSI_FRAME_H )
                        {
                            ++m_next_frame_index;
                            retval = readObject( streamref.get( ) );
                            if ( m_next_frame_index > Frame )
                            {
                                break;
                            }
                            else
                            {
                                continue;
                            }
                        }
                        //-----------------------------------------------------------
                        // Check for dictionary information
                        //-----------------------------------------------------------
                        if ( ( streamref->GetStreamClass( ) == FrameSpec::Info::FSI_FR_SH ) ||
                             ( streamref->GetStreamClass( ) == FrameSpec::Info::FSI_FR_SE ) )
                        {
                            //---------------------------------------------------------
                            // This object contains dictionary info so need to
                            // capture for proper decoding of stream
                            //---------------------------------------------------------
                            readObject( streamref.get( ) );
                            continue;
                        }
                        //-----------------------------------------------------------
                        // Skip the object
                        //-----------------------------------------------------------
                        seekg( streamref->GetLength() -
                                   ReferenceStreamRef()->Bytes(*this),
                               std::ios::cur );
                    }
                }
            }
            //-----------------------------------------------------------------
            // Return the information to the caller
            //-----------------------------------------------------------------
            return retval;
        }

        boost::shared_ptr< StreamRefInterface >
        IFrameStream::readStreamRef( )
        {
            boost::shared_ptr< FrameSpec::Object >  obj;
            boost::shared_ptr< StreamRefInterface > retval;

            // Log entry point and current stream position
            if ( logger( ) )
            {
                logger_log_debug(
                    logger( ),
                    60,
                    "IFrameStream::readStreamRef() entry at stream position: ",
                    tellg( ) );
            }

            //-----------------------------------------------------------------
            // Read the common element block
            //-----------------------------------------------------------------
            try
            {
                obj.reset( streamRef( ).Create( *this ) );
            }
            catch ( ... )
            {
                if ( eof( ) && ( gcount( ) == 0 ) )
                {
                    //-------------------------------------------------------------
                    // Just ran into the end of the file. Nothing to panic about
                    //-------------------------------------------------------------
                    return retval;
                }
                //---------------------------------------------------------------
                // Something bad has happened. Notify the caller
                //---------------------------------------------------------------
                throw; // Rethow the exception
            }
            if ( eof( ) && ( gcount( ) == 0 ) )
            {
                //---------------------------------------------------------------
                // Just ran into the end of the file. Nothing to panic about
                //---------------------------------------------------------------
                return retval;
            }
            retval = boost::dynamic_pointer_cast< StreamRefInterface >( obj );
            if ( !retval )
            {
                throw std::runtime_error(
                    "Failed to read common elements for the data structure" );
            }

            // Log successfully read StreamRef details
            if ( logger( ) && retval )
            {
                logger_log_debug(
                    logger( ),
                    70,
                    "IFrameStream::readStreamRef() read StreamRef - class: ",
                    retval->GetStreamClass( ),
                    ", instance: ",
                    retval->GetInstance( ),
                    ", length: ",
                    retval->GetLength( ),
                    ", current position: ",
                    tellg( ) );
            }

            try
            {
                // Log before attempting to map class ID to FSI ID
                if ( logger( ) )
                {
                    logger_log_debug( logger( ),
                                      80,
                                      "IFrameStream::readStreamRef() "
                                      "attempting to map class ID ",
                                      retval->GetStreamClass( ),
                                      " to FSI ID" );
                }

                INT_4U fsi_id = GetFSIId( retval->GetStreamClass( ) );
                if ( fsi_id == FrameSpec::Info::FSI_FR_DETECTOR )
                {
                    //---------------------------------------------------------
                    // Log where all detectors exist
                    //---------------------------------------------------------
                    INT_8U pos =
                        ( INT_8U( tellg( ) ) -
                          INT_8U( ReferenceStreamRef( )->Bytes( *this ) ) );

                    m_detector_pos[ pos ].m_class = retval->GetStreamClass( );
                    m_detector_pos[ pos ].m_instance = retval->GetInstance( );
                }
            }
            catch ( std::range_error& E )
            {
                std::ostringstream msg;

                INT_8U pos =
                    ( INT_8U( tellg( ) ) -
                      INT_8U( ReferenceStreamRef( )->Bytes( *this ) ) );

                msg << E.what( ) << " at position: " << pos
                    << " [streamref: class: " << retval->GetClass( )
                    << " instance: " << retval->GetInstance( )
                    << " length: " << retval->GetLength( ) << " ]";
                //-------------------------------------------------------------
                // Seek to the end of this unknown class
                //-------------------------------------------------------------
                seekg( retval->GetLength( ) -
                           ReferenceStreamRef( )->Bytes( *this ),
                       std::ios::cur );

                //-------------------------------------------------------------
                // Rethrow the exception
                //-------------------------------------------------------------
                throw std::range_error( msg.str( ) );
            }
            return retval;
        }

        IFrameStream::object_type
        IFrameStream::readObject( const StreamRefInterface* StreamRef )
        {
            const INT_4U fsi_id = GetFSIId( StreamRef->GetStreamClass( ) );

            object_type obj;

            const std::streampos start =
                ( tellg( ) -
                  std::streampos( ReferenceStreamRef( )->Bytes( *this ) ) );

            try
            {
                object_type::element_type* ptr(
                    frameSpecInfo( )
                        .FrameObject(
                            FrameSpec::Info::frame_object_types( fsi_id ) )
                        ->Create( *this ) );

                obj = objectLookup( ptr );
            }
            catch ( const Common::VerifyException& E )
            {
                std::ostringstream msg;

                msg << E.what( ) << " [ StreamId: " << StreamRef->GetStreamClass( )
                    << "-" << StreamRef->GetInstance( ) << " ]";
                throw Common::VerifyException( E.ErrorCode( ), msg.str( ) );
            }
            catch ( const std::runtime_error& E )
            {
                std::ostringstream msg;

                msg << E.what( ) << " [ StreamId: " << StreamRef->GetStreamClass( )
                    << "-" << StreamRef->GetInstance( ) << " ]";
                throw std::runtime_error( msg.str( ) );
            }
            catch ( const std::exception& E )
            {
                std::ostringstream msg;

                msg << E.what( ) << " [ StreamId: " << StreamRef->GetStreamClass( )
                    << "-" << StreamRef->GetInstance( ) << " ]";
                throw std::runtime_error( msg.str( ) );
            }
            //-----------------------------------------------------------------
            // Check if the bytes read differs from the exepected value
            //-----------------------------------------------------------------
            if ( ( tellg( ) - start ) !=
                 std::streampos( StreamRef->GetLength( ) ) )
            {
                std::streampos diff = ( tellg( ) - start ) -
                    std::streampos( StreamRef->GetLength( ) );
                //---------------------------------------------------------------
                /// \note
                /// In version 3 patch level 0 of the framecpp library,
                /// the length attribute for the FrSH and FrSE structures were
                /// not properly calculated.
                /// This reader will ignore this specific error so analysis
                /// of these frame files can continue.
                //---------------------------------------------------------------
                if ( !( ( Version( ) == 3 ) &&
                        ( ( ( StreamRef->GetStreamClass( ) == 1 ) &&
                            ( diff == std::streampos( 4 ) ) ) ||
                          ( ( StreamRef->GetStreamClass( ) == 2 ) &&
                            ( diff == std::streampos( 6 ) ) ) ) ) )
                {
                    std::ostringstream msg;

                    msg << "FATAL: Object: " << StreamRef->GetStreamClass( ) << "-"
                        << StreamRef->GetInstance( ) << ": Read "
                        << ( tellg( ) - start ) << " instead of "
                        << StreamRef->GetLength( ) << " bytes.";
                    throw std::range_error( msg.str( ) );
                }
            }
            //-----------------------------------------------------------------
            // Check if stream continues to be in a good state
            //-----------------------------------------------------------------
            if ( !good( ) )
            {
                std::ostringstream msg;

                msg << "I/O error on stream.";
                throw std::runtime_error( msg.str( ) );
            }

            if ( fsi_id == FrameSpec::Info::FSI_FR_SH )
            {
                //---------------------------------------------------------------
                // Create map entry mapping stream class id to memory class id
                //---------------------------------------------------------------
                logger_log_debug( logger(), 35, "IFrameStream: Processing FrSH structure" );
                boost::shared_ptr< FrSH > frsh(
                    boost::dynamic_pointer_cast< FrSH >( obj ) );
                if ( frsh )
                {
                    logger_log_debug( logger(), 35, "IFrameStream: FrSH cast succeeded, name='",
                                     frsh->name(), "' classId=", frsh->classId() );
                    const INT_2U id = GetClassId( frsh->name( ) );
                    if ( id )
                    {
                        logger_log_debug( logger(), 40, "IFrameStream: Registering stream class ID ",
                                         frsh->classId(), " -> FSI ID ", id,
                                         " for class '", frsh->name(), "'" );
                        m_stream_id_to_fsi_id[ frsh->classId( ) ] = id;
                    }
                    else
                    {
                        logger_log_debug( logger(), 30, "IFrameStream: FrSH for class '",
                                         frsh->name(), "' has no FSI ID mapping (classId=",
                                         frsh->classId(), ")" );
                    }
                }
                else
                {
                    logger_log_debug( logger(), 30, "IFrameStream: FrSH dynamic_pointer_cast FAILED" );
                }
            }
            else if ( fsi_id == FrameSpec::Info::FSI_FR_SE )
            {
                //---------------------------------------------------------------
                // Silently ignore these structures.
                //---------------------------------------------------------------
            }
            //
            // NOTE: Universal objects don't require version conversion.
            // Legacy promote/demote mechanism (morph) removed - all version
            // adaptation now happens at I/O layer via pCreate.
            //
            return obj;
        }

        void
        IFrameStream::readRecursive( INT_4U StopOnClassId, bool Decompress )
        {
            //-----------------------------------------------------------------
            // Setup for the recursive read
            //-----------------------------------------------------------------
            m_to_be_resolved.clear( );

            logger_log_debug(resolver_logger(), 10, "readRecursive() entry - resolverContainer size: ", resolverContainer().size());

            for ( resolver_container_type::const_iterator
                      cur = resolverContainer( ).begin( ),
                      last = resolverContainer( ).end( );
                  cur != last;
                  ++cur )
            {
                logger_log_debug(resolver_logger(), 20, "Adding PTR_STRUCT to queue - class: ",
                          (*cur)->PtrStruct()->Class(), " instance: ", (*cur)->PtrStruct()->Instance());
                addRecursiveDependant( ( *cur )->PtrStruct( ) );
            }

            logger_log_debug(resolver_logger(), 10, "Resolver queue size after initialization: ", m_to_be_resolved.size());

            //-----------------------------------------------------------------
            // Read until reaching a stopping point
            //-----------------------------------------------------------------
            boost::shared_ptr< StreamRefInterface > streamref;
            object_type                             obj;

            while ( m_to_be_resolved.empty( ) == false )
            {
                std::streampos struct_end = tellg( );
                streamref = readStreamRef( );
                if ( !streamref )
                {
                    //-------------------------------------------------------------
                    // Reached end of file
                    //-------------------------------------------------------------
                    logger_log_debug(resolver_logger(), 20, "Reached end of file, queue size: ", m_to_be_resolved.size());
                    break;
                }
                try
                {
                    INT_4U fsi_id( GetFSIId( streamref->GetStreamClass( ) ) );

                    logger_log_debug(resolver_logger(), 30, "Read StreamRef - stream class: ", streamref->GetStreamClass(),
                              " stream instance: ", streamref->GetInstance(),
                              " FSI_id: ", fsi_id,
                              " position: ", struct_end);

                    if ( fsi_id == StopOnClassId )
                    {
                        //-----------------------------------------------------------
                        // Stop on this object. Rewind to start of StreamRef
                        //-----------------------------------------------------------
                        logger_log_debug(resolver_logger(), 20, "Stopping on class ID: ", StopOnClassId);
                        seekg( -( ReferenceStreamRef( )->Bytes( *this ) ),
                               std::ios::cur );
                        break;
                    }
                    //-------------------------------------------------------------
                    // See if object is needed
                    //-------------------------------------------------------------
                    bool is_needed = removeRecursiveDependant( streamref.get( ) );
                    logger_log_debug(resolver_logger(), 30, "Object is_needed: ", (is_needed ? "YES" : "NO"),
                              " (queue size now: ", m_to_be_resolved.size(), ")");
                    if ( ( is_needed == false ) &&
                         ( fsi_id != ( FrameSpec::Info::FSI_FR_SH ) ) )
                    {
                        //-----------------------------------------------------------
                        // Advance to the next object
                        //-----------------------------------------------------------
                        struct_end += streamref->GetLength( );
                        seekg( struct_end, std::ios::beg );
                        continue;
                    }
                    //-------------------------------------------------------------
                    // Object is needed
                    //-------------------------------------------------------------
                    obj = readObject( streamref.get( ) );
                    if ( obj )
                    {
                        logger_log_debug(resolver_logger(), 30, "Object read successfully - internal class: ", obj->GetClass());
                        if ( obj->GetClass( ) == FrameSpec::Info::FSI_FR_SH )
                        {
                            logger_log_debug(resolver_logger(), 30, "Skipping FrSH object (structure header)");
                            continue;
                        }
                        logger_log_debug(resolver_logger(), 30, "Adding object to dictionary - stream class: ",
                                  streamref->GetStreamClass(), " stream instance: ", streamref->GetInstance());
                        m_dictionary.Ref( streamref, obj );
                        if ( ( obj->GetClass( ) ==
                               FrameSpec::Info::FSI_FR_VECT ) &&
                             ( Decompress ) )
                        {
                            boost::shared_ptr< FrVect > vect =
                                boost::dynamic_pointer_cast< FrVect >( obj );

                            vect->CompressData( Compression::MODE_RAW, 0 );
                        }
                    }
                }
                catch ( const Common::VerifyException& E )
                {
                    if ( E.ErrorCode( ) ==
                         Common::VerifyException::CHECKSUM_ERROR )
                    {
                        //-----------------------------------------------------------
                        // Checksum errors need to be reported instead of
                        // quietly
                        //   being ignored.
                        //-----------------------------------------------------------
                        throw;
                    }
                    //-------------------------------------------------------------
                    // Seek to the end of this unknown class
                    //-------------------------------------------------------------
                    struct_end += streamref->GetLength( );
                    seekg( struct_end, std::ios::beg );
                }
                catch ( ... )
                {
                    //-------------------------------------------------------------
                    // Seek to the end of this unknown class
                    //-------------------------------------------------------------
                    struct_end += streamref->GetLength( );
                    seekg( struct_end, std::ios::beg );
                }
            }

            //-----------------------------------------------------------------
            // Glue the pieces together
            //-----------------------------------------------------------------
            Resolve( );
            m_to_be_resolved.clear( );
        }

        void
        IFrameStream::addRecursiveDependant( ptr_struct_base_type Ref )
        {
            if ( Ref )
            {
                ResolverKey resolver_key( Ref->Class(), Ref->Instance() );
                logger_log_debug(resolver_logger(), 30, "addRecursiveDependant(PTR_STRUCT) - class_id: ",
                          resolver_key.parts.class_id, " instance: ", resolver_key.parts.instance,
                          " key: 0x", std::hex, resolver_key.key, std::dec);
                if ( resolver_key.key )
                {
                    m_to_be_resolved.insert( resolver_key.key );
                }
            }
        }

        void
        IFrameStream::addRecursiveDependant(
            const StreamRefInterface* StreamRef )
        {
            if ( StreamRef )
            {
                ResolverKey resolver_key( StreamRef->GetStreamClass(), StreamRef->GetInstance() );
                logger_log_debug(resolver_logger(), 30, "addRecursiveDependant(StreamRef) - stream_class: ",
                          resolver_key.parts.class_id, " instance: ", resolver_key.parts.instance,
                          " key: 0x", std::hex, resolver_key.key, std::dec);

                if ( resolver_key.key )
                {
                    m_to_be_resolved.insert( resolver_key.key );
                }
            }
        }

        bool
        IFrameStream::removeRecursiveDependant(
            const StreamRefInterface* StreamRef )
        {
            bool retval = false;
            if ( StreamRef )
            {
                //-----------------------------------------------------------------
                // FIX: Use stream class ID directly, NOT FSI ID!
                // addRecursiveDependant(PTR_STRUCT) stores the class ID from PTR_STRUCT,
                // which contains the stream class ID as read from the file.
                // We must use the same stream class ID to match the key!
                //-----------------------------------------------------------------
                INT_4U stream_class = StreamRef->GetStreamClass();
                ResolverKey lookup_key( stream_class, StreamRef->GetInstance() );

                if ( lookup_key.key && ( m_to_be_resolved.erase( lookup_key.key ) > 0 ) )
                {
                    retval = true;
                    logger_log_debug(resolver_logger(), 30, "removeRecursiveDependant() - stream_class: ", stream_class,
                              " instance: ", lookup_key.parts.instance,
                              " lookup_key: 0x", std::hex, lookup_key.key, std::dec,
                              " FOUND (removed from queue)");
                }
                else
                {
                    logger_log_debug(resolver_logger(), 30, "removeRecursiveDependant() - stream_class: ", stream_class,
                              " instance: ", lookup_key.parts.instance,
                              " lookup_key: 0x", std::hex, lookup_key.key, std::dec,
                              " NOT FOUND (not in queue)");
                }
            }

            return retval;
        }

        void
        IFrameStream::pushResolver( resolver_type Resolver )
        {
            //-----------------------------------------------------------------
            // Let the base class use the information first
            //-----------------------------------------------------------------
            IStream::pushResolver( Resolver );
            //-----------------------------------------------------------------
            // Thing that need to be done locally
            //-----------------------------------------------------------------
            if ( Resolver )
            {
                addRecursiveDependant( Resolver->PtrStruct( ) );
            }
        }

        template <>
        INT_8U
        IFrameStream::position< FrameSpec::Info::FSI_FR_ADC_DATA, std::string >(
            const FrTOC* TOC, INT_4U Frame, const std::string& Channel ) const
        {
            return TOC->positionADC( Frame, Channel );
        }

        template <>
        INT_8U
        IFrameStream::position< FrameSpec::Info::FSI_FR_ADC_DATA, INT_4U >(
            const FrTOC* TOC, INT_4U Frame, const INT_4U& Channel ) const
        {
            return TOC->positionADC( Frame, Channel );
        }

        template <>
        INT_8U
        IFrameStream::position< FrameSpec::Info::FSI_FR_EVENT, std::string >(
            const FrTOC* TOC, INT_4U Frame, const std::string& Channel ) const
        {
            return TOC->positionEvent( Frame, Channel );
        }

        template <>
        INT_8U
        IFrameStream::position< FrameSpec::Info::FSI_FR_PROC_DATA,
                                std::string >(
            const FrTOC* TOC, INT_4U Frame, const std::string& Channel ) const
        {
            return TOC->positionProc( Frame, Channel );
        }

        template <>
        INT_8U
        IFrameStream::position< FrameSpec::Info::FSI_FR_PROC_DATA, INT_4U >(
            const FrTOC* TOC, INT_4U Frame, const INT_4U& Channel ) const
        {
            return TOC->positionProc( Frame, Channel );
        }

        template <>
        INT_8U
        IFrameStream::position< FrameSpec::Info::FSI_FR_SER_DATA, std::string >(
            const FrTOC* TOC, INT_4U Frame, const std::string& Channel ) const
        {
            return TOC->positionSer( Frame, Channel );
        }

        template <>
        INT_8U
        IFrameStream::position< FrameSpec::Info::FSI_FR_SIM_DATA, std::string >(
            const FrTOC* TOC, INT_4U Frame, const std::string& Channel ) const
        {
            return TOC->positionSim( Frame, Channel );
        }

        template <>
        INT_8U
        IFrameStream::position< FrameSpec::Info::FSI_FR_SIM_EVENT,
                                std::string >(
            const FrTOC* TOC, INT_4U Frame, const std::string& Channel ) const
        {
            return TOC->positionSimEvent( Frame, Channel );
        }

        template <>
        INT_8U
        IFrameStream::position_index< FrameSpec::Info::FSI_FR_EVENT,
                                      std::string >( const FrTOC*       TOC,
                                                     const std::string& Channel,
                                                     INT_4U Index ) const
        {
            return TOC->positionEvent( Channel, Index );
        }

        template <>
        INT_8U
        IFrameStream::position_index< FrameSpec::Info::FSI_FR_SIM_EVENT,
                                      std::string >( const FrTOC*       TOC,
                                                     const std::string& Channel,
                                                     INT_4U Index ) const
        {
            return TOC->positionSimEvent( Channel, Index );
        }

        template < INT_4U ClassType, typename ChannelType >
        IFrameStream::object_type
        IFrameStream::advance_to_fr_struct( INT_4U Frame, ChannelType Channel )
        {
            object_type  retval;
            const FrTOC* toc( dynamic_cast< const FrTOC* >( GetTOC( ) ) );

            //-----------------------------------------------------------------
            // Position within the file where the frame starts
            //-----------------------------------------------------------------
            if ( toc )
            {
                //---------------------------------------------------------------
                // Fast seek implementation via table of contents.
                //---------------------------------------------------------------
                const std::streampos offset =
                    position< ClassType >( toc, Frame, Channel );
                if ( offset == (std::streampos)0 )
                {
                    std::ostringstream msg;

                    msg << "channel: " << Channel
                        << " does not exist in frame:" << Frame;
                    throw std::range_error( msg.str( ) );
                }

                clear( );
                seekg( offset, std::ios::beg );
                retval = Read( );
                while (
                    good( ) && retval.get( ) &&
                    ( ( retval->GetClass( ) == FrameSpec::Info::FSI_FR_SE ) ||
                      ( retval->GetClass( ) == FrameSpec::Info::FSI_FR_SH ) ) )
                {
                    //-------------------------------------------------------------
                    // Ignore structure definition components
                    //-------------------------------------------------------------
                    retval = Read( );
                }
                if ( !good( ) )
                {
                    std::ostringstream msg;
                    msg << "After reading object of type: "
                        << frameSpecInfo( )
                               .FrameObject(
                                   FrameSpec::Info::frame_object_types(
                                       ClassType ) )
                               ->ObjectStructName( )
                        << " stream is no longer in good state."
                        << " ( Frmae: " << Frame << " ChannelType: " << Channel
                        << " offset: " << offset << ")";
                    throw std::runtime_error( msg.str( ) );
                }
                if ( ( !retval ) || ( retval->GetClass( ) != ClassType ) )
                {
                    std::ostringstream msg;

                    msg << "The object named: " << Channel << " at location "
                        << offset << " is not a "
                        << frameSpecInfo( )
                               .FrameObject(
                                   FrameSpec::Info::frame_object_types(
                                       ClassType ) )
                               ->ObjectStructName( )
                        << " structure.";
                    if ( retval.get( ) )
                    {
                        msg << " It is instead of type: "
                            << retval->ObjectStructName( );
                    }
                    else
                    {
                        msg << " It is instead of type: NULL";
                    }
                    throw std::runtime_error( msg.str( ) );
                }
            }
            else
            {
                //---------------------------------------------------------------
                // :TODO: Slower implementation by reading forward in file
                //---------------------------------------------------------------
                throw Unimplemented(
                    "Common::IFrameStreamWrapper::advanceToFrProcData(non-toc)",
                    streamVersion( ),
                    __FILE__,
                    __LINE__ );
            }

            //-----------------------------------------------------------------
            // Return the information to the caller
            //-----------------------------------------------------------------
            return retval;
        }

        template < INT_4U ClassType, typename ChannelType >
        IFrameStream::object_type
        IFrameStream::advance_to_indexed_fr_struct( ChannelType Channel,
                                                    INT_4U      Index )
        {
            object_type  retval;
            const FrTOC* toc( dynamic_cast< const FrTOC* >( GetTOC( ) ) );

            //-----------------------------------------------------------------
            // Position within the file where the frame starts
            //-----------------------------------------------------------------
            if ( toc )
            {
                //---------------------------------------------------------------
                // Fast seek implementation via table of contents.
                //---------------------------------------------------------------
                const std::streampos offset =
                    position_index< ClassType >( toc, Channel, Index );
                if ( offset == (std::streampos)0 )
                {
                    std::ostringstream msg;

                    msg << "channel: " << Channel
                        << " does not exist at index: " << Index;
                    throw std::range_error( msg.str( ) );
                }

                clear( );
                seekg( offset, std::ios::beg );
                retval = Read( );
                while (
                    good( ) && retval.get( ) &&
                    ( ( retval->GetClass( ) == FrameSpec::Info::FSI_FR_SE ) ||
                      ( retval->GetClass( ) == FrameSpec::Info::FSI_FR_SH ) ) )
                {
                    //-------------------------------------------------------------
                    // Ignore structure definition components
                    //-------------------------------------------------------------
                    retval = Read( );
                }
                if ( !good( ) )
                {
                    std::ostringstream msg;
                    msg << "After reading object of type: "
                        << frameSpecInfo( )
                               .FrameObject(
                                   FrameSpec::Info::frame_object_types(
                                       ClassType ) )
                               ->ObjectStructName( )
                        << " stream is no longer in good state."
                        << " ( ChannelType: " << Channel << " Index: " << Index
                        << " file position offset: " << offset << ")";
                    throw std::runtime_error( msg.str( ) );
                }
                if ( ( !retval ) || ( retval->GetClass( ) != ClassType ) )
                {
                    std::ostringstream msg;

                    msg << "The object named: " << Channel << " at location "
                        << offset << " is not a "
                        << frameSpecInfo( )
                               .FrameObject(
                                   FrameSpec::Info::frame_object_types(
                                       ClassType ) )
                               ->ObjectStructName( )
                        << " structure.";
                    if ( retval.get( ) )
                    {
                        msg << " It is instead of type: "
                            << retval->ObjectStructName( );
                    }
                    else
                    {
                        msg << " It is instead of type: NULL";
                    }
                    throw std::runtime_error( msg.str( ) );
                }
            }
            else
            {
                //---------------------------------------------------------------
                // :TODO: Slower implementation by reading forward in file
                //---------------------------------------------------------------
                throw Unimplemented(
                    "Common::IFrameStreamWrapper::advanceToFrProcData(non-toc)",
                    streamVersion( ),
                    __FILE__,
                    __LINE__ );
            }

            //-----------------------------------------------------------------
            // Return the information to the caller
            //-----------------------------------------------------------------
            return retval;
        }

        template < INT_4U ClassType, typename ChannelType >
        IFrameStream::object_type
        IFrameStream::read_fr_struct( INT_4U      Frame,
                                      ChannelType Channel,
                                      bool        Recursively )
        try
        {
            //-----------------------------------------------------------------
            // Prep for errors
            //-----------------------------------------------------------------
            reset( );
            //-----------------------------------------------------------------
            // Advance to the requested frame within the stream
            //-----------------------------------------------------------------
            object_type retval;

            m_logNextPtr = false;
            try
            {
                retval = advance_to_fr_struct< ClassType >( Frame, Channel );
            }
            catch ( ... )
            {
                m_logNextPtr = true;
                throw;
            }
            m_logNextPtr = true;
            if ( Recursively && retval )
            {
                //---------------------------------------------------------------
                // Read until all references are resolved or until FrEndOfFrame
                //   is reached
                //---------------------------------------------------------------
                readRecursive( FrameSpec::Info::FSI_FR_NULL );
            }
            //-----------------------------------------------------------------
            // Return the results
            //-----------------------------------------------------------------
            return retval;
        }
        catch ( ... )
        {
            ERROR_HANDLER( );
        }

        template < INT_4U ClassType, typename ChannelType >
        IFrameStream::object_type
        IFrameStream::read_indexed_fr_struct( ChannelType Channel,
                                              INT_4U      Index,
                                              bool        Recursively )
        try
        {
            //-----------------------------------------------------------------
            // Prep for errors
            //-----------------------------------------------------------------
            reset( );
            //-----------------------------------------------------------------
            // Advance to the requested frame within the stream
            //-----------------------------------------------------------------
            object_type retval;

            m_logNextPtr = false;
            try
            {
                retval =
                    advance_to_indexed_fr_struct< ClassType >( Channel, Index );
            }
            catch ( ... )
            {
                m_logNextPtr = true;
                throw;
            }
            m_logNextPtr = true;
            if ( Recursively && retval )
            {
                //---------------------------------------------------------------
                // Read until all references are resolved or until FrEndOfFrame
                //   is reached
                //---------------------------------------------------------------
                readRecursive( FrameSpec::Info::FSI_FR_NULL );
            }
            //-----------------------------------------------------------------
            // Return the results
            //-----------------------------------------------------------------
            return retval;
        }
        catch ( ... )
        {
            ERROR_HANDLER( );
        }

        //===================================================================
        //===================================================================
        bool
        OFrameStream::detector_cmp::operator( )( fr_detector_type S1,
                                                 fr_detector_type S2 ) const
        {
            return ( S1.get( ) < S2.get( ) );
        }

        //===================================================================
        //
        //===================================================================
        OFrameStream::OFrameStream( buffer_type* Buffer, INT_2U Version )
            : FrameStream( Version, false /* AllowZeroVersion */ ),
              OStream( Buffer ), m_toc_location( 0 ), m_frame_count( 0 ),
              m_has_header( false )
        {
            if ( logger( ) )
            {
                logger_log_debug( logger( ),
                                  10,
                                  "OFrameStream::OFrameStream() entry, buffer=",
                                  static_cast< void* >( Buffer ),
                                  " version=",
                                  Version );
            }
            version_stream( Version );
            if ( logger( ) )
            {
                logger_log_debug(
                    logger( ),
                    30,
                    "OFrameStream::OFrameStream() about to call init()" );
            }
            init( );
            if ( logger( ) )
            {
                logger_log_debug(
                    logger( ),
                    10,
                    "OFrameStream::OFrameStream() constructor complete" );
            }
        } // method OFrameStream::OFrameStream

        OFrameStream::OFrameStream( buffer_type* Buffer,
                                    INT_2U       StreamVersion,
                                    INT_2U       MemoryVersion )
            : FrameStream( MemoryVersion, false /* AllowZeroVersion */ ),
              OStream( Buffer ), m_toc_location( 0 ), m_frame_count( 0 ),
              m_has_header( false )
        {
            if ( logger( ) )
            {
                logger_log_debug( logger( ),
                                  10,
                                  "OFrameStream::OFrameStream() entry, buffer=",
                                  static_cast< void* >( Buffer ),
                                  " streamVersion=",
                                  StreamVersion,
                                  " memoryVersion=",
                                  MemoryVersion );
            }
            version_stream( StreamVersion );
            if ( logger( ) )
            {
                logger_log_debug(
                    logger( ),
                    30,
                    "OFrameStream::OFrameStream() about to call init()" );
            }
            init( );
            if ( logger( ) )
            {
                logger_log_debug(
                    logger( ),
                    10,
                    "OFrameStream::OFrameStream() constructor complete" );
            }
        } // method OFrameStream::OFrameStream

        OFrameStream::OFrameStream( bool         AutoDelete,
                                    buffer_type* Buffer,
                                    INT_2U       Version )
            : FrameStream( Version, false /* AllowZeroVersion */ ),
              OStream( Buffer, AutoDelete ), m_toc_location( 0 ),
              m_frame_count( 0 ), m_has_header( false )
        {
            if ( logger( ) )
            {
                logger_log_debug(
                    logger( ),
                    10,
                    "OFrameStream::OFrameStream() entry, autoDelete=",
                    AutoDelete,
                    " buffer=",
                    static_cast< void* >( Buffer ),
                    " version=",
                    Version );
            }
            version_stream( Version );
            if ( logger( ) )
            {
                logger_log_debug(
                    logger( ),
                    30,
                    "OFrameStream::OFrameStream() about to call init()" );
            }
            init( );
            if ( logger( ) )
            {
                logger_log_debug(
                    logger( ),
                    10,
                    "OFrameStream::OFrameStream() constructor complete" );
            }
        } // method OFrameStream::OFrameStream

        OFrameStream::~OFrameStream( )
        {
            if ( logger( ) )
            {
                logger_log_debug(
                    logger( ),
                    10,
                    "OFrameStream::~OFrameStream() destructor called, this=",
                    static_cast< const void* >( this ) );
            }
            if ( logger( ) )
            {
                logger_log_debug(
                    logger( ),
                    30,
                    "OFrameStream::~OFrameStream() about to call Close()" );
            }
            Close( );
            if ( logger( ) )
            {
                logger_log_debug(
                    logger( ),
                    10,
                    "OFrameStream::~OFrameStream() destructor complete" );
            }
        } // method - OFrameStream::~OFrameStream

        void
        OFrameStream::Close( )
        {
            if ( logger( ) )
            {
                logger_log_debug( logger( ),
                                  20,
                                  "OFrameStream::Close() entry, closed_state=",
                                  m_closed_state,
                                  " toc=",
                                  ( m_toc ? "exists" : "null" ) );
            }
            if ( !m_closed_state )
            {
                //---------------------------------------------------------------
                // Need to write out the table of contents.
                //---------------------------------------------------------------
                if ( m_toc )
                {
                    if ( logger( ) )
                    {
                        logger_log_debug(
                            logger( ),
                            30,
                            "OFrameStream::Close() writing TOC to stream" );
                    }
                    Write( m_toc );
                    if ( logger( ) )
                    {
                        logger_log_debug(
                            logger( ),
                            30,
                            "OFrameStream::Close() TOC written successfully" );
                    }
                }
                //---------------------------------------------------------------
                // Mark the end of file
                //---------------------------------------------------------------
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ),
                        30,
                        "OFrameStream::Close() creating FrEndOfFile object" );
                }
                object_type fr_end_of_file(
                    frameSpecInfo( )
                        .FrameObject( FrameSpec::Info::FSI_FR_END_OF_FILE )
                        ->Clone( ) );
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ),
                        30,
                        "OFrameStream::Close() writing FrEndOfFile to stream" );
                }
                Write( fr_end_of_file );
                m_closed_state = true;
                if ( logger( ) )
                {
                    logger_log_debug( logger( ),
                                      30,
                                      "OFrameStream::Close() flushing stream" );
                }
                flush( );
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ),
                        20,
                        "OFrameStream::Close() stream closed successfully" );
                }
            }
            else
            {
                if ( logger( ) )
                {
                    logger_log_debug( logger( ), 20, "closed, nothing to do" );
                }
            }
        } // method - OFrameStream::Close()

        void
        OFrameStream::Write( object_type Obj )
        {
            if ( logger( ) )
            {
                logger_log_debug( logger( ),
                                  20,
                                  "OFrameStream::Write() entry, closed_state=",
                                  m_closed_state,
                                  " obj=",
                                  ( Obj ? "valid" : "null" ) );
            }
            if ( m_closed_state || ( !Obj ) )
            {
                if ( logger( ) )
                {
                    logger_log_debug( logger( ), 30, "closed or null object" );
                }
                return;
            }
            if ( logger( ) )
            {
                logger_log_debug( logger( ),
                                  30,
                                  "OFrameStream::Write() object class=",
                                  Obj->GetClass( ),
                                  " has_header=",
                                  m_has_header );
            }
            if ( ( m_has_header == false ) &&
                 ( Obj->GetClass( ) !=
                   FrameSpec::class_type( FrameSpec::Info::FSI_FR_HEADER ) ) )
            {
                //---------------------------------------------------------------
                // Write the header to the file
                //---------------------------------------------------------------
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ), 30, "header first, creating FrHeader" );
                }
                FrameSpec::ObjectInterface::unique_object_type frheader(
                    frameSpecInfo( )
                        .FrameObject( FrameSpec::Info::FSI_FR_HEADER )
                        ->Clone( ) );
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ), 50, "attempting dynamic cast" );
                }
                FrHeader* base = dynamic_cast< FrHeader* >( frheader.get( ) );
                if ( base )
                {
                    //-------------------------------------------------------------
                    // Need to setup some fields
                    //-------------------------------------------------------------
                    if ( logger( ) )
                    {
                        logger_log_debug(
                            logger( ),
                            50,
                            "OFrameStream::Write() setting up header fields" );
                    }
                    base->SetOriginator( "IGWD" );
                    base->SetVersion( frameSpecInfo( ).Version( ) );
                    base->SetLibraryVersion( frameSpecInfo( ).VersionMinor( ) );
                    base->SetFrameLibrary( FrHeader::FRAME_LIBRARY_FRAMECPP );
                    if ( logger( ) )
                    {
                        logger_log_debug(
                            logger( ),
                            50,
                            "OFrameStream::Write() header fields set, version=",
                            frameSpecInfo( ).Version( ) );
                    }
                }
                //---------------------------------------------------------------
                // Write the object to the stream.
                //---------------------------------------------------------------
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ),
                        30,
                        "OFrameStream::Write() writing header to stream" );
                }
                frheader->Write( *this );
                if ( logger( ) )
                {
                    logger_log_debug( logger( ), 50, "setting FrHeader" );
                }
                setFrHeader( frheader );
                m_has_header = true;
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ),
                        30,
                        "OFrameStream::Write() header setup complete" );
                }
            }

            //-----------------------------------------------------------------
            // Prepare for the case where a new FrVect will be created
            //-----------------------------------------------------------------
            object_type dictionary_obj( Obj );

            //-----------------------------------------------------------------
            // Compress compressable objects only if requested.
            //-----------------------------------------------------------------
            if ( ( Obj->GetClass( ) == FrameSpec::Info::FSI_FR_VECT ) &&
                 ( ( CompressionScheme( ) & 0xFF ) != Compression::MODE_RAW ) )

            {
                //---------------------------------------------------------------
                /// \todo Check that the compression mode is supported by
                ///       by the writer
                //---------------------------------------------------------------
                boost::shared_ptr< FrVect > vect =
                    boost::dynamic_pointer_cast< FrVect >( Obj );

                if ( vect &&
                     ( ( vect->Compression( ) & 0xFF ) ==
                       Compression::MODE_RAW ) )
                {
                    FrameSpec::Object* cv = vect->CloneCompressed(
                        CompressionScheme( ), CompressionLevel( ) );
                    if ( cv && ( cv != Obj.get( ) ) )
                    {
                        Obj.reset( cv ); // Reset the obj to be written
                    }
                }
            }

            //-----------------------------------------------------------------
            // Add object to TOC
            //-----------------------------------------------------------------
            std::streampos      start = tellp( );
            cmn_streamsize_type b = 0;
            /* cmn_streamsize_type	ob = Obj->Bytes( *this ); */

            //-----------------------------------------------------------------
            // Create and register reference for the object
            //-----------------------------------------------------------------
            logger_log_debug( logger(),
                              50,
                              "OFrameStream::Write() object class ID (FSI): ",
                              Obj->GetClass(),
                              " at position: ",
                              tellp() );

            if ( Obj->GetClass( ) > 0 )
            {
                Dictionary::streamref_type ce;

                ce = m_dictionary.RefCreate( dictionary_obj, *this );

                logger_log_debug( logger(),
                                  50,
                                  "OFrameStream::Write() RefCreate returned: ",
                                  ( ce ? "valid StreamRef" : "nullptr" ),
                                  " for FSI ID: ",
                                  Obj->GetClass() );

                if ( ce )
                {
                    bool wrote_description = false;

                    if ( ( m_defined.find( Obj->GetClass( ) ) ==
                           m_defined.end( ) ) &&
                         ( Obj->GetDescription( *this ) ) )
                    {
                        Obj->GetDescription( *this )->Write( *this );
                        m_defined.insert( Obj->GetClass( ) );
                        wrote_description = true;
                    }
                    b += ce->Bytes( *this );
                    start = tellp( );
                    b = ce->Bytes( *this ) + Obj->Bytes( *this );
                    ce->SetLength( b );
                    //-------------------------------------------------------------
                    // Check if the object to be written is a frame header
                    // object
                    //   and that a description for the object was written.
                    //-------------------------------------------------------------
                    if ( ( Obj->GetClass( ) == FrameSpec::Info::FSI_FRAME_H ) &&
                         ( wrote_description ) )
                    {
                        CheckSumFilter* sum = GetCheckSumFrame( );
                        if ( sum )
                        {
                            //---------------------------------------------------------
                            // Need to reset the frame checksum since it
                            // currently
                            //   contains the checksum of the description of the
                            //   frame header object.
                            //---------------------------------------------------------
                            SetCheckSumFrame( sum->Type( ) );
                        }
                    }
                    //-------------------------------------------------------------
                    // Starting with version 8, the checksum can be at the level
                    // of the individual objects.
                    //-------------------------------------------------------------
                    if ( ( Version( ) >= 8 ) //
                         && GetCheckSumObject( ) //
                         && GetCheckSumObject( )->GetChecksum( ) )
                    {
                        GetCheckSumObject( )->GetChecksum( )->Reset( );
                    }
                    ce->Write( *this );
                }
            }
            //-----------------------------------------------------------------
            // Write object to the stream
            //-----------------------------------------------------------------
            if ( Obj->GetClass( ) == FrameSpec::Info::FSI_FRAME_H )
            {
                ++m_frame_count;
            }
            else if ( Obj->GetClass( ) == FrameSpec::Info::FSI_FR_TOC )
            {
                m_toc_location = start;
            }
            if ( b == 0 )
            {
                b = Obj->Bytes( *this );
            }
            Obj->Write( *this );
            if ( ( Obj->GetClass( ) == FrameSpec::Info::FSI_FR_END_OF_FRAME ) ||
                 ( Obj->GetClass( ) == FrameSpec::Info::FSI_FR_END_OF_FILE ) )
            {
                m_dictionary.ResetInstanceCounts( );
            }
            //-----------------------------------------------------------------
            // Add object to table of contents
            //-----------------------------------------------------------------
            if ( m_toc )
            {
                m_toc->IndexObject( Obj, start );
            }
            //-----------------------------------------------------------------
            // Check the number of bytes written
            //-----------------------------------------------------------------
            std::streampos end = tellp( );
            if ( end != ( start + std::streampos( b ) ) )
            {
                std::ostringstream msg;

                msg << "Wrote " << ( end - start )
                    << " bytes to the stream instead of " << b
                    << " bytes for class: " << Obj->GetClass( );
                const Description* d( Obj->GetDescription( *this ) );
                if ( d )
                {
                    msg << " (" << d->GetName( ) << ")";
                }
                msg << " [" << ErrnoMessage( ) << "]";
                throw std::length_error( msg.str( ) );
            }
            if ( Obj->GetClass( ) == FrameSpec::Info::FSI_FR_DETECTOR )
            {
                //---------------------------------------------------------------
                // For detectors, need to check for FrStatData that needs to
                //  be outputted.
                //---------------------------------------------------------------
                fr_detector_type detector = boost::dynamic_pointer_cast<
                    fr_detector_type::element_type >( Obj );
                fr_stat_container_type::iterator fr_stat(
                    m_fr_stats.find( detector ) );
                if ( fr_stat != m_fr_stats.end( ) )
                {
                    //-------------------------------------------------------------
                    // Here we put the FrStatData structures onto the print
                    // stack
                    //   since there is a requirement that the first must appear
                    //   after the detector that it references.
                    // The spec is silent on what to do about the others so just
                    //   put them all after the detector they reference.
                    //-------------------------------------------------------------
                    PushMulti( fr_stat->second.begin( ),
                               fr_stat->second.end( ),
                               fr_stat->second.size( ) );
                    //-------------------------------------------------------------
                    // Remove from the list
                    /// \todo
                    ///  Need to ensure that all FrStatData structures have
                    ///  been written to the stream. This is to verify that
                    ///  that an FrDetector structure has been associated
                    ///  with each FrStatData.
                    //-------------------------------------------------------------
                    m_fr_stats.erase( fr_stat );
                } // if ( fr_stats != m_fr_stats.end( ) )
            } // if ( Obj->GetClass( ) == FrameSpec::Info::FSI_FR_DETECTOR )
        } // method - OFrameStream::Write( )

        void
        OFrameStream::WriteFrame( object_type FrameObject,
                                  chkSum_type FrameChecksumType )
        {
            if ( FrameObject->GetClass( ) != FrameSpec::Info::FSI_FRAME_H )
            {
                std::ostringstream msg;

                msg << "WriteFramme called with an object not of class FrameH";

                throw std::invalid_argument( msg.str( ) );
            }
            //-----------------------------------------------------------------
            // Setup for calculating checksum for frame
            //-----------------------------------------------------------------
            this->SetCheckSumFrame( CheckSum::kind_type( FrameChecksumType ) );
            PushSingle( FrameObject );
            write_stream_objects( );

            //-----------------------------------------------------------------
            // DEBUG: Peek at file checksum after writing FrHeader
            //-----------------------------------------------------------------
            // File checksum is now active and seeded with header
        }

        void
        OFrameStream::WriteFrame( object_type FrameObject,
                                  INT_2U      CompressionScheme,
                                  INT_2U      CompressionLevel,
                                  chkSum_type FrameChecksumType )
        {
            Compression( CompressionScheme, CompressionLevel );
            try
            {
                WriteFrame( FrameObject, FrameChecksumType );
            }
            catch ( ... )
            {
                //---------------------------------------------------------------
                // Reset stream to initial state
                //---------------------------------------------------------------
                Compression( CompressionScheme, CompressionLevel );
                //---------------------------------------------------------------
                // Rethrow exception
                //---------------------------------------------------------------
                throw;
            }
            //-----------------------------------------------------------------
            // Reset stream to initial state
            //-----------------------------------------------------------------
            Compression( CompressionScheme, CompressionLevel );
        }

        void
        OFrameStream::WriteFrStatData( object_type Object )
        {
            //-----------------------------------------------------------------
            // Ensure the object is of the appropriate data type
            //-----------------------------------------------------------------
            fr_stat_data_type fr_stat_data =
                boost::dynamic_pointer_cast< fr_stat_data_type::element_type >(
                    Object );
            if ( !fr_stat_data )
            {
                std::ostringstream msg;

                msg << "";
                throw std::domain_error( msg.str( ) );
            }
            m_fr_stats[ fr_stat_data->GetDetector( ) ].push_back(
                fr_stat_data );
        }

        void
        OFrameStream::init( )
        {
            if ( logger( ) )
            {
                logger_log_debug( logger( ),
                                  20,
                                  "OFrameStream::init() entry, frame version=",
                                  frameSpecInfo( ).Version( ) );
            }
            //-----------------------------------------------------------------
            // Ensure buffering on the stream
            //-----------------------------------------------------------------
            if ( logger( ) )
            {
                logger_log_debug(
                    logger( ),
                    30,
                    "OFrameStream::init() setting up stream buffering" );
            }
            rdbuf( )->buffer( );
            seekp( 0 ); // To go the beginning of the file.
            if ( logger( ) )
            {
                logger_log_debug(
                    logger( ),
                    30,
                    "OFrameStream::init() stream positioned to beginning" );
            }

            //-----------------------------------------------------------------
            // Create a table of contents structure
            //-----------------------------------------------------------------
            if ( logger( ) )
            {
                logger_log_debug(
                    logger( ),
                    30,
                    "OFrameStream::init() attempting to create TOC structure" );
            }
            try
            {
                const FrTOC* toc =
                    dynamic_cast< const FrTOC* >( frameSpecInfo( ).FrameObject(
                        FrameSpec::Info::FSI_FR_TOC ) );
                if ( toc )
                {
                    if ( logger( ) )
                    {
                        logger_log_debug( logger( ), 50, "creating instance" );
                    }
                    object_type obj( toc->Create( ) );
                    m_toc = boost::dynamic_pointer_cast< FrTOC >( obj );
                    if ( logger( ) )
                    {
                        logger_log_debug(
                            logger( ),
                            30,
                            "OFrameStream::init() TOC created successfully" );
                    }
                }
                else
                {
                    if ( logger( ) )
                    {
                        logger_log_debug(
                            logger( ), 30, "version (expected for v3)" );
                    }
                }
            }
            catch ( ... )
            {
                //---------------------------------------------------------------
                // Quietly ignore if TOC is not supported.
                //---------------------------------------------------------------
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ), 30, "supported (expected for version 3)" );
                }
            }
            //-----------------------------------------------------------------
            // By default, generate the file checksum
            //-----------------------------------------------------------------
            if ( logger( ) )
            {
                logger_log_debug( logger( ),
                                  30,
                                  "OFrameStream::init() setting up checksums" );
            }
            SetCheckSumFile( CheckSum::CRC );
            if ( frameSpecInfo( ).Version( ) >= 8 )
            {
                //---------------------------------------------------------------
                // By default, generate a checksum per object
                //---------------------------------------------------------------
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ), 50, "setting object checksum" );
                }
                SetCheckSumObject( CheckSum::CRC );
            }
            if ( logger( ) )
            {
                logger_log_debug(
                    logger( ),
                    20,
                    "OFrameStream::init() initialization complete" );
            }
        }

        void
        OFrameStream::write_stream_objects( )
        {
            object_type obj;

            while ( ( obj = Pop( ) ) )
            {
                Write( obj );

                // File checksum is being updated as objects are written
            }
        }

        // Static logger methods (moved from header to avoid ODR violations)
        SimpleLogger*
        IFrameStream::logger()
        {
            static SimpleLogger* instance = get_channel_logger("framecpp.framestream.istream");
            return instance;
        }

        SimpleLogger*
        OFrameStream::logger()
        {
            static SimpleLogger* instance = get_channel_logger("framecpp.framestream.ostream");
            return instance;
        }

        // Dependency injection logger methods (moved from header to avoid
        // circular dependencies)
        SimpleLogger*
        IFrameStream::logger( const FrameCPPServices& services )
        {
            return services.logger_mgr.getLogger(
                "framecpp.framestream.istream" );
        }

        SimpleLogger*
        OFrameStream::logger( const FrameCPPServices& services )
        {
            return services.logger_mgr.getLogger(
                "framecpp.framestream.ostream" );
        }

        void
        IFrameStream::SeedFileChecksumWithHeader( )
        {
            //-----------------------------------------------------------------
            // Check if we have both raw header bytes and a file checksum filter
            //-----------------------------------------------------------------
            if ( !m_raw_header_bytes || !GetCheckSumFile( ) )
            {
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ),
                        25,
                        "SeedFileChecksumWithHeader() skipped - ",
                        "raw_header_bytes: ",
                        static_cast< bool >( m_raw_header_bytes ),
                        ", file_checksum_filter: ",
                        static_cast< bool >( GetCheckSumFile( ) ) );
                }
                return;
            }

            CheckSumFilter* filter = GetCheckSumFile( );
            if ( !filter->GetChecksum( ) )
            {
                if ( logger( ) )
                {
                    logger_log_debug(
                        logger( ), 25,
                        "SeedFileChecksumWithHeader() skipped - no checksum object" );
                }
                return;
            }

            //-----------------------------------------------------------------
            // Feed the raw 40 header bytes to the checksum
            //-----------------------------------------------------------------
            CheckSum* checksum = filter->GetChecksum( );
            checksum->calc( m_raw_header_bytes.get( ), 40 );

            if ( logger( ) )
            {
                logger_log_debug(
                    logger( ),
                    20,
                    "SeedFileChecksumWithHeader() seeded checksum with 40 header bytes, new value: ",
                    checksum->PrettyPrint( ) );
            }
        }

    } // namespace Common

    // Explicit template instantiation for OStream support
    template Common::FrameSpec::version_type StreamVersion<Common::OStream>(const Common::OStream&);

} // namespace FrameCPP
