//
// LDASTools frameCPP - A library implementing the LIGO/Virgo frame
// specification
//
// Copyright (C) 2019 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_UNIVERSAL__IMPL__FrProcDataData_HH
#define FrameCPP_UNIVERSAL__IMPL__FrProcDataData_HH

#if defined( __cplusplus )
#if !defined( SWIG )
#include <algorithm>
#include <memory>
#include <vector>

#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/nvp.hpp>

#include "ldastoolsal/types.hh"

#include "framecpp/Common/Container.hh"

#include "framecpp/Universal/FrHistory.hh"
#include "framecpp/Universal/FrTable.hh"
#include "framecpp/Universal/FrVect.hh"

#endif /* ! defined(SWIG) */
#endif /* defined(__cplusplus) */


#undef FR_PROC_DATA_TYPE_TYPE
#define FR_PROC_DATA_TYPE_TYPE INT_2U

#undef FR_PROC_DATA_SUB_TYPE_TYPE
#define FR_PROC_DATA_SUB_TYPE_TYPE INT_2U

#undef FR_PROC_DATA_TIME_OFFSET_TYPE
#define FR_PROC_DATA_TIME_OFFSET_TYPE REAL_8

#undef FR_PROC_DATA_T_RANGE_TYPE
#define FR_PROC_DATA_T_RANGE_TYPE REAL_8

#undef FR_PROC_DATA_F_SHIFT_TYPE
#define FR_PROC_DATA_F_SHIFT_TYPE REAL_8

#undef FR_PROC_DATA_PHASE_TYPE
#define FR_PROC_DATA_PHASE_TYPE REAL_4

#undef FR_PROC_DATA_F_RANGE_TYPE
#define FR_PROC_DATA_F_RANGE_TYPE REAL_8

#undef FR_PROC_DATA_BW_TYPE
#define FR_PROC_DATA_BW_TYPE REAL_8

#undef FR_PROC_DATA_AUX_PARAM_VALUE_TYPE
#define FR_PROC_DATA_AUX_PARAM_VALUE_TYPE REAL_8

#undef FR_PROC_DATA_T_RANGE_TYPE
#define FR_PROC_DATA_T_RANGE_TYPE REAL_8

#define FR_PROC_DATA__MIME_TYPE UNKNOWN_TYPE
#define FR_PROC_DATA__MIME_SUB_TYPE UNKNOWN_SUB_TYPE


#undef FR_PROC_DATA_MIME_DATA_TYPE
#define FR_PROC_DATA_MIME_DATA_TYPE CHAR_U

#if defined( __cplusplus )
#if !defined( SWIG )

#include "framecpp/Universal/impl/FrObjectMetaData.hh"

#include "framecpp/Universal/impl/GPSTime.hh"

namespace FrameCPP
{
    namespace Universal
    {
        namespace FrProcDataImpl
        {
            class Data : public Impl::FrObjectMetaData< Data >
            {
            public:
                struct v3
                {
                    using name_type = std::string;
                    using comment_type = std::string;
                    using sampleRate_type = REAL_8;
                    using timeOffsetS_type = INT_4U;
                    using timeOffsetN_type = INT_4U;
                    using fShift_type = REAL_8;
                    //-------------------------------------------------------
                    using data_type = Common::Container< FrVect >;
                    using const_iterator = data_type::const_iterator;
                    using iterator = data_type::iterator;
                    using aux_type = Common::Container< FrVect >;
                    using const_aux_iterator = aux_type::const_iterator;
                    using aux_iterator = aux_type::iterator;
                };
                struct v4
                {
                    using name_type = v3::name_type;
                    using comment_type = v3::comment_type;
                    using sampleRate_type = v3::sampleRate_type;
                    using timeOffsetS_type = v3::timeOffsetS_type;
                    using timeOffsetN_type = v3::timeOffsetN_type;
                    using fShift_type = v3::fShift_type;
                    //-------------------------------------------------------
                    using data_type = v3::data_type;
                    using const_iterator = v3::const_iterator;
                    using iterator = v3::iterator;
                    using aux_type = v3::aux_type;
                    using const_aux_iterator = v3::const_aux_iterator;
                    using aux_iterator = v3::aux_iterator;
                    using table_value_type = FrTable;
                    using table_type = Common::Container< table_value_type >;
                    using const_table_iterator = table_type::const_iterator;
                    using table_iterator = table_type::iterator;
                };
                struct v5
                {
                    enum e_type_type
                    {
                        UNKNOWN_TYPE = 0,
                        TIME_SERIES = 1,
                        FREQUENCY_SERIES = 2,
                        OTHER_1D_SERIES_DATA = 3,
                        TIME_FREQUENCY = 4,
                        WAVELETS = 5,
                        MULTI_DIMENSIONAL = 6
                    };

