//
// LDASTools frameCPP - A library implementing the LIGO/Virgo frame
// specification
//
// Copyright (C) 2025 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
//

#ifndef FrameCPP_Archive_DebugArchive_HH
#define FrameCPP_Archive_DebugArchive_HH

#if !defined( SWIGIMPORTED )
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/version.hpp>
#include <boost/serialization/binary_object.hpp>
#include <boost/archive/detail/common_oarchive.hpp>
#include <boost/archive/detail/register_archive.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/mpl/bool.hpp>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <vector>
#include <typeinfo>
#include <cxxabi.h>
#include <memory>
#include <ctime>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <type_traits>

#include "framecpp/Common/Description.hh"
#include "ldastoolsal/Logger.hh"

// Logger types are already in global namespace from ldastoolsal/Logger.hh
// SimpleLogger and get_channel_logger are available directly

// Forward declaration for Container type trait detection
namespace FrameCPP { 
    namespace Common { 
        template<class T> class Container; 
        template<typename T, const std::string& (T::*F)() const> class SearchContainer;
    } 
}

// Forward declaration for dependency injection (full definition in .cc file)
namespace FrameCPP { namespace Common { struct FrameCPPServices; }}

namespace FrameCPP
{
    namespace Debug
    {
            /// \brief Alignment modes for debug output formatting
            enum class AlignmentMode
            {
                NONE,         ///< No special alignment - compact format
                SEPARATOR,    ///< Right-justify names, align separator tokens
                COLUMNS       ///< Left-justify names and values in separate columns
            };

            /// \brief Abstract base class for field filtering
            ///
            /// This class provides a filtering mechanism to selectively include
            /// or exclude fields during debug output. Users can implement custom
            /// filters by inheriting from this class and overriding the
            /// shouldInclude() method.
            ///
            /// Usage:
            /// ```cpp
            /// class SkipBinaryData : public FieldFilter {
            /// public:
            ///     bool shouldInclude(const char* field_name, unsigned int version) const override {
            ///         return strcmp(field_name, "compress") != 0 && strcmp(field_name, "data") != 0;
            ///     }
            /// };
            /// ```
            class FieldFilter
            {
            public:
                /// \brief Virtual destructor for proper inheritance
                virtual ~FieldFilter() = default;

                /// \brief Determine if a field should be included in output
                ///
                /// \param[in] field_name Name of the field being processed
                /// \param[in] version Frame specification version (3-9)
                /// \return true if field should be included, false to skip
                virtual bool shouldInclude( const char* field_name, unsigned int version ) const = 0;
            };

            /// \brief Skip binary data fields filter
            ///
            /// This filter excludes common binary data fields that are typically
            /// not useful in human-readable debug output, such as compression
            /// indicators and raw data arrays.
            class SkipBinaryData : public FieldFilter
            {
            public:
                bool shouldInclude( const char* field_name, unsigned int version ) const override
                {
                    // Skip compression and data fields
                    return strcmp( field_name, "compress" ) != 0 &&
                           strcmp( field_name, "data" ) != 0 &&
                           strcmp( field_name, "nBytes" ) != 0;
                }
            };

            /// \brief Skip empty or default-valued fields filter
            ///
            /// This filter attempts to exclude fields that contain empty or
            /// default values to reduce output clutter. Note: This requires
            /// value inspection and may have performance implications.
            class SkipEmptyFields : public FieldFilter
            {
            public:
                bool shouldInclude( const char* field_name, unsigned int version ) const override
                {
                    // For now, skip commonly empty fields
                    // TODO: Implement value-based filtering in future enhancement
                    return strcmp( field_name, "comment" ) != 0 ||
                           strcmp( field_name, "history" ) != 0;
                }
            };

            /// \brief Include only specified fields filter
            ///
            /// This filter creates a whitelist of field names that should be
            /// included in the output, excluding all others.
            class IncludeOnlyFields : public FieldFilter
            {
            private:
                std::vector<std::string> m_included_fields;

            public:
                /// \brief Constructor with field list
                ///
                /// \param[in] fields Vector of field names to include
                explicit IncludeOnlyFields( const std::vector<std::string>& fields )
                    : m_included_fields( fields )
                {
                }

                /// \brief Constructor with initializer list
                ///
                /// \param[in] fields Initializer list of field names to include
                IncludeOnlyFields( std::initializer_list<std::string> fields )
                    : m_included_fields( fields )
                {
                }

                bool shouldInclude( const char* field_name, unsigned int version ) const override
                {
                    return std::find( m_included_fields.begin(), m_included_fields.end(),
                                      std::string( field_name ) ) != m_included_fields.end();
                }
            };

            /// \brief Exclude specified fields filter
            ///
            /// This filter creates a blacklist of field names that should be
            /// excluded from the output, including all others.
            class ExcludeFields : public FieldFilter
            {
            private:
                std::vector<std::string> m_excluded_fields;

            public:
                /// \brief Constructor with field list
                ///
                /// \param[in] fields Vector of field names to exclude
                explicit ExcludeFields( const std::vector<std::string>& fields )
                    : m_excluded_fields( fields )
                {
                }

                /// \brief Constructor with initializer list
                ///
                /// \param[in] fields Initializer list of field names to exclude
                ExcludeFields( std::initializer_list<std::string> fields )
                    : m_excluded_fields( fields )
                {
                }

                bool shouldInclude( const char* field_name, unsigned int version ) const override
                {
                    return std::find( m_excluded_fields.begin(), m_excluded_fields.end(),
                                      std::string( field_name ) ) == m_excluded_fields.end();
                }
            };

            /// \brief Abstract base class for value transformation
            ///
            /// This class provides a transformation mechanism to format field
            /// values before display. Users can implement custom transformers
            /// by inheriting from this class and overriding the transform()
            /// method.
            ///
            /// Usage:
            /// ```cpp
            /// class GPSTimeFormatter : public ValueTransformer {
            /// public:
            ///     std::string transform(const char* field_name, 
            ///                          const std::string& value,
            ///                          const std::string& type_info,
            ///                          unsigned int version) const override {
            ///         if (strcmp(field_name, "GTime") == 0) {
            ///             return formatGPSTime(value);
            ///         }
            ///         return value;
            ///     }
            /// };
            /// ```
            class ValueTransformer
            {
            public:
                /// \brief Virtual destructor for proper inheritance
                virtual ~ValueTransformer() = default;

                /// \brief Transform a field value for display
                ///
                /// \param[in] field_name Name of the field being transformed
                /// \param[in] value String representation of the value
                /// \param[in] type_info Type information string (may be empty)
                /// \param[in] version Frame specification version (3-9)
                /// \return Transformed value string for display
                virtual std::string transform( const char* field_name,
                                               const std::string& value,
                                               const std::string& type_info,
                                               unsigned int version ) const = 0;
            };

            /// \brief GPS time formatter transformer
            ///
            /// This transformer converts GPS time fields (GTime, GTimeS, GTimeN)
            /// from raw seconds to human-readable format with actual date/time.
            class GPSTimeFormatter : public ValueTransformer
            {
            private:
                /// \brief Convert GPS seconds to human-readable date/time
                ///
                /// \param[in] gps_seconds GPS seconds since 1980-01-06 00:00:00 UTC
                /// \return Human-readable date/time string
                std::string formatGPSTime( double gps_seconds ) const
                {
                    // GPS epoch: January 6, 1980, 00:00:00 UTC
                    // Unix epoch: January 1, 1970, 00:00:00 UTC
                    // Difference: 315964800 seconds (excluding leap seconds)
                    const double GPS_UNIX_OFFSET = 315964800.0;
                    
                    // Convert to Unix time (approximate, doesn't account for leap seconds)
                    double unix_time = gps_seconds + GPS_UNIX_OFFSET;
                    
                    // Convert to time_t for formatting
                    time_t time_val = static_cast<time_t>( unix_time );
                    
                    // Format the time
                    char buffer[100];
                    struct tm* time_info = gmtime( &time_val );
                    strftime( buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S UTC", time_info );
                    
                    // Include fractional seconds
                    double fractional = unix_time - static_cast<double>( time_val );
                    
                    std::ostringstream oss;
                    oss << buffer;
                    if ( fractional > 0.0 )
                    {
                        oss << std::fixed << std::setprecision(6) 
                            << fractional << " ";
                    }
                    
                    return oss.str();
                }
                
            public:
                std::string transform( const char* field_name,
                                       const std::string& value,
                                       const std::string& type_info,
                                       unsigned int version ) const override
                {
                    // Check if this is a GPS time field
                    if ( strcmp( field_name, "GTime" ) == 0 ||
                         strcmp( field_name, "GTimeS" ) == 0 ||
                         strcmp( field_name, "gtime" ) == 0 ||
                         strcmp( field_name, "GPSTime" ) == 0 )
                    {
                        try
                        {
                            // Parse the GPS seconds value
                            double gps_seconds = std::stod( value );
                            
                            // Format with both raw value and human-readable time
                            std::ostringstream oss;
                            oss << value << " [" << formatGPSTime( gps_seconds ) << "]";
                            return oss.str();
                        }
                        catch ( const std::exception& )
                        {
                            // If parsing fails, return original value
                            return value;
                        }
                    }
                    return value;
                }
            };

            /// \brief Hexadecimal formatter for numeric fields
            ///
            /// This transformer adds hexadecimal representation for integer
            /// fields that might represent addresses, checksums, or flags.
            class HexFormatter : public ValueTransformer
            {
            public:
                std::string transform( const char* field_name,
                                       const std::string& value,
                                       const std::string& type_info,
                                       unsigned int version ) const override
                {
                    // Common fields that benefit from hex display
                    if ( strcmp( field_name, "checkSum" ) == 0 ||
                         strcmp( field_name, "crc" ) == 0 ||
                         strcmp( field_name, "flags" ) == 0 ||
                         strstr( field_name, "addr" ) != nullptr ||
                         strstr( field_name, "offset" ) != nullptr )
                    {
                        try
                        {
                            // Try to parse as integer
                            long long int_val = std::stoll( value );
                            
                            // Format with hex representation
                            std::ostringstream oss;
                            oss << value << " (0x" << std::hex << int_val << ")";
                            return oss.str();
                        }
                        catch ( const std::exception& )
                        {
                            // If parsing fails, return original value
                            return value;
                        }
                    }
                    return value;
                }
            };

            /// \brief Size formatter for byte count fields
            ///
            /// This transformer converts byte counts to human-readable sizes
            /// (KB, MB, GB) for easier comprehension.
            class SizeFormatter : public ValueTransformer
            {
            public:
                std::string transform( const char* field_name,
                                       const std::string& value,
                                       const std::string& type_info,
                                       unsigned int version ) const override
                {
                    // Fields that represent sizes in bytes
                    if ( strcmp( field_name, "nBytes" ) == 0 ||
                         strcmp( field_name, "size" ) == 0 ||
                         strcmp( field_name, "length" ) == 0 ||
                         strstr( field_name, "_size" ) != nullptr ||
                         strstr( field_name, "Size" ) != nullptr )
                    {
                        try
                        {
                            // Parse the byte count
                            double bytes = std::stod( value );
                            
                            // Format with appropriate unit
                            std::ostringstream oss;
                            if ( bytes < 1024 )
                            {
                                oss << value << " bytes";
                            }
                            else if ( bytes < 1024 * 1024 )
                            {
                                oss << value << " (" << std::fixed << std::setprecision(2) 
                                    << bytes / 1024.0 << " KB)";
                            }
                            else if ( bytes < 1024 * 1024 * 1024 )
                            {
                                oss << value << " (" << std::fixed << std::setprecision(2)
                                    << bytes / (1024.0 * 1024.0) << " MB)";
                            }
                            else
                            {
                                oss << value << " (" << std::fixed << std::setprecision(2)
                                    << bytes / (1024.0 * 1024.0 * 1024.0) << " GB)";
                            }
                            return oss.str();
                        }
                        catch ( const std::exception& )
                        {
                            // If parsing fails, return original value
                            return value;
                        }
                    }
                    return value;
                }
            };

            /// \brief Binary data formatter transformer
            ///
            /// This transformer shows binary data as hex dump with ASCII sidebar
            /// for fields containing raw binary data.
            class BinaryDataFormatter : public ValueTransformer
            {
            private:
                size_t m_bytes_per_line;
                size_t m_max_bytes;
                
            public:
                /// \brief Constructor
                ///
                /// \param[in] bytes_per_line Number of bytes per hex dump line (default: 16)
                /// \param[in] max_bytes Maximum bytes to display (0 = all, default: 256)
                explicit BinaryDataFormatter( size_t bytes_per_line = 16, size_t max_bytes = 256 )
                    : m_bytes_per_line( bytes_per_line )
                    , m_max_bytes( max_bytes )
                {
                }
                
                std::string transform( const char* field_name,
                                       const std::string& value,
                                       const std::string& type_info,
                                       unsigned int version ) const override
                {
                    // Check if this is a binary data field
                    if ( strstr( type_info.c_str(), "binary" ) != nullptr ||
                         strstr( field_name, "data" ) != nullptr ||
                         strstr( field_name, "Data" ) != nullptr ||
                         strstr( field_name, "buffer" ) != nullptr ||
                         strstr( field_name, "Buffer" ) != nullptr )
                    {
                        // If value looks like "[binary data: N bytes]", keep original format
                        if ( value.find( "[binary data:" ) != std::string::npos )
                        {
                            return value;
                        }
                        
                        // For other binary-looking fields, add a note
                        return value + " [binary field]";
                    }
                    return value;
                }
            };

            /// \brief Array formatter transformer
            ///
            /// This transformer provides smart truncation for large arrays,
            /// showing first and last elements with ellipsis in between.
            class ArrayFormatter : public ValueTransformer
            {
            private:
                size_t m_max_elements;
                size_t m_edge_elements;
                
            public:
                /// \brief Constructor
                ///
                /// \param[in] max_elements Maximum elements to show fully (default: 10)
                /// \param[in] edge_elements Elements to show at start/end when truncating (default: 3)
                explicit ArrayFormatter( size_t max_elements = 10, size_t edge_elements = 3 )
                    : m_max_elements( max_elements )
                    , m_edge_elements( edge_elements )
                {
                }
                
                std::string transform( const char* field_name,
                                       const std::string& value,
                                       const std::string& type_info,
                                       unsigned int version ) const override
                {
                    // Check if this looks like an array representation
                    if ( value.length() > 2 && value[0] == '[' && value[value.length()-1] == ']' )
                    {
                        // Check if it's a type summary like "[N elements of type T]"
                        if ( value.find( " elements of type " ) != std::string::npos )
                        {
                            return value; // Keep the summary format
                        }
                        
                        // For actual array data, check if truncation is needed
                        // Count commas to estimate elements
                        size_t comma_count = std::count( value.begin(), value.end(), ',' );
                        
                        if ( comma_count + 1 > m_max_elements )
                        {
                            // Add truncation note
                            size_t pos = value.find_last_of( ']' );
                            if ( pos != std::string::npos )
                            {
                                return value.substr( 0, pos ) + " ... truncated]";
                            }
                        }
                    }
                    return value;
                }
            };

            /// \brief Floating point formatter transformer
            ///
            /// This transformer provides scientific notation and precision control
            /// for floating point values.
            class FloatFormatter : public ValueTransformer
            {
            private:
                int m_precision;
                double m_sci_threshold;
                
            public:
                /// \brief Constructor
                ///
                /// \param[in] precision Decimal precision (default: 6)
                /// \param[in] sci_threshold Threshold for scientific notation (default: 1e6)
                explicit FloatFormatter( int precision = 6, double sci_threshold = 1e6 )
                    : m_precision( precision )
                    , m_sci_threshold( sci_threshold )
                {
                }
                