                    enum e_subType_type
                    {
                        UNKNOWN_SUB_TYPE = 0,
                        /*---------------------------------------------------------------
                          Subtype for fSeries
                          ---------------------------------------------------------------*/
                        DFT = 1,
                        AMPLITUDE_SPECTRAL_DENSITY = 2,
                        POWER_SPECTRAL_DENSITY = 3,
                        CROSS_SPECTRAL_DENSITY = 4,
                        COHERENCE = 5,
                        TRANSFER_FUNCTION = 6
                    };

                    typedef struct auxParamInfo
                    {
                        friend class boost::serialization::access;

                        typedef REAL_8      auxParamValue_type;
                        typedef std::string auxParamName_type;

                        auxParamInfo( ) = default;
                        auxParamInfo( const auxParamInfo& ) = default;

                        auxParamInfo( const auxParamName_type& Name,
                                      auxParamValue_type       Value )
                            : auxParam( Value ), auxParamName( Name )
                        {
                        }

                        inline bool
                        operator==( const auxParamInfo& RHS ) const
                        {
                            bool const retval{
                                ( this == &RHS ) ||
                                ( ( auxParam == RHS.auxParam ) &&
                                  ( auxParamName.compare( RHS.auxParamName ) ==
                                    0 ) )
                            };
#if 0
                            std::cerr
                                << "DEBUG: auxParamInfo(" << retval << ")"
                                << std::endl
                                << " auxParam: " << auxParam << " =?= "
                                << " RHS.auxParam: " << RHS.auxParam
                                << std::endl //
                                << " auxParamName: " << auxParamName << " =?= "
                                << " RHS.auxParamName: " << RHS.auxParamName
                                << std::endl //
                                ;
#endif /* 0 */
                            return retval;
                        }

#if !defined( SWIG )
                        template < class Archive >
                        void
                        serialize( Archive& ar, const unsigned int version )
                        {
                            ar& BOOST_SERIALIZATION_NVP( auxParam );
                            ar& BOOST_SERIALIZATION_NVP( auxParamName );
                        }
#endif /* !defined( SWIG ) */

                        auxParamValue_type auxParam;
                        auxParamName_type  auxParamName;
                    } auxParamInfo_type;

                    using name_type = v4::name_type;
                    using comment_type = v4::comment_type;
                    using type_type = INT_2U;
                    using subType_type = INT_2U;
                    using timeOffset_type = REAL_8;
                    using tRange_type = REAL_8;
                    using fShift_type = v4::fShift_type;
                    using phase_type = REAL_4;
                    using fRange_type = REAL_8;
                    using BW_type = REAL_8;
                    using auxParam_type = std::vector< auxParamInfo_type >;
                    //-------------------------------------------------------
                    using data_type = v4::data_type;
                    using const_iterator = v4::const_iterator;
                    using iterator = v4::iterator;
                    using aux_type = v4::aux_type;
                    using const_aux_iterator = v4::const_aux_iterator;
                    using aux_iterator = v4::aux_iterator;
                    using table_value_type = FrTable;
                    using table_type = Common::Container< table_value_type >;
                    using const_table_iterator = table_type::const_iterator;
                    using table_iterator = table_type::iterator;
                    using history_type = Common::Container< FrHistory >;
                    using const_history_iterator = history_type::const_iterator;
                    using history_iterator = history_type::iterator;
                };
                using v6 = v5;
                using v7 = v6;
                using v8 = v7;
                struct v9
                {
                    enum e_type_type
                    {
                        UNKNOWN_TYPE = 0,
                        TIME_SERIES = 1,
                        FREQUENCY_SERIES = 2,
                        OTHER_1D_SERIES_DATA = 3,
                        TIME_FREQUENCY = 4,
                        WAVELETS = 5,
                        MULTI_DIMENSIONAL = 6,
                        MIME = 7
                    };