                std::string transform( const char* field_name,
                                       const std::string& value,
                                       const std::string& type_info,
                                       unsigned int version ) const override
                {
                    // Check if this is a floating point field
                    if ( strstr( type_info.c_str(), "double" ) != nullptr ||
                         strstr( type_info.c_str(), "float" ) != nullptr ||
                         strstr( type_info.c_str(), "REAL" ) != nullptr )
                    {
                        try
                        {
                            double float_val = std::stod( value );
                            
                            // Check if scientific notation is needed
                            if ( std::abs( float_val ) >= m_sci_threshold ||
                                 ( std::abs( float_val ) < 1e-4 && float_val != 0.0 ) )
                            {
                                std::ostringstream oss;
                                oss << std::scientific << std::setprecision( m_precision ) 
                                    << float_val;
                                return oss.str();
                            }
                        }
                        catch ( const std::exception& )
                        {
                            // If parsing fails, return original value
                        }
                    }
                    return value;
                }
            };

            /// \brief Enum/flag formatter transformer
            ///
            /// This transformer shows symbolic names for known enum values
            /// and bit flags.
            class EnumFormatter : public ValueTransformer
            {
            public:
                std::string transform( const char* field_name,
                                       const std::string& value,
                                       const std::string& type_info,
                                       unsigned int version ) const override
                {
                    // Check for common flag/enum fields
                    if ( strcmp( field_name, "type" ) == 0 ||
                         strcmp( field_name, "Type" ) == 0 ||
                         strcmp( field_name, "kind" ) == 0 ||
                         strcmp( field_name, "Kind" ) == 0 ||
                         strcmp( field_name, "mode" ) == 0 ||
                         strcmp( field_name, "Mode" ) == 0 ||
                         strcmp( field_name, "state" ) == 0 ||
                         strcmp( field_name, "State" ) == 0 ||
                         strcmp( field_name, "status" ) == 0 ||
                         strcmp( field_name, "Status" ) == 0 )
                    {
                        try
                        {
                            int enum_val = std::stoi( value );
                            
                            // Add generic enum annotation
                            std::ostringstream oss;
                            oss << value << " [enum value]";
                            
                            // Special handling for known types
                            if ( strcmp( field_name, "type" ) == 0 && enum_val >= 0 && enum_val <= 10 )
                            {
                                // Frame types or data types might use 0-10 range
                                oss << " (type " << enum_val << ")";
                            }
                            
                            return oss.str();
                        }
                        catch ( const std::exception& )
                        {
                            // Not an integer enum
                        }
                    }
                    
                    // Check for bit flags
                    if ( strstr( field_name, "flags" ) != nullptr ||
                         strstr( field_name, "Flags" ) != nullptr ||
                         strstr( field_name, "mask" ) != nullptr ||
                         strstr( field_name, "Mask" ) != nullptr )
                    {
                        try
                        {
                            unsigned int flags = std::stoul( value );
                            
                            std::ostringstream oss;
                            oss << value << " [";
                            
                            // Show which bits are set
                            bool first = true;
                            for ( int bit = 0; bit < 32; ++bit )
                            {
                                if ( flags & ( 1U << bit ) )
                                {
                                    if ( !first ) oss << ", ";
                                    oss << "bit" << bit;
                                    first = false;
                                }
                            }
                            
                            oss << "]";
                            return oss.str();
                        }
                        catch ( const std::exception& )
                        {
                            // Not a numeric flags field
                        }
                    }
                    
                    return value;
                }
            };

            /// \brief Composite transformer that applies multiple transformers
            ///
            /// This transformer allows chaining multiple value transformers
            /// together, applying them in sequence.
            class CompositeTransformer : public ValueTransformer
            {
            private:
                std::vector<const ValueTransformer*> m_transformers;

            public:
                /// \brief Add a transformer to the chain
                ///
                /// \param[in] transformer Transformer to add (not owned)
                void addTransformer( const ValueTransformer* transformer )
                {
                    if ( transformer )
                    {
                        m_transformers.push_back( transformer );
                    }
                }

                std::string transform( const char* field_name,
                                       const std::string& value,
                                       const std::string& type_info,
                                       unsigned int version ) const override
                {
                    std::string result = value;
                    
                    // Apply each transformer in sequence
                    for ( const auto* transformer : m_transformers )
                    {
                        result = transformer->transform( field_name, result, type_info, version );
                    }
                    
                    return result;
                }
            };

            /// \brief Custom boost serialization archive for debug output
            ///
            /// This archive provides human-readable debug output for any Frame
            /// structure that uses boost serialization. It extracts field names
            /// from boost::serialization::nvp objects and formats them with
            /// configurable alignment and type information.
            ///
            /// The archive supports version-aware output, showing version-specific
            /// field annotations and handling the same version evolution logic
            /// as the existing binary serialization archives.
            ///
            /// Usage:
            /// ```cpp
            /// DebugArchive debug_ar(std::cout, 9, AlignmentMode::SEPARATOR);
            /// frame_object.save(debug_ar, 9);
            /// ```
            class DebugArchive : public boost::archive::detail::common_oarchive< DebugArchive >
            {
                friend class boost::serialization::access;
                friend class boost::archive::save_access;
                friend class WalkingDebugArchive;
                
            public:
                typedef boost::mpl::bool_<true> is_saving;
                typedef boost::mpl::bool_<false> is_loading;
                
                /// \brief Constructor with full configuration
                ///
                /// \param[in,out] os Output stream for debug information
                /// \param[in] version Frame specification version (3-9)
                /// \param[in] align_mode Alignment mode for output formatting
                /// \param[in] separator String to separate field names from values
                /// \param[in] indentation Number of spaces for indentation
                /// \param[in] show_type_info Whether to show type information
                /// \param[in] show_version_info Whether to show version annotations
                /// \param[in] max_field_width Maximum field name width (0=auto)
                /// \param[in] max_value_width Maximum value width (0=auto)
                /// \param[in] field_filter Optional field filter (nullptr = show all fields)
                /// \param[in] value_transformer Optional value transformer (nullptr = no transformation)
                DebugArchive( std::ostream& os,
                              unsigned int version,
                              AlignmentMode align_mode = AlignmentMode::SEPARATOR,
                              const std::string& separator = " : ",
                              int indentation = 2,
                              bool show_type_info = true,
                              bool show_version_info = true,
                              size_t max_field_width = 0,
                              size_t max_value_width = 0,
                              const FieldFilter* field_filter = nullptr,
                              const ValueTransformer* value_transformer = nullptr );

                /// \brief Save primitive types (required by boost::serialization)
                template< class T >
                void save( const T& t )
                {
                    // For primitive types, we don't have nvp, so just format the value
                    std::ostringstream oss;
                    oss << t;
                    m_os << oss.str();
                }

                /// \brief Begin processing pass
                ///
                /// For alignment modes that require width calculation, this
                /// initiates the first pass. For NONE mode, goes directly
                /// to output pass.
                void beginPass( );

                /// \brief Advance to next processing pass
                ///
                /// Transitions from width calculation pass to output pass.
                /// Calculates optimal field and value widths for alignment.
                void nextPass( );

                /// \brief Check if current pass is the output pass
                ///
                /// \return true if currently in output pass, false if in width calculation pass
                bool isOutputPass( ) const;

                /// \brief Core NVP handler - extracts field names and values
                ///
                /// This is the primary interface used by boost serialization.
                /// It extracts the field name from the nvp object and delegates
                /// to type-specific processing methods.
                ///
                /// \tparam T The type of the value being serialized
                /// \param[in] nvp Named value pair containing field name and value
                /// \return Reference to this archive for chaining
                template < typename T >
                DebugArchive& operator&( const boost::serialization::nvp< T >& nvp )
                {
                    const char* field_name = nvp.name( );
                    const T& value = nvp.const_value( );

                    // Check field filter - skip if filtered out
                    if ( m_field_filter && !m_field_filter->shouldInclude( field_name, m_version ) )
                    {
                        return *this;
                    }

                    if ( m_current_pass == 1 )
                    {
                        // First pass: collect field information for width calculation
                        collectFieldInfo( field_name, value );
                    }
                    else
                    {
                        // Second pass: output with proper alignment
                        processField( field_name, value );
                    }
                    return *this;
                }

                /// \brief Alternative operator for compatibility
                template < typename T >
                DebugArchive& operator<<( const boost::serialization::nvp< T >& nvp )
                {
                    return operator&( nvp );
                }