                    using e_subType_type = v8::e_subType_type;
                    using auxParamInfo = v8::auxParamInfo;

                    using name_type = v8::name_type;
                    using comment_type = v8::comment_type;
                    using type_type = v8::type_type;
                    using subType_type = v8::subType_type;
                    using timeOffset_type = v8::timeOffset_type;
                    using tRange_type = v8::tRange_type;
                    using fShift_type = v8::fShift_type;
                    using phase_type = v8::phase_type;
                    using fRange_type = v8::fRange_type;
                    using BW_type = v8::BW_type;
                    using auxParam_type = v8::auxParam_type;
                    using mime_type = std::string;
                    using mime_data_type = CHAR_U;
                    //-------------------------------------------------------
                    using data_type = v8::data_type;
                    using const_iterator = v8::const_iterator;
                    using iterator = v8::iterator;
                    using aux_type = v8::aux_type;
                    using const_aux_iterator = v8::const_aux_iterator;
                    using aux_iterator = v8::aux_iterator;
                    using table_type = v8::table_type;
                    using table_value_type = v8::table_value_type;
                    using const_table_iterator = v8::const_table_iterator;
                    using table_iterator = v8::table_iterator;
                    using history_type = v8::history_type;
                    using const_history_iterator = v8::const_history_iterator;
                    using history_iterator = v8::history_iterator;
                };

                using current_version = v9;

                using name_type = current_version::name_type;
                using comment_type = current_version::comment_type;
                using type_type = current_version::type_type;
                using e_type_type = v9::e_type_type;
                using subType_type = current_version::subType_type;
                using e_subType_type = v9::e_subType_type;
                using timeOffset_type = current_version::timeOffset_type;
                using tRange_type = current_version::tRange_type;
                using fShift_type = current_version::fShift_type;
                using phase_type = current_version::phase_type;
                using fRange_type = current_version::fRange_type;
                using BW_type = current_version::BW_type;
                using auxParam_type = current_version::auxParam_type;
                using auxParamInfo = current_version::auxParamInfo;
                using mime_type = current_version::mime_type;
                using mime_data_type = current_version::mime_data_type;
                //-------------------------------------------------------
                using data_type = current_version::data_type;
                using const_iterator = current_version::const_iterator;
                using iterator = current_version::iterator;
                using aux_type = current_version::aux_type;
                using const_aux_iterator = current_version::const_aux_iterator;
                using aux_iterator = current_version::aux_iterator;
                using table_type = current_version::table_type;
                using table_value_type = current_version::table_value_type;
                using const_table_iterator =
                    current_version::const_table_iterator;
                using table_iterator = current_version::table_iterator;
                using history_type = current_version::history_type;
                using const_history_iterator =
                    current_version::const_history_iterator;
                using history_iterator = current_version::history_iterator;

                static constexpr auto UNKNOWN_TYPE = e_type_type::UNKNOWN_TYPE;
                static constexpr auto TIME_SERIES = e_type_type::TIME_SERIES;
                static constexpr auto FREQUENCY_SERIES =
                    e_type_type::FREQUENCY_SERIES;
                static constexpr auto OTHER_1D_SERIES_DATA =
                    e_type_type::OTHER_1D_SERIES_DATA;
                static constexpr auto TIME_FREQUENCY =
                    e_type_type::TIME_FREQUENCY;
                static constexpr auto WAVELETS = e_type_type::WAVELETS;
                static constexpr auto MULTI_DIMENSIONAL =
                    e_type_type::MULTI_DIMENSIONAL;
                static constexpr auto MIME = e_type_type::MIME;

                static constexpr auto UNKNOWN_SUB_TYPE =
                    e_subType_type::UNKNOWN_SUB_TYPE;
                static constexpr auto DFT = e_subType_type::DFT;
                static constexpr auto AMPLITUDE_SPECTRAL_DENSITY =
                    e_subType_type::AMPLITUDE_SPECTRAL_DENSITY;
                static constexpr auto POWER_SPECTRAL_DENSITY =
                    e_subType_type::POWER_SPECTRAL_DENSITY;
                static constexpr auto CROSS_SPECTRAL_DENSITY =
                    e_subType_type::CROSS_SPECTRAL_DENSITY;
                static constexpr auto COHERENCE = e_subType_type::COHERENCE;
                static constexpr auto TRANSFER_FUNCTION =
                    e_subType_type::TRANSFER_FUNCTION;

                static constexpr tRange_type FR_PROC_DATA_DEFAULT_TRANGE{ 0.0 };
                static constexpr fShift_type FR_PROC_DATA_DEFAULT_FSHIFT{ 0.0 };
                static constexpr phase_type FR_PROC_DATA_DEFAULT_PHASE{ 0.0 };
                static constexpr fRange_type FR_PROC_DATA_DEFAULT_FRANGE{ 0.0 };
                static constexpr BW_type FR_PROC_DATA_DEFAULT_BW{ 0.0 };

                //-------------------------------------------------------
                // Legacy types
                //-------------------------------------------------------
                // Backwards compatibility
                using AuxParamList_type = auxParam_type;
                using AuxParam_type = auxParam_type::value_type;

                Data( ) : synced_with_vector_( false )
                {
                }

                inline void
                AppendComment( const std::string& Comment )
                {
                    FrameCPP::Common::AppendComment( comment, Comment );
                }

                inline void
                AppendAuxParam( const auxParam_type::value_type& Param )
                {
                    auxParam.push_back( Param );
                }

                /**
                 * @brief Append MIME data to the FrProData structure
                 *
                 * Create or append to list of MIME data associated with the
                 * FrProcData structure.
                 *
                 * @param[in] Type
                 *  MIME type as a character string (ex: text/plain)
                 * @param[in] Data
                 *  Opeque blob of MIME content
                 * @paran[in] Size
                 *  Size of Data
                 * @param[in] Name
                 *  Name for the FrVect (Default: Same as the name for the
                 *  FrProcData)
                 *
                 * @note
                 *   - This library does not supply any native support for
                 *     interpretation of MIME types or associated data
                 *   - A list of MIME types can be found <a
                 *     href="https://mimetype.io/all-types/">here</a>
                 */
                inline void
                AppendMIME( const mime_type& Type,
                            mime_data_type*  Data,
                            std::size_t      Size,
                            const name_type& Name = "" )
                {
                    if ( !( ( GetType( ) == UNKNOWN_TYPE ) ||
                            ( GetType( ) == MIME ) ) )
                    {
                        throw std::runtime_error(
                            "Unable to concatinate MIME type/data" );
                    }
                    boost::shared_array< mime_data_type > mime_data(
                        new mime_data_type[ Size ] );
                    std::move( Data, &( Data[ Size ] ), mime_data.get( ) );
                    auto dim = FrVect::dimension_type( Size, 1 );
                    auto mime_vector = boost::make_shared< FrVect >(
                        ( Name.size( ) ? Name : GetName( ) ),
                        FrVect::compression_scheme_type::RAW, /* Compress */
                        FrVect::data_types_type::FR_VECT_1U, /* Type */
                        1, /* nDim */
                        &dim, /* dims */
                        Size, /* NData */
                        Size, /* NBytes */
                        mime_data, /* Data */
                        Type /* unitY */ );
                    RefData( ).append( mime_vector );
                    if ( GetType( ) == UNKNOWN_TYPE )
                    {
                        type = MIME;
                    }
                }

                /**
                 * \brief Return the name associate with the FrProcData
                 * structure.
                 *
                 * \return
                 *     The name associated with the FrProcData structure
                 */
                const name_type&
                GetName( ) const
                {
                    return name;
                }

                const name_type& GetNameSlow( ) const;

                /**
                 * \brief A brief description of the FrProcData structure
                 *
                 * \return
                 *     A brief description of the FrProcData structure
                 */
                const comment_type&
                GetComment( ) const
                {
                    return comment;
                }

                inline type_type
                GetType( ) const
                {
                    return ( type );
                }