                /// \brief Stream operator for serializable objects
                template < typename T >
                DebugArchive& operator<<( const T& obj )
                {
                    // Route through boost serialization system to access private save methods
                    this->save_override( obj );
                    return *this;
                }

                /// \brief Required archive methods
                void save_binary( const void * address, std::size_t count )
                {
                    // For debug archive, we don't actually save binary data
                }

                unsigned int get_library_version()
                {
                    return m_version; // Return the frame specification version passed to constructor
                }

                /// \brief Override save_override to control version passed to save() methods
                ///
                /// This method intercepts boost::serialization calls for Frame objects
                /// and ensures that their save() method is called with our frame specification
                /// version instead of the default archive version (0).
                /// Boost internal types are handled by explicit overrides below.
                template<class T>
                void save_override(const T& t)
                {
                    // Add debug logging to trace what goes through base class
                    if constexpr (!std::is_same_v<T, boost::archive::version_type> &&
                                  !std::is_same_v<T, boost::archive::object_id_type> &&
                                  !std::is_same_v<T, boost::archive::object_reference_type> &&
                                  !std::is_same_v<T, boost::archive::class_id_type> &&
                                  !std::is_same_v<T, boost::archive::class_id_optional_type> &&
                                  !std::is_same_v<T, boost::archive::class_id_reference_type> &&
                                  !std::is_same_v<T, boost::archive::class_name_type> &&
                                  !std::is_same_v<T, boost::archive::tracking_type> &&
                                  !std::is_same_v<T, boost::serialization::version_type> &&
                                  !std::is_same_v<T, boost::serialization::collection_size_type>)
                    {
                        // Debug logging to see what types go through base DebugArchive
                        static SimpleLogger* debug_logger = get_channel_logger("framecpp.archive.base");
                        logger_log_debug(debug_logger, 40, "Base DebugArchive::save_override called for type: ", typeid(T).name());
                        
                        // Call the object's serialize method directly with our version
                        boost::serialization::serialize_adl(*this, const_cast<T&>(t), m_version);
                    }
                    else
                    {
                        // For boost internal types, ignore them (they're handled by explicit overrides)
                        // This prevents the template instantiation errors
                    }
                }

                /// \brief Override save_override for boost::serialization::nvp 
                ///
                /// Named value pairs should be routed back to our operator& which
                /// handles nvp properly and maintains our custom version control.
                template<class T>
                void save_override(const boost::serialization::nvp<T>& nvp)
                {
                    // Route back to our operator& which handles nvp properly
                    *this & nvp;
                }

                template< class T >
                void register_type( const T * = NULL )
                {
                    // No-op for debug archive
                }

            protected:
                /// \brief Container detection method for derived classes
                ///
                /// Derived classes can provide their own implementation using
                /// template specialization or overloads rather than virtual methods.
                /// This base implementation provides no container detection.
                ///
                /// \tparam T Type of the field value
                /// \param[in] field_name Name of the field
                /// \param[in] value Field value
                /// \return true if field contains a container that should be walked
                template < typename T >
                bool isContainerImpl( const char* field_name, const T& value ) const
                {
                    // Base implementation: no containers detected
                    return false;
                }

                /// \brief Container size detection method for derived classes
                ///
                /// Derived classes can provide their own implementation using
                /// template specialization or overloads rather than virtual methods.
                /// This base implementation supports no containers.
                ///
                /// \tparam T Type of the container
                /// \param[in] container Container to measure
                /// \return Number of elements in the container, or 0 if not a container
                template < typename T >
                size_t getContainerSizeImpl( const T& container ) const
                {
                    // Base implementation: no containers supported
                    return 0;
                }

                /// \brief Container element access method for derived classes
                ///
                /// Derived classes can provide their own implementation using
                /// template specialization or overloads rather than virtual methods.
                /// This base implementation provides no element access.
                ///
                /// \tparam T Type of the container
                /// \param[in] container Container to access
                /// \param[in] index Index of the element to retrieve
                /// \return Pointer to the element, or nullptr if not accessible
                template < typename T >
                const void* getContainerElementImpl( const T& container, size_t index ) const
                {
                    // Base implementation: no elements accessible
                    return nullptr;
                }

                /// \brief Protected getter for output stream access by derived classes
                std::ostream& getOutputStream() { return m_os; }
                std::ostream& getOutputStream() const { return m_os; }

                /// \brief Protected getter for indentation access by derived classes
                int getIndentation() const { return m_indentation; }

                /// \brief Protected getter for show_type_info flag by derived classes
                bool getShowTypeInfo() const { return m_show_type_info; }

                /// \brief Protected wrapper for type name demangling
                std::string protectedDemangleTypeName( const char* mangled_name ) 
                {
                    return demangleTypeName( mangled_name );
                }

                /// \brief Protected wrapper for aligned output
                void protectedOutputAligned( const std::string& name, const std::string& value, const std::string& type_info )
                {
                    outputAligned( name, value, type_info );
                }

            private:
                std::ostream& m_os;                ///< Output stream
                unsigned int m_version;            ///< Frame specification version
                AlignmentMode m_alignment_mode;    ///< Alignment mode
                std::string m_separator;           ///< Field name/value separator
                int m_indentation;                 ///< Indentation level
                bool m_show_type_info;             ///< Show type information
                bool m_show_version_info;          ///< Show version annotations
                size_t m_max_field_width;          ///< Maximum field name width
                size_t m_max_value_width;          ///< Maximum value width
                int m_current_pass;                ///< Current processing pass (1 or 2)
                const FieldFilter* m_field_filter; ///< Optional field filter
                const ValueTransformer* m_value_transformer; ///< Optional value transformer

                // Width tracking for alignment
                size_t m_calculated_field_width;   ///< Calculated field name width
                size_t m_calculated_type_width;    ///< Calculated type width
                size_t m_calculated_value_width;   ///< Calculated value width

                /// \brief Collect field information for width calculation (first pass)
                ///
                /// \tparam T Type of the field value
                /// \param[in] name Field name
                /// \param[in] value Field value
                template < typename T >
                void collectFieldInfo( const char* name, const T& value );

                /// \brief Process and output field (second pass)
                ///
                /// \tparam T Type of the field value
                /// \param[in] name Field name
                /// \param[in] value Field value
                template < typename T >
                void processField( const char* name, const T& value );

                /// \brief Output field with proper alignment
                ///
                /// \param[in] name Field name
                /// \param[in] value_str Formatted value string
                /// \param[in] type_info Type information string
                void outputAligned( const std::string& name,
                                    const std::string& value_str,
                                    const std::string& type_info );

                /// \brief Format value as string
                ///
                /// \tparam T Type of the value
                /// \param[in] value Value to format
                /// \return Formatted string representation
                template < typename T >
                std::string formatValue( const T& value );

                /// \brief Format container value as string
                ///
                /// \tparam T Element type of the container
                /// \param[in] container Container to format
                /// \return Formatted string representation
                template < typename T >
                std::string formatValue( const std::vector< T >& container );

                // Specializations for common streamable types
                std::string formatValue( const std::vector< int >& container );
                std::string formatValue( const std::vector< unsigned int >& container );
                std::string formatValue( const std::vector< float >& container );
                std::string formatValue( const std::vector< double >& container );
                std::string formatValue( const std::vector< std::string >& container );

                /// \brief Format string value (adds quotes)
                ///
                /// \param[in] str String to format
                /// \return Formatted string with quotes
                std::string formatValue( const std::string& str );
                
                /// \brief Format binary object (shows size)
                ///
                /// \param[in] obj Binary object to format
                /// \return Formatted string with binary data size
                std::string formatValue( const boost::serialization::binary_object& obj );

                /// \brief Get type information string
                ///
                /// \tparam T Type to get information for
                /// \return Type information string using Description::Ascii
                template < typename T >
                std::string getTypeInfo( );

                /// \brief Get type information for container
                ///
                /// \tparam T Element type of the container
                /// \param[in] container Container to get type info for
                /// \return Type information string with element count
                template < typename T >
                std::string getTypeInfo( const std::vector< T >& container );

                /// \brief Output proper indentation
                void indent( );

                /// \brief Calculate optimal field and value widths for alignment
                void calculateWidths( );

                /// \brief Demangle C++ type name to human-readable format
                ///
                /// Converts mangled type names (e.g., N8FrameCPP9Universal6FrVectE)
                /// to readable C++ names (e.g., FrameCPP::Universal::FrVect)
                ///
                /// \param[in] mangled_name Mangled type name from typeid().name()
                /// \return Human-readable C++ type name
                std::string demangleTypeName( const char* mangled_name );

                /// \brief Helper implementation for streamable types
                ///
                /// \tparam T Type of the value
                /// \param[in] value Value to format
                /// \param[in] std::true_type Tag indicating type is streamable
                /// \return Formatted string representation
                template < typename T >
                std::string formatValueImpl( const T& value, std::true_type );

                /// \brief Helper implementation for non-streamable types
                ///
                /// \tparam T Type of the value  
                /// \param[in] value Value to format
                /// \param[in] std::false_type Tag indicating type is not streamable
                /// \return Formatted string representation
                template < typename T >
                std::string formatValueImpl( const T& value, std::false_type );
            };

            //=================================================================
            // Template method implementations
            //=================================================================

            template < typename T >
            void DebugArchive::collectFieldInfo( const char* name, const T& value )
            {
                if ( m_alignment_mode == AlignmentMode::NONE )
                    return;

                std::string field_name( name );
                m_calculated_field_width = std::max( m_calculated_field_width, field_name.length( ) );

                // Always track type width since we show it in all alignment modes now
                if ( m_show_type_info )
                {
                    std::string type_info = getTypeInfo< T >( );
                    m_calculated_type_width = std::max( m_calculated_type_width, type_info.length( ) );
                }

                if ( m_alignment_mode == AlignmentMode::COLUMNS )
                {
                    std::string value_str = formatValue( value );
                    m_calculated_value_width = std::max( m_calculated_value_width, value_str.length( ) );
                }
            }

            template < typename T >
            void DebugArchive::processField( const char* name, const T& value )
            {
                std::string field_name( name );
                std::string value_str = formatValue( value );
                std::string type_info = m_show_type_info ? getTypeInfo< T >( ) : "";

                // Apply value transformer if present
                if ( m_value_transformer )
                {
                    value_str = m_value_transformer->transform( name, value_str, type_info, m_version );
                }

                outputAligned( field_name, value_str, type_info );
            }

            // SFINAE helper to detect if a type can be streamed
            template < typename T >
            class is_streamable
            {
                template < typename U >
                static auto test(int) -> decltype( std::declval<std::ostream&>() << std::declval<U>(), std::true_type() );
                
                template < typename >
                static auto test(...) -> std::false_type;
                
            public:
                static constexpr bool value = decltype(test<T>(0))::value;
            };
            
            template < typename T >
            std::string DebugArchive::formatValue( const T& value )
            {
                // Check if this is a type that can be streamed
                return formatValueImpl( value, typename std::conditional<
                    is_streamable<T>::value || std::is_arithmetic<T>::value || std::is_enum<T>::value,
                    std::true_type,
                    std::false_type
                >::type() );
            }
            
            // Helper for streamable types
            template < typename T >
            std::string DebugArchive::formatValueImpl( const T& value, std::true_type )
            {
                std::ostringstream oss;
                oss << value;
                return oss.str( );
            }
            
            // Helper for non-streamable types (like Frame objects)
            template < typename T >
            std::string DebugArchive::formatValueImpl( const T& value, std::false_type )
            {
                // For complex types that can't be streamed, show readable type info
                return std::string("[") + demangleTypeName(typeid(T).name()) + " object]";
            }
            
            // Specialization for binary_object
            inline std::string DebugArchive::formatValue( const boost::serialization::binary_object& obj )
            {
                std::ostringstream oss;
                oss << "[binary data: " << obj.m_size << " bytes]";
                return oss.str( );
            }

            template < typename T >
            std::string DebugArchive::formatValue( const std::vector< T >& container )
            {
                std::ostringstream oss;
                oss << "[" << container.size() << " elements of type " << demangleTypeName(typeid(T).name()) << "]";
                return oss.str( );
            }

            template < typename T >
            std::string DebugArchive::getTypeInfo( )
            {
                if ( !m_show_type_info )
                    return "";

                std::ostringstream oss;
                oss << "[" << demangleTypeName(typeid(T).name()) << "]";
                return oss.str( );
            }

            template < typename T >
            std::string DebugArchive::getTypeInfo( const std::vector< T >& container )
            {
                if ( !m_show_type_info )
                    return "";

                std::ostringstream oss;
                oss << "[" << demangleTypeName(typeid(T).name()) 
                    << "[" << container.size( ) << "]]";
                return oss.str( );
            }

            //=================================================================
            // DebugArchive method implementations
            //=================================================================
            
            inline DebugArchive::DebugArchive( std::ostream& os,
                                        unsigned int version,
                                        AlignmentMode align_mode,
                                        const std::string& separator,
                                        int indentation,
                                        bool show_type_info,
                                        bool show_version_info,
                                        size_t max_field_width,
                                        size_t max_value_width,
                                        const FieldFilter* field_filter,
                                        const ValueTransformer* value_transformer )
                : m_os( os )
                , m_version( version )
                , m_alignment_mode( align_mode )
                , m_separator( separator )
                , m_indentation( indentation )
                , m_show_type_info( show_type_info )
                , m_show_version_info( show_version_info )
                , m_max_field_width( max_field_width )
                , m_max_value_width( max_value_width )
                , m_current_pass( 1 )
                , m_field_filter( field_filter )
                , m_value_transformer( value_transformer )
                , m_calculated_field_width( 0 )
                , m_calculated_type_width( 0 )
                , m_calculated_value_width( 0 )
            {
            }

            inline void DebugArchive::beginPass( )
            {
                m_current_pass = 1;
                m_calculated_field_width = 0;
                m_calculated_type_width = 0;
                m_calculated_value_width = 0;
            }

            inline void DebugArchive::nextPass( )
            {
                m_current_pass = 2;
                calculateWidths( );
            }

            inline bool DebugArchive::isOutputPass( ) const
            {
                return m_current_pass == 2 || m_alignment_mode == AlignmentMode::NONE;
            }

            inline void DebugArchive::calculateWidths( )
            {
                if ( m_max_field_width > 0 )
                    m_calculated_field_width = std::min( m_calculated_field_width, m_max_field_width );
                // No user control over type width - it's determined by the longest type in the structure
                if ( m_max_value_width > 0 && m_alignment_mode == AlignmentMode::COLUMNS )
                    m_calculated_value_width = std::min( m_calculated_value_width, m_max_value_width );
            }

            inline void DebugArchive::outputAligned( const std::string& name,
                                              const std::string& value_str,
                                              const std::string& type_info )
            {
                indent( );

                switch ( m_alignment_mode )
                {
                case AlignmentMode::NONE:
                    m_os << name << m_separator;
                    if ( !type_info.empty( ) )
                        m_os << type_info << m_separator;
                    m_os << value_str;
                    break;

                case AlignmentMode::SEPARATOR:
                    m_os << std::right << std::setw( m_calculated_field_width ) << name
                         << m_separator;
                    if ( !type_info.empty( ) )
                        m_os << std::left << std::setw( m_calculated_type_width ) << type_info << m_separator;
                    m_os << std::left << value_str;
                    break;

                case AlignmentMode::COLUMNS:
                    m_os << std::left << std::setw( m_calculated_field_width ) << name
                         << m_separator;
                    if ( !type_info.empty( ) )
                        m_os << std::left << std::setw( m_calculated_type_width ) << type_info << m_separator;
                    m_os << std::left << std::setw( m_calculated_value_width ) << value_str;
                    break;
                }

                m_os << std::endl;
            }

            inline void DebugArchive::indent( )
            {
                for ( int i = 0; i < m_indentation; ++i )
                    m_os << " ";
            }