                inline subType_type
                GetSubType( ) const
                {
                    return ( subType );
                }

                inline timeOffset_type
                GetTimeOffset( ) const
                {
                    return ( timeOffset );
                }

                inline fShift_type
                GetFShift( ) const
                {
                    return ( fShift );
                }

                inline phase_type
                GetPhase( ) const
                {
                    return ( phase );
                }

                inline BW_type
                GetBW( ) const
                {
                    return ( BW );
                }

                inline const auxParam_type&
                GetAuxParam( ) const
                {
                    return ( auxParam );
                }

                inline auxParam_type&
                GetAuxParam( )
                {
                    return ( auxParam );
                }

                /**
                 * \brief Retrieve the frequency range.
                 *
                 * \return
                 *     The frequency range.
                 */
                inline fRange_type
                GetFRange( ) const
                {
                    sync( );
                    return ( fRange );
                }

                /**
                 * \brief Retrieve the time range.
                 *
                 * \return
                 *     The time range.
                 */
                inline tRange_type
                GetTRange( ) const
                {
                    sync( );
                    return ( tRange );
                }

                /**
                 * \brief Convert numeric types to string representation
                 *
                 * \param[in] Type
                 *     Numeric type.
                 *
                 * \return
                 *     The string representation of Type.
                 */
                static const std::string& IDTypeToString( type_type Type );

                /**
                 * \brief Convert numeric sub-types to string representation
                 *
                 * \param[in] Type
                 *     Numeric type.
                 * \param[in] SubType
                 *     Numeric sub-type.
                 *
                 * \return
                 *     The string representation of SubType of Type.
                 */
                static const std::string&
                IDSubTypeToString( type_type Type, subType_type SubType );

                inline void
                SetAuxParam( const auxParam_type& AuxParams )
                {
                    auxParam = AuxParams;
                }
                inline void
                SetComment( const comment_type& Comment )
                {
                    comment = Comment;
                }
                inline void
                SetFRange( fRange_type FRange )
                {
                    fRange = FRange;
                }

                inline void
                SetFShift( fShift_type FShift )
                {
                    fShift = FShift;
                }

                inline void
                SetTimeOffset( timeOffset_type TimeOffset )
                {
                    timeOffset = TimeOffset;
                }

                inline void
                SetTRange( tRange_type TRange )
                {
                    tRange = TRange;
                }

                /**
                 * \brief Identifier for vector for auxilliary data.
                 *
                 * \return
                 *     A constant reference to the auxilliary data.
                 */
                inline const aux_type&
                RefAux( ) const
                {
                    return ( aux );
                }

                /**
                 * \brief Identifier for vector for auxilliary data.
                 *
                 * \return
                 *     A reference to the auxilliary data.
                 */
                inline aux_type&
                RefAux( )
                {
                    return ( aux );
                }

                /**
                 * \brief Identifier for vector for data vector.
                 *
                 * \return
                 *     A constant reference to the data vector.
                 */
                inline const data_type&
                RefData( ) const
                {
                    return ( data );
                }

                /**
                 * \brief Identifier for vector for data vector.
                 *
                 * \return
                 *     A reference to the data vector.
                 */
                inline data_type&
                RefData( )
                {
                    return ( data );
                }

                /**
                 * \brief Identifier for parameter table.
                 *
                 * \return
                 *     A constant reference to the parameter table.
                 */
                inline const table_type&
                RefTable( ) const
                {
                    return ( table );
                }

                /**
                 * \brief Identifier for parameter table.
                 *
                 * \return
                 *     A reference to the parameter table.
                 */
                inline table_type&
                RefTable( )
                {
                    return ( table );
                }

                /**
                 * \brief Identifier for channel history.
                 *
                 * \return
                 *     A constant reference to the channel history.
                 */
                inline const history_type&
                RefHistory( ) const
                {
                    return ( history );
                }

                /**
                 * \brief Identifier for channel history.
                 *
                 * \return
                 *     A reference to the channel history.
                 */
                inline history_type&
                RefHistory( )
                {
                    return ( history );
                }