            inline std::string DebugArchive::demangleTypeName( const char* mangled_name )
            {
                int status = 0;
                std::unique_ptr<char, void(*)(void*)> demangled(
                    abi::__cxa_demangle(mangled_name, nullptr, nullptr, &status),
                    std::free
                );
                
                if (status == 0 && demangled) {
                    std::string cpp_type = std::string(demangled.get());
                    
                    // Translate C++ types to LDAS types
                    // Basic integer types
                    if (cpp_type == "char" || cpp_type == "signed char") return "INT_1S";
                    if (cpp_type == "unsigned char") return "INT_1U";
                    if (cpp_type == "short" || cpp_type == "short int") return "INT_2S";
                    if (cpp_type == "unsigned short" || cpp_type == "unsigned short int") return "INT_2U";
                    if (cpp_type == "int" || cpp_type == "signed int") return "INT_4S";
                    if (cpp_type == "unsigned int") return "INT_4U";
                    if (cpp_type == "long" || cpp_type == "long int") return "INT_8S";
                    if (cpp_type == "unsigned long" || cpp_type == "unsigned long int") return "INT_8U";
                    if (cpp_type == "long long" || cpp_type == "long long int") return "INT_8S";
                    if (cpp_type == "unsigned long long" || cpp_type == "unsigned long long int") return "INT_8U";
                    
                    // Floating point types
                    if (cpp_type == "float") return "REAL_4";
                    if (cpp_type == "double") return "REAL_8";
                    
                    // Complex types
                    if (cpp_type == "std::complex<float>") return "COMPLEX_8";
                    if (cpp_type == "std::complex<double>") return "COMPLEX_16";
                    
                    // String types
                    if (cpp_type.find("std::__cxx11::basic_string") == 0 || 
                        cpp_type.find("std::basic_string") == 0 ||
                        cpp_type == "std::string") return "STRING";
                    
                    // Pointer types to frame structures
                    if (cpp_type.find("boost::shared_ptr<") == 0) {
                        // Extract the inner type
                        size_t start = cpp_type.find('<') + 1;
                        size_t end = cpp_type.rfind('>');
                        if (start != std::string::npos && end != std::string::npos && end > start) {
                            std::string inner = cpp_type.substr(start, end - start);
                            // Remove namespace prefixes for frame types
                            size_t last_colon = inner.rfind("::");
                            if (last_colon != std::string::npos) {
                                inner = inner.substr(last_colon + 2);
                            }
                            return "PTR_STRUCT(" + inner + " *)";
                        }
                    }
                    
                    // Vector/array types
                    if (cpp_type.find("std::vector<") == 0) {
                        // Extract the inner type and translate it
                        size_t start = cpp_type.find('<') + 1;
                        size_t end = cpp_type.rfind('>');
                        if (start != std::string::npos && end != std::string::npos && end > start) {
                            std::string inner = cpp_type.substr(start, end - start);
                            // Remove allocator part if present
                            size_t comma = inner.find(',');
                            if (comma != std::string::npos) {
                                inner = inner.substr(0, comma);
                                // Trim whitespace
                                while (!inner.empty() && inner.back() == ' ') inner.pop_back();
                            }
                            // Remove namespace prefixes for frame types
                            size_t last_colon = inner.rfind("::");
                            if (last_colon != std::string::npos) {
                                inner = inner.substr(last_colon + 2);
                            }
                            return "PTR_STRUCT(" + inner + " *)";
                        }
                    }
                    
                    // Return original C++ type if no LDAS mapping found
                    return cpp_type;
                } else {
                    // Fallback to mangled name if demangling fails
                    return std::string(mangled_name);
                }
            }

            inline std::string DebugArchive::formatValue( const std::string& str )
            {
                return "\"" + str + "\"";
            }

            //=================================================================
            // Specializations for common streamable vector types
            //=================================================================
            
            // Helper template for streamable types
            template< typename T >
            std::string formatStreamableVector( const std::vector< T >& container )
            {
                std::ostringstream oss;
                oss << "[";
                for ( size_t i = 0; i < container.size( ); ++i )
                {
                    if ( i > 0 )
                        oss << ", ";
                    oss << container[i];
                }
                oss << "]";
                return oss.str( );
            }
            
            // Inline specializations
            inline std::string DebugArchive::formatValue( const std::vector< int >& container )
            {
                return formatStreamableVector( container );
            }

            inline std::string DebugArchive::formatValue( const std::vector< unsigned int >& container )
            {
                return formatStreamableVector( container );
            }

            inline std::string DebugArchive::formatValue( const std::vector< float >& container )
            {
                return formatStreamableVector( container );
            }

            inline std::string DebugArchive::formatValue( const std::vector< double >& container )
            {
                return formatStreamableVector( container );
            }

            inline std::string DebugArchive::formatValue( const std::vector< std::string >& container )
            {
                std::ostringstream oss;
                oss << "[";
                for ( size_t i = 0; i < container.size( ); ++i )
                {
                    if ( i > 0 )
                        oss << ", ";
                    oss << "\"" << container[i] << "\"";
                }
                oss << "]";
                return oss.str( );
            }

    } // namespace Debug

    namespace Archive
    {
        // Type traits for Container detection
        namespace detail
        {
            /// \brief Type trait to detect FrameCPP::Common::Container types
            template<typename T>
            struct is_framecpp_container : std::false_type {};

            /// \brief Specialization for FrameCPP::Common::Container types
            template<typename T>
            struct is_framecpp_container<FrameCPP::Common::Container<T>> : std::true_type {};
            
            /// \brief Specialization for FrameCPP::Common::SearchContainer types
            /// SearchContainer derives from Container, so we need explicit detection
            template<typename T, const std::string& (T::*F)() const>
            struct is_framecpp_container<FrameCPP::Common::SearchContainer<T, F>> : std::true_type {};

            /// \brief Specialization for std::vector types (used in Frame objects)
            template<typename T>
            struct is_framecpp_container<std::vector<T>> : std::true_type {};

            /// \brief Helper variable template for Container detection
            template<typename T>
            constexpr bool is_framecpp_container_v = is_framecpp_container<T>::value;

            /// \brief Type trait to extract element type from Container
            template<typename T>
            struct container_element_type;

            /// \brief Specialization to extract element type from Container<T>
            template<typename T>
            struct container_element_type<FrameCPP::Common::Container<T>> 
            {
                using type = T;
            };
            
            /// \brief Specialization to extract element type from SearchContainer<T, F>
            template<typename T, const std::string& (T::*F)() const>
            struct container_element_type<FrameCPP::Common::SearchContainer<T, F>> 
            {
                using type = T;
            };

            /// \brief Specialization to extract element type from std::vector<T>
            template<typename T>
            struct container_element_type<std::vector<T>> 
            {
                using type = T;
            };

            /// \brief Helper type alias for element type extraction
            template<typename T>
            using container_element_type_t = typename container_element_type<T>::type;
        }

        /// \brief Walking-enabled debug archive for recursive container traversal
        ///
        /// This archive extends DebugArchive with the ability to walk into container
        /// objects and display their contents recursively. It provides configurable
        /// walking depth and cycle detection to prevent infinite recursion.
        ///
        /// The walking functionality allows inspection of PTR_STRUCT containers
        /// by iterating through their elements and pretty-printing each contained
        /// object. This is particularly useful for non-sequential frame reading
        /// where objects are fully loaded but not automatically displayed.
        class WalkingDebugArchive : public Debug::DebugArchive
        {
        private:
            /// \brief Static logger instance - lazily initialized with correct debug levels
            static SimpleLogger* m_static_logger;
            
            /// \brief Services reference for accessing properly initialized loggers
            const FrameCPP::Common::FrameCPPServices& m_services;
            
            /// \brief Get logger for WalkingDebugArchive debugging with proper initialization timing
            static SimpleLogger* logger(const FrameCPP::Common::FrameCPPServices& services);
            
        public:
            /// \brief Constructor with walking configuration
            ///
            /// \param[in,out] os Output stream for debug information
            /// \param[in] version Frame specification version (3-9)
            /// \param[in] align_mode Alignment mode for output formatting
            /// \param[in] separator String to separate field names from values
            /// \param[in] indentation Number of spaces for indentation
            /// \param[in] show_type_info Whether to show type information
            /// \param[in] show_version_info Whether to show version annotations
            /// \param[in] max_field_width Maximum field name width (0=auto)
            /// \param[in] max_value_width Maximum value width (0=auto)
            /// \param[in] field_filter Optional field filter (nullptr = show all fields)
            /// \param[in] value_transformer Optional value transformer (nullptr = no transformation)
            /// \param[in] walk_objects Whether to walk into container objects
            /// \param[in] walk_containers Whether to walk PTR_STRUCT containers
            /// \param[in] walk_depth Maximum recursion depth for walking (0 = no limit)
            /// \param[in] services Services context for proper logger initialization
            WalkingDebugArchive( std::ostream& os,
                                 unsigned int version,
                                 const FrameCPP::Common::FrameCPPServices& services,
                                 Debug::AlignmentMode align_mode = Debug::AlignmentMode::SEPARATOR,
                                 const std::string& separator = " : ",
                                 int indentation = 2,
                                 bool show_type_info = true,
                                 bool show_version_info = true,
                                 size_t max_field_width = 0,
                                 size_t max_value_width = 0,
                                 const Debug::FieldFilter* field_filter = nullptr,
                                 const Debug::ValueTransformer* value_transformer = nullptr,
                                 bool walk_objects = true,
                                 bool walk_containers = true,
                                 int walk_depth = 0 )
                : DebugArchive( os, version, align_mode, separator, indentation,
                                show_type_info, show_version_info, max_field_width,
                                max_value_width, field_filter, value_transformer ),
                  m_services( services ),
                  m_walk_objects( walk_objects ),
                  m_walk_containers( walk_containers ),
                  m_walk_depth( walk_depth ),
                  m_current_depth( 0 )
            {
                logger_log_debug( logger(m_services), 5, 
                                 "WalkingDebugArchive constructor - walk_objects=", walk_objects ? "true" : "false",
                                 ", walk_containers=", walk_containers ? "true" : "false",
                                 ", walk_depth=", walk_depth );
            }

            /// \brief Enhanced NVP handler with walking support
            ///
            /// This override of the base class operator& adds walking capability
            /// for PTR_STRUCT containers and frame objects.
            ///
            /// \tparam T The type of the value being serialized
            /// \param[in] nvp Named value pair containing field name and value
            /// \return Reference to this archive for chaining
            template < typename T >
            WalkingDebugArchive& operator&( const boost::serialization::nvp< T >& nvp )
            {
                const char* field_name = nvp.name();
                const T& value = nvp.const_value();
                
                logger_log_debug( logger(m_services), 30, "Processing field: ", field_name, ", type: ", typeid(T).name() );
                
                // Check if this is a Container type that should be walked
                if constexpr ( detail::is_framecpp_container_v<T> )
                {
                    logger_log_debug( logger(m_services), 20, "Container detected: ", field_name, 
                                     ", walk_containers: ", m_walk_containers ? "true" : "false", 
                                     ", isOutputPass: ", isOutputPass() ? "true" : "false" );
                    
                    // Handle Container types with walking support
                    if ( m_walk_containers && isOutputPass() )
                    {
                        logger_log_debug( logger(m_services), 10, "Walking container: ", field_name );
                        processContainerField( field_name, value );
                    }
                    else
                    {
                        logger_log_debug( logger(m_services), 15, "Using base class for container: ", field_name, " (not walking)" );
                        // Use base class for first pass or when walking is disabled
                        Debug::DebugArchive::operator&( nvp );
                    }
                }
                else
                {
                    logger_log_debug( logger(m_services), 40, "Non-container field: ", field_name );
                    // For non-container types, use base class behavior
                    Debug::DebugArchive::operator&( nvp );
                }

                return *this;
            }

            /// \brief Alternative operator for compatibility with NVPs
            template < typename T >
            WalkingDebugArchive& operator<<( const boost::serialization::nvp< T >& nvp )
            {
                return operator&( nvp );
            }

            /// \brief Stream operator for serializable objects
            template < typename T >
            WalkingDebugArchive& operator<<( const T& obj )
            {
                // Add debug logging to trace operator<< calls
                logger_log_debug( logger(m_services), 25, 
                                 "WalkingDebugArchive::operator<< called for type: ", typeid(T).name() );
                
                // IMPORTANT: Use save_override to enable walking functionality
                // This ensures containers go through our walking-enabled save_override
                save_override( obj );
                return *this;
            }

            /// \brief Override save_override for Container interception
            ///
            /// This method intercepts the serialization of Container objects
            /// to provide walking functionality during serialization.
            template<class T>
            void save_override(const T& t)
            {
                logger_log_debug( logger(m_services), 35, 
                                 "WalkingDebugArchive::save_override called, type: ", typeid(T).name(),
                                 ", is_container: ", detail::is_framecpp_container_v<T> ? "true" : "false" );
                
                if constexpr ( detail::is_framecpp_container_v<T> )
                {
                    // Handle Container types with potential walking
                    logger_log_debug( logger(m_services), 30, "Handling container serialization" );
                    handleContainerSerialization( t );
                }
                else
                {
                    // For non-container types, delegate to base class to handle primitive serialization
                    logger_log_debug( logger(m_services), 40, "Delegating non-container type to base DebugArchive" );
                    
                    // For primitive types and objects without containers, use base class
                    Debug::DebugArchive::save_override(t);
                }
            }
            
            /// \brief Process Container fields with walking support
            ///
            /// This method handles Container and SearchContainer fields to provide
            /// recursive walking functionality when enabled.
            ///
            /// \tparam ContainerType Type of the container (Container<T> or SearchContainer<T, Func>)
            /// \param[in] name Field name
            /// \param[in] container Container to process
            template < typename ContainerType >
            typename std::enable_if<detail::is_framecpp_container_v<ContainerType>, void>::type
            processContainerField( const char* name, const ContainerType& container )
            {
                logger_log_debug( logger(m_services), 10, "processContainerField entered: ", name, ", size: ", container.size() );
                
                // First output the container header using base class logic
                using ElementType = detail::container_element_type_t<ContainerType>;
                std::string field_name( name );
                std::string container_header = "[" + std::to_string(container.size()) + 
                                              " elements of type " + protectedDemangleTypeName(typeid(ElementType).name()) + "]";
                std::string type_info = getShowTypeInfo() ? "PTR_STRUCT(" + protectedDemangleTypeName(typeid(ElementType).name()) + " *)" : "";
                
                logger_log_debug( logger(m_services), 15, "Container header: ", container_header );
                protectedOutputAligned( field_name, container_header, type_info );
                
                // If walking is enabled and we have elements, walk through them
                logger_log_debug( logger(m_services), 15, "Walking check: m_walk_containers=", m_walk_containers ? "true" : "false",
                                 ", empty=", container.empty() ? "true" : "false", 
                                 ", shouldWalkDeeper=", shouldWalkDeeper() ? "true" : "false",
                                 ", isOutputPass=", isOutputPass() ? "true" : "false" );
                                 
                if ( m_walk_containers && !container.empty() && shouldWalkDeeper() && isOutputPass() )
                {
                    logger_log_debug( logger(m_services), 10, "Starting to walk container elements: ", container.size(), " elements" );
                    // Increment depth for recursive walking
                    ++m_current_depth;
                    
                    // Serialize each element
                    for ( size_t i = 0; i < container.size(); ++i )
                    {
                        const auto& element = container[i];
                        
                        // Add indentation
                        indent();
                        for ( int d = 0; d < m_current_depth; ++d )
                        {
                            getOutputStream() << "  ";
                        }
                        getOutputStream() << "[" << i << "]: ";
                        
                        // For std::vector, elements are objects (not pointers), so serialize directly
                        if constexpr ( std::is_same_v<ContainerType, std::vector<ElementType>> )
                        {
                            // std::vector contains value objects
                            *this << element;
                        }
                        else
                        {
                            // FrameCPP::Common::Container contains shared_ptr
                            if ( element )
                            {
                                *this << *element;
                            }
                            else
                            {
                                getOutputStream() << "[null pointer]";
                            }
                        }
                    }
                    
                    // Decrement depth when done
                    --m_current_depth;
                }
            }