                /**
                 * \brief equality operator
                 *
                 * \param[in] RHS
                 *     The FrProcData object to be compared.
                 *
                 * \return
                 *     The value true is returned if this object is equivelent
                 *     to the RHS instance; false otherwise.
                 */
                inline bool
                operator==( const Data& RHS ) const
                {
                    bool const retval{
                        ( this == &RHS ) ||
                        ( ( name.compare( RHS.name ) == 0 ) &&
                          ( comment.compare( RHS.comment ) == 0 ) &&
                          ( type == RHS.type ) && ( subType == RHS.subType ) &&
                          ( timeOffset == RHS.timeOffset ) &&
                          ( tRange == RHS.tRange ) &&
                          ( fShift == RHS.fShift ) && ( phase == RHS.phase ) &&
                          ( fRange == RHS.fRange ) && ( BW == RHS.BW ) &&
                          ( auxParam == RHS.auxParam ) &&
                          ( data == RHS.data ) && ( aux == RHS.aux ) &&
                          ( table == RHS.table ) && ( history == RHS.history ) )
                    };

#if 0
                    std::cerr
                        << "DEBUG: FrProcData::operator==(" << retval << ")"
                        << std::endl //
                        // --------------------------------------------------
                        << " name: " << name << " =?= RHS.name: "
                        << RHS.name
                        // --------------------------------------------------
                        << " name: " << comment
                        << " =?= RHS.comment: " << RHS.comment
                        << std::endl //
                        // --------------------------------------------------
                        << " type: " << type << " =?= RHS.type: " << RHS.type
                        << std::endl //
                        // --------------------------------------------------
                        << " subType: " << subType
                        << " =?= RHS.subType: " << RHS.subType
                        << std::endl //
                        // --------------------------------------------------
                        << " timeOffset: " << timeOffset
                        << " =?= RHS.timeOffset: " << RHS.timeOffset
                        << std::endl //
                        // --------------------------------------------------
                        << " tRange: " << tRange
                        << " =?= RHS.tRange: " << RHS.tRange
                        << std::endl //
                        // --------------------------------------------------
                        << " fShift: " << fShift
                        << " =?= RHS.fShift: " << RHS.fShift
                        << std::endl //
                        // --------------------------------------------------
                        << " phase: " << phase
                        << " =?= RHS.phase: " << RHS.phase
                        << std::endl //
                        // --------------------------------------------------
                        << " fRange: " << fRange
                        << " =?= RHS.fRange: " << RHS.fRange
                        << std::endl //
                        // --------------------------------------------------
                        << " BW: " << BW << " =?= RHS.BW: " << RHS.BW
                        << std::endl //
                        // --------------------------------------------------
                        << " auxParam: " << ( auxParam == RHS.auxParam )
                        << std::endl //
                        // --------------------------------------------------
                        << " data: " << ( data == RHS.data )
                        << std::endl //
                        // --------------------------------------------------
                        << " aux: " << ( aux == RHS.aux )
                        << std::endl //
                        // --------------------------------------------------
                        << " table: " << ( table == RHS.table )
                        << std::endl //
                        // --------------------------------------------------
                        << " history: " << ( history == RHS.history )
                        << std::endl //
                        ;
#endif /* 0  */
                    return retval;
                }

                static constexpr phase_type PHASE_UNKNOWN{ 0 };
                static constexpr fRange_type FRANGE_UNKNOWN{ 0 };
                static constexpr BW_type BW_UNKNOWN{ 0 };

            protected:
                /**
                 * \brief Copy core data.
                 *
                 * \param[in] Source
                 *     The source from which to copy the data
                 */
                void
                copy_core( const Data& Source )
                {
                    Data::name = Source.name;
                    Data::comment = Source.comment;
                    Data::type = Source.type;
                    Data::subType = Source.subType;
                    Data::timeOffset = Source.timeOffset;
                    Data::tRange = Source.tRange;
                    Data::fShift = Source.fShift;
                    Data::phase = Source.phase;
                    Data::fRange = Source.fRange;
                    Data::BW = Source.BW;
                    //-----------------------------------------------------------
                    Data::aux = Source.aux;
                    Data::table = Source.table;
                    Data::history = Source.history;
                }

                inline void
                sync( ) const
                {
                    if ( synced_with_vector_ )
                    {
                        const_cast< Data* >( this )->sync_with_vector( );
                    }
                }
                void
                sync_with_vector( )
                {
                    if ( ( synced_with_vector_ == false ) &&
                         ( RefData( ).size( ) > 0 ) )
                    {
                        switch ( GetType( ) )
                        {
                        case TIME_SERIES:
                            SetTRange(
                                ( RefData( )[ 0 ]->GetDim( 0 ).GetNx( ) *
                                  RefData( )[ 0 ]->GetDim( 0 ).GetDx( ) ) );
                            break;
                        case FREQUENCY_SERIES:
                            SetFRange(
                                ( RefData( )[ 0 ]->GetDim( 0 ).GetNx( ) *
                                  RefData( )[ 0 ]->GetDim( 0 ).GetDx( ) ) );
                            break;
                        }
                        synced_with_vector_ = true;
                    }
                }

                //-------------------------------------------------------
                /// Channel name -- must be unique with the frame
                //-------------------------------------------------------
                name_type name;
                //-------------------------------------------------------
                /// Comment
                //-------------------------------------------------------
                comment_type comment;
                //-------------------------------------------------------
                /// Type of data object
                //-------------------------------------------------------
                type_type type = UNKNOWN_TYPE;
                //-------------------------------------------------------
                /// Subtype for f-Series (TBD for other types)
                //-------------------------------------------------------
                subType_type subType = UNKNOWN_SUB_TYPE;
                //-------------------------------------------------------
                /// Offset of 1st sample relative to the frame start time
                /// (seconds)
                //-------------------------------------------------------
                timeOffset_type timeOffset;
                //-------------------------------------------------------
                /// Duration of sampled data (tStop-tStart)
                //-------------------------------------------------------
                tRange_type tRange;
                //-------------------------------------------------------
                /// fShift is the frequency in the original data that
                /// corresponds to 0 Hz in the heterodyned series
                //-------------------------------------------------------
                fShift_type fShift;
                //-------------------------------------------------------
                /// Phase of heterodyning signal at start of dataset (radians, 0
                /// if unknown)
                //-------------------------------------------------------
                phase_type phase;
                //-------------------------------------------------------
                /// Frequency range (=fMax-fMin, 0 if unknown)
                //-------------------------------------------------------
                fRange_type fRange;
                //-------------------------------------------------------
                /// Resolution bandwidth
                //-------------------------------------------------------
                BW_type BW;
                //-------------------------------------------------------
                /// Auxiliary parameters
                //-------------------------------------------------------
                auxParam_type auxParam;
                //-------------------------------------------------------
                /// Data vector. The data vector fro single dimensional types
                /// (t-Series and f-Series) must have a single dimension.
                //-------------------------------------------------------
                data_type data;
                //-------------------------------------------------------
                /// Auxiliary data; use is generic.
                //-------------------------------------------------------
                aux_type aux;
                //-------------------------------------------------------
                /// Parameter table
                //-------------------------------------------------------
                table_type table;
                //-------------------------------------------------------
                /// Channel history.
                //-------------------------------------------------------
                history_type history;
                //=======================================================
                //-------------------------------------------------------
                static constexpr unsigned int MAX_REF{ 4 };
                //=======================================================
                //-------------------------------------------------------
                bool synced_with_vector_;
            }; // class Data
        } // namespace FrProcDataImpl
    } // namespace Universal
} // namespace FrameCPP

FR_OBJECT_META_DATA_DECLARE_UNIVERSAL( FrProcDataImpl )

// Type aliases for SWIG compatibility - defined in terms of Data class types
using FR_PROC_DATA_NAME_TYPE = FrameCPP::Universal::FrProcDataImpl::Data::name_type;
using FR_PROC_DATA_COMMENT_TYPE = FrameCPP::Universal::FrProcDataImpl::Data::comment_type;
using FR_PROC_DATA_MIME_TYPE = FrameCPP::Universal::FrProcDataImpl::Data::mime_type;

#endif /* ! defined(SWIG) */
#endif /* defined(__cplusplus) */

#endif /* FrameCPP_UNIVERSAL__IMPL__FrProcDataData_HH */