        private:
            bool m_walk_objects;        ///< Whether to walk into container objects
            bool m_walk_containers;     ///< Whether to walk PTR_STRUCT containers
            int m_walk_depth;           ///< Maximum recursion depth (0 = no limit)
            mutable int m_current_depth; ///< Current recursion depth

            /// \brief Check if we should walk deeper into containers
            ///
            /// \return true if walking depth limit has not been reached
            bool shouldWalkDeeper() const
            {
                return m_walk_depth == 0 || m_current_depth < m_walk_depth;
            }

            /// \brief Check if a specific field should be walked
            ///
            /// This method determines whether a field contains a container
            /// that should be traversed based on walking configuration.
            ///
            /// \tparam T Type of the field value
            /// \param[in] field_name Name of the field
            /// \param[in] value Field value
            /// \return true if field should be walked
            template < typename T >
            bool shouldWalkField( const char* field_name, const T& value ) const
            {
                return isContainerWalking( field_name, value );
            }

            /// \brief Enhanced container detection for PTR_STRUCT containers
            ///
            /// This method provides enhanced container detection using SFINAE
            /// to detect FrameCPP::Common::Container types at compile time.
            ///
            /// \tparam T Type of the field value
            /// \param[in] field_name Name of the field
            /// \param[in] value Field value
            /// \return true if field contains a container that should be walked
            template < typename T >
            bool isContainerWalking( const char* field_name, const T& value ) const
            {
                // Use type traits for compile-time detection
                if constexpr ( detail::is_framecpp_container_v<T> )
                {
                    // This is a Container<SomeType> - should be walked if it has elements
                    return !value.empty();
                }
                else
                {
                    // Fallback to field name-based detection for other types
                    std::string name( field_name );
                    return ( name.find( "data" ) != std::string::npos ||
                             name.find( "event" ) != std::string::npos ||
                             name.find( "proc" ) != std::string::npos ||
                             name.find( "sim" ) != std::string::npos ||
                             name.find( "history" ) != std::string::npos ||
                             name.find( "detector" ) != std::string::npos ||
                             name.find( "summary" ) != std::string::npos ||
                             name.find( "aux" ) != std::string::npos ||
                             name.find( "Table" ) != std::string::npos );
                }
            }

            /// \brief Container size detection using SFINAE
            ///
            /// This method determines the number of elements in a container
            /// using compile-time type detection.
            ///
            /// \tparam T Type of the container
            /// \param[in] container Container to measure
            /// \return Number of elements in the container, or 0 if not a container
            template < typename T >
            size_t getContainerSizeWalking( const T& container ) const
            {
                if constexpr ( detail::is_framecpp_container_v<T> )
                {
                    // This is a Container<SomeType> - return actual size
                    return container.size();
                }
                else
                {
                    // Not a container - return 0
                    return 0;
                }
            }

            /// \brief Container element access using SFINAE
            ///
            /// This method provides access to individual elements within a
            /// container using compile-time type detection.
            ///
            /// \tparam T Type of the container
            /// \param[in] container Container to access
            /// \param[in] index Index of the element to retrieve
            /// \return Pointer to the element, or nullptr if not accessible
            template < typename T >
            const void* getContainerElementWalking( const T& container, size_t index ) const
            {
                if constexpr ( detail::is_framecpp_container_v<T> )
                {
                    // This is a Container<SomeType> - access element via shared_ptr
                    if ( index < container.size() && container[index] )
                    {
                        return container[index].get();  // Get raw pointer from shared_ptr
                    }
                }
                // Not a container or invalid index - return nullptr
                return nullptr;
            }

            /// \brief Walk into a container and display its contents
            ///
            /// This method handles the actual traversal of container objects,
            /// incrementing depth and recursively printing contained elements.
            ///
            /// \tparam T Type of the container
            /// \param[in] field_name Name of the container field
            /// \param[in] container Container to walk
            template < typename T >
            void walkContainer( const char* field_name, const T& container )
            {
                // Increment depth for recursive walking
                ++m_current_depth;

                // Get container size using the walking-specific implementation
                size_t container_size = getContainerSizeWalking( container );
                
                if ( container_size > 0 )
                {
                    // Print header for container contents
                    indent();
                    getOutputStream() << "Contents of " << field_name << " [" << container_size << " elements]:" << std::endl;
                    
                    // Iterate through container elements
                    for ( size_t i = 0; i < container_size; ++i )
                    {
                        const void* element = getContainerElementWalking( container, i );
                        if ( element )
                        {
                            // Print element header
                            indent();
                            getOutputStream() << "  [" << i << "]: ";
                            
                            // TODO: Need to pretty-print the element object
                            // This requires knowledge of the element type for boost::serialization
                            // For now, just indicate that an element exists
                            getOutputStream() << "[Element at " << element << "]" << std::endl;
                        }
                    }
                }

                // Decrement depth when done
                --m_current_depth;
            }
            
            /// \brief Helper method for indentation based on current depth
            void indent() const
            {
                for ( int i = 0; i < (m_current_depth + 1) * getIndentation(); ++i )
                    getOutputStream() << " ";
            }

            /// \brief Handle Container serialization with potential walking
            ///
            /// This method handles the serialization of Container objects and
            /// performs recursive walking if enabled.
            ///
            /// \tparam T Container type
            /// \param[in] container Container to serialize and potentially walk
            template < typename T >
            void handleContainerSerialization( const T& container )
            {
                logger_log_debug( logger(m_services), 25, 
                                 "handleContainerSerialization: container size=", container.size(),
                                 ", walk_objects=", m_walk_objects ? "true" : "false",
                                 ", walk_containers=", m_walk_containers ? "true" : "false",
                                 ", shouldWalkDeeper=", shouldWalkDeeper() ? "true" : "false",
                                 ", isOutputPass=", isOutputPass() ? "true" : "false" );
                
                // First, perform normal serialization using base class
                Debug::DebugArchive::save_override( container );

                // If walking is enabled and we're in output pass, walk the container
                if ( ( m_walk_objects || m_walk_containers ) && isOutputPass() && shouldWalkDeeper() )
                {
                    if ( !container.empty() )
                    {
                        logger_log_debug( logger(m_services), 20, "Walking container with ", container.size(), " elements" );
                        // Print container contents header
                        getOutputStream() << std::endl;
                        indent();
                        getOutputStream() << "  Container Contents [" << container.size() << " elements]:" << std::endl;
                        
                        // Walk through each element
                        walkContainerElements( container );
                    }
                    else
                    {
                        logger_log_debug( logger(m_services), 30, "Container is empty, skipping walk" );
                    }
                }
                else
                {
                    logger_log_debug( logger(m_services), 30, "Not walking container - conditions not met" );
                }
            }

            /// \brief Walk through container elements recursively
            ///
            /// This method iterates through Container elements and pretty-prints each one.
            ///
            /// \tparam T Container type
            /// \param[in] container Container to walk through
            template < typename T >
            void walkContainerElements( const T& container )
            {
                ++m_current_depth;

                size_t index = 0;
                for ( const auto& element : container )
                {
                    if ( element )  // Check if shared_ptr is valid
                    {
                        // Print element header
                        indent();
                        getOutputStream() << "  [" << index << "]: ";
                        
                        // Recursively serialize the element object
                        getOutputStream() << std::endl;
                        ++m_current_depth;
                        
                        // Use the element's own serialization
                        *this << *element;  // This should trigger element's serialize method
                        
                        --m_current_depth;
                    }
                    ++index;
                }

                --m_current_depth;
            }
        };

    } // namespace Archive
} // namespace FrameCPP

// Register the archives with boost::serialization
BOOST_SERIALIZATION_REGISTER_ARCHIVE( FrameCPP::Debug::DebugArchive )
BOOST_SERIALIZATION_REGISTER_ARCHIVE( FrameCPP::Archive::WalkingDebugArchive )

#endif /* !defined( SWIGIMPORTED ) */

#endif /* FrameCPP_Archive_DebugArchive_HH */