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

#include <framecpp_config.h>

#include "framecpp/Common/IOStream.hh"
#include "framecpp/Common/FrameSpec.tcc"

#include "framecpp/Universal/FrEndOfFrame.hh"

#include "framecpp/Universal/FrameH.hh"
#include "framecpp/Universal/FrSE.hh"
#include "framecpp/Universal/FrSH.hh"

#include "framecpp/Universal/PTR_STRUCT.hh"


using FrameCPP::Common::Description;
using FrameCPP::Common::FrameSpec;

//-----------------------------------------------------------------------
// Local functions and variables
//-----------------------------------------------------------------------

FR_OBJECT_META_DATA_DEFINE_UNIVERSAL( FrameHImpl,
                                      FSI_FRAME_H,
                                      "FrameH",
                                      "Frame Header Structure" )

namespace FrameCPP
{
    namespace Universal
    {
        //===================================================================
        //
        //===================================================================
        FrameH::FrameH( )
        {
        }

        FrameH::FrameH( const name_type&  name,
                        run_type          run,
                        frame_type        frame,
                        const GTime_type& time,
                        const dt_type     dt,
                        dataQuality_type  dqual )
        {
            Data::name = name;
            Data::run = run;
            Data::frame = frame;
            Data::GTime = time;
            Data::dt = dt;
            Data::dataQuality = dqual;
        }

        //=======================================================================
        //
        //=======================================================================
        FrameH::FrameH( const FrameH& frame )
        {
            Data::name = frame.GetName( );
            Data::run = frame.GetRun( );
            Data::frame = frame.GetFrame( );
            Data::GTime = frame.GetGTime( );
            Data::dt = frame.GetDt( );
            Data::dataQuality = frame.GetDataQuality( );

            Data::type = frame.type;
            Data::user = frame.user;
            Data::detectSim = frame.detectSim;
            Data::detectProc = frame.detectProc;
            Data::history = frame.history;
            Data::rawData = frame.rawData;
            Data::procData = frame.procData;
            Data::simData = frame.simData;
            Data::event = frame.event;
            Data::simEvent = frame.simEvent;
            Data::summaryData = frame.summaryData;
            Data::auxData = frame.auxData;
            Data::auxTable = frame.auxTable;
        }

        bool
        FrameH::operator==( const Common::FrameSpec::Object& RHS ) const
        {
            return FrameCPP::compare( *this, RHS );
        }
    } // namespace Universal
} // namespace FrameCPP

//=======================================================================
//               C L A S S I C   I O
//=======================================================================
namespace FrameCPP
{
    namespace Universal
    {
        namespace FrameHImpl
        {
            static constexpr INT_2U MAX_REF{ 13 };

            template <>
            const Common::Description*
            ClassicIO< FrameH >::GetDescription( unsigned int frame_stream_version ) const
            {

                Description* description{ nullptr };

                if ( frame_stream_version >= 9 )
                {
                    static Description v9_description;

                    if ( v9_description.size( ) == 0 )
                    {
                        //-----------------------------------------------
                        v9_description( FrSH( Data::FrameSpecName( ),
                                              Data::FrameSpecId( ),
                                              Data::FrameSpecDescription( ) ) );

                        //-----------------------------------------------
                        v9_description(
                            FrSE( "name",
                                  Description::Ascii< v9::name_type >( ),
                                  "Name of project or other experiment "
                                  "description" ) );
                        v9_description( FrSE(
                            "run",
                            Description::Ascii< v9::run_type >( ),
                            "Run number(number<0 reserved for simulated data);"
                            " monotonic for experimental runs." ) );
                        v9_description(
                            FrSE( "frame",
                                  Description::Ascii< v9::frame_type >( ),
                                  "Frame number, monotonically increasing "
                                  "until end of run,"
                                  " re-starting from 0 with each new run" ) );
                        v9_description(
                            FrSE( "dataQuality",
                                  Description::Ascii< v9::dataQuality_type >( ),
                                  "A logical 32-bit word to denote top level "
                                  "quality of data."
                                  " Lowest order bits are reserved in pairs "
                                  "for the various"
                                  " GW detectors" ) );
                        v9_description(
                            FrSE( "GTimeS",
                                  Description::Ascii< v9::GTimeS_type >( ),
                                  "Frame start time in GPS seconds" ) );
                        v9_description(
                            FrSE( "GTimeN",
                                  Description::Ascii< v9::GTimeS_type >( ),
                                  "Frame start time residual, integer "
                                  "nanoseconds" ) );
                        v9_description(
                            FrSE( "dt",
                                  Description::Ascii< v9::dt_type >( ),
                                  "Frame length in seconds." ) );

                        //-----------------------------------------------
                        v9_description( FrSE(
                            "type",
                            PTR_STRUCT::Desc( FrVect::StructName( ) ),
                            "Identifier for array used to store general info "
                            "like the event type." ) );
                        v9_description(
                            FrSE( "user",
                                  PTR_STRUCT::Desc( FrVect::StructName( ) ),
                                  "Identifier for array for user-provided "
                                  "information." ) );
                        v9_description( FrSE(
                            "detectSim",
                            PTR_STRUCT::Desc( FrDetector::StructName( ) ),
                            "Identifier for array storing model or simulation "
                            "parameter data definition" ) );
                        v9_description(
                            FrSE( "detectProc",
                                  PTR_STRUCT::Desc( FrDetector::StructName( ) ),
                                  "Identifier for detector-derived data." ) );
                        v9_description(
                            FrSE( "history",
                                  PTR_STRUCT::Desc( "FrHistory" ),
                                  "Identifier for first history of "
                                  "post-processing with"
                                  " which frame may have been generated." ) );
                        v9_description( FrSE(
                            "rawData",
                            PTR_STRUCT::Desc(
                                rawData_type::element_type::StructName( ) ),
                            "Identifier for the raw data structure" ) );
                        v9_description( FrSE(
                            "procData",
                            PTR_STRUCT::Desc( FrProcData::StructName( ) ),
                            "Identifier for the first post-processed data" ) );
                        v9_description(
                            FrSE( "simData",
                                  PTR_STRUCT::Desc( FrSimData::StructName( ) ),
                                  "Identifier for the first simulated data "
                                  "buffers" ) );
                        v9_description( FrSE(
                            "event",
                            PTR_STRUCT::Desc( FrEvent::StructName( 9 ) ),
                            "Identifier for the first event structure" ) );
                        v9_description( FrSE(
                            "simEvent",
                            PTR_STRUCT::Desc( FrSimEvent::StructName( ) ),
                            "Identifier for the first simulated event data "
                            "structure." ) );
                        v9_description(
                            FrSE( "summaryData",
                                  PTR_STRUCT::Desc( FrSummary::StructName( ) ),
                                  "Identifier for the first statistical "
                                  "summary data" ) );
                        v9_description(
                            FrSE( "auxData",
                                  PTR_STRUCT::Desc( FrVect::StructName( ) ),
                                  "Identifier for the first auxiliary data" ) );
                        v9_description( FrSE(
                            "auxTable",
                            PTR_STRUCT::Desc( FrTable::StructName( ) ),
                            "Identifier for the first auxiliary table data" ) );
                        //-----------------------------------------------
                        v9_description( FrSE( "chkSum",
                                              CheckSumDataClass( ),
                                              CheckSumDataComment( ) ) );
                    }

                    description = &v9_description;
                }
                else if ( frame_stream_version >= 8 )
                {
                    static Description v8_description;

                    if ( v8_description.size( ) == 0 )
                    {
                        //-----------------------------------------------
                        v8_description( FrSH( Data::FrameSpecName( ),
                                              Data::FrameSpecId( ),
                                              Data::FrameSpecDescription( ) ) );

                        //-----------------------------------------------
                        v8_description(
                            FrSE( "name",
                                  Description::Ascii< v8::name_type >( ),
                                  "Name of project or other experiment "
                                  "description" ) );
                        v8_description( FrSE(
                            "run",
                            Description::Ascii< v8::run_type >( ),
                            "Run number(number<0 reserved for simulated data);"
                            " monotonic for experimental runs." ) );
                        v8_description(
                            FrSE( "frame",
                                  Description::Ascii< v8::frame_type >( ),
                                  "Frame number, monotonically increasing "
                                  "until end of run,"
                                  " re-starting from 0 with each new run" ) );
                        v8_description(
                            FrSE( "dataQuality",
                                  Description::Ascii< v8::dataQuality_type >( ),
                                  "A logical 32-bit word to denote top level "
                                  "quality of data."
                                  " Lowest order bits are reserved in pairs "
                                  "for the various"
                                  " GW detectors" ) );
                        v8_description(
                            FrSE( "GTimeS",
                                  Description::Ascii< v8::GTimeS_type >( ),
                                  "Frame start time in GPS seconds" ) );
                        v8_description(
                            FrSE( "GTimeN",
                                  Description::Ascii< v8::GTimeS_type >( ),
                                  "Frame start time residual, integer "
                                  "nanoseconds" ) );
                        v8_description(
                            FrSE( "ULeapS",
                                  Description::Ascii< v8::ULeapS_type >( ),
                                  "The integer number of leap seconds between "
                                  "GPS/AI and UTC in the epoch when the frame "
                                  "is written" ) );
                        v8_description(
                            FrSE( "dt",
                                  Description::Ascii< v8::dt_type >( ),
                                  "Frame length in seconds." ) );

                        //-----------------------------------------------
                        v8_description( FrSE(
                            "type",
                            PTR_STRUCT::Desc( FrVect::StructName( ) ),
                            "Identifier for array used to store general info "
                            "like the event type." ) );
                        v8_description(
                            FrSE( "user",
                                  PTR_STRUCT::Desc( FrVect::StructName( ) ),
                                  "Identifier for array for user-provided "
                                  "information." ) );
                        v8_description( FrSE(
                            "detectSim",
                            PTR_STRUCT::Desc( FrDetector::StructName( ) ),
                            "Identifier for array storing model or simulation "
                            "parameter data definition" ) );
                        v8_description(
                            FrSE( "detectProc",
                                  PTR_STRUCT::Desc( FrDetector::StructName( ) ),
                                  "Identifier for detector-derived data." ) );
                        v8_description(
                            FrSE( "history",
                                  PTR_STRUCT::Desc( "FrHistory" ),
                                  "Identifier for first history of "
                                  "post-processing with"
                                  " which frame may have been generated." ) );
                        v8_description( FrSE(
                            "rawData",
                            PTR_STRUCT::Desc(
                                rawData_type::element_type::StructName( ) ),
                            "Identifier for the raw data structure" ) );
                        v8_description( FrSE(
                            "procData",
                            PTR_STRUCT::Desc( FrProcData::StructName( ) ),
                            "Identifier for the first post-processed data" ) );
                        v8_description(
                            FrSE( "simData",
                                  PTR_STRUCT::Desc( FrSimData::StructName( ) ),
                                  "Identifier for the first simulated data "
                                  "buffers" ) );
                        v8_description( FrSE(
                            "event",
                            PTR_STRUCT::Desc( FrEvent::StructName( 8 ) ),
                            "Identifier for the first event structure" ) );
                        v8_description( FrSE(
                            "simEvent",
                            PTR_STRUCT::Desc( FrSimEvent::StructName( ) ),
                            "Identifier for the first simulated event data "
                            "structure." ) );
                        v8_description(
                            FrSE( "summaryData",
                                  PTR_STRUCT::Desc( FrSummary::StructName( ) ),
                                  "Identifier for the first statistical "
                                  "summary data" ) );
                        v8_description(
                            FrSE( "auxData",
                                  PTR_STRUCT::Desc( FrVect::StructName( ) ),
                                  "Identifier for the first auxiliary data" ) );
                        v8_description( FrSE(
                            "auxTable",
                            PTR_STRUCT::Desc( FrTable::StructName( ) ),
                            "Identifier for the first auxiliary table data" ) );
                        //-----------------------------------------------
                        v8_description( FrSE( "chkSum",
                                              CheckSumDataClass( ),
                                              CheckSumDataComment( ) ) );
                    }

                    description = &v8_description;
                }
                else if ( frame_stream_version >= 5 )
                {
                    static Description v5_description;

                    if ( v5_description.size( ) == 0 )
                    {
                        //-----------------------------------------------
                        v5_description( FrSH( Data::FrameSpecName( ),
                                              Data::FrameSpecId( ),
                                              Data::FrameSpecDescription( ) ) );

                        //-----------------------------------------------
                        v5_description(
                            FrSE( "name",
                                  Description::Ascii< v5::name_type >( ),
                                  "Name of project or other experiment "
                                  "description" ) );
                        v5_description( FrSE(
                            "run",
                            Description::Ascii< v5::run_type >( ),
                            "Run number(number<0 reserved for simulated data);"
                            " monotonic for experimental runs." ) );
                        v5_description(
                            FrSE( "frame",
                                  Description::Ascii< v5::frame_type >( ),
                                  "Frame number, monotonically increasing "
                                  "until end of run,"
                                  " re-starting from 0 with each new run" ) );
                        v5_description(
                            FrSE( "dataQuality",
                                  Description::Ascii< v5::dataQuality_type >( ),
                                  "A logical 32-bit word to denote top level "
                                  "quality of data."
                                  " Lowest order bits are reserved in pairs "
                                  "for the various"
                                  " GW detectors" ) );
                        v5_description(
                            FrSE( "GTimeS",
                                  Description::Ascii< v5::GTimeS_type >( ),
                                  "Frame start time in GPS seconds" ) );
                        v5_description(
                            FrSE( "GTimeN",
                                  Description::Ascii< v5::GTimeS_type >( ),
                                  "Frame start time residual, integer "
                                  "nanoseconds" ) );
                        v5_description(
                            FrSE( "ULeapS",
                                  Description::Ascii< v5::ULeapS_type >( ),
                                  "The integer number of leap seconds between "
                                  "GPS/AI and UTC in the epoch when the frame "
                                  "is written" ) );
                        v5_description(
                            FrSE( "dt",
                                  Description::Ascii< v5::dt_type >( ),
                                  "Frame length in seconds." ) );

                        //-----------------------------------------------
                        v5_description( FrSE(
                            "type",
                            PTR_STRUCT::Desc( FrVect::StructName( ) ),
                            "Identifier for array used to store general info "
                            "like the event type." ) );
                        v5_description(
                            FrSE( "user",
                                  PTR_STRUCT::Desc( FrVect::StructName( ) ),
                                  "Identifier for array for user-provided "
                                  "information." ) );
                        v5_description( FrSE(
                            "detectSim",
                            PTR_STRUCT::Desc( FrDetector::StructName( ) ),
                            "Identifier for array storing model or simulation "
                            "parameter data definition" ) );
                        v5_description(
                            FrSE( "detectProc",
                                  PTR_STRUCT::Desc( FrDetector::StructName( ) ),
                                  "Identifier for detector-derived data." ) );
                        v5_description(
                            FrSE( "history",
                                  PTR_STRUCT::Desc( "FrHistory" ),
                                  "Identifier for first history of "
                                  "post-processing with"
                                  " which frame may have been generated." ) );
                        v5_description( FrSE(
                            "rawData",
                            PTR_STRUCT::Desc(
                                rawData_type::element_type::StructName( ) ),
                            "Identifier for the raw data structure" ) );
                        v5_description( FrSE(
                            "procData",
                            PTR_STRUCT::Desc( FrProcData::StructName( ) ),
                            "Identifier for the first post-processed data" ) );
                        v5_description(
                            FrSE( "simData",
                                  PTR_STRUCT::Desc( FrSimData::StructName( ) ),
                                  "Identifier for the first simulated data "
                                  "buffers" ) );
                        v5_description( FrSE(
                            "event",
                            PTR_STRUCT::Desc( FrEvent::StructName( 5 ) ),
                            "Identifier for the first event structure" ) );
                        v5_description( FrSE(
                            "simEvent",
                            PTR_STRUCT::Desc( FrSimEvent::StructName( ) ),
                            "Identifier for the first simulated event data "
                            "structure." ) );
                        v5_description(
                            FrSE( "summaryData",
                                  PTR_STRUCT::Desc( FrSummary::StructName( ) ),
                                  "Identifier for the first statistical "
                                  "summary data" ) );
                        v5_description(
                            FrSE( "auxData",
                                  PTR_STRUCT::Desc( FrVect::StructName( ) ),
                                  "Identifier for the first auxiliary data" ) );
                        v5_description( FrSE(
                            "auxTable",
                            PTR_STRUCT::Desc( FrTable::StructName( ) ),
                            "Identifier for the first auxiliary table data" ) );
                    }

                    description = &v5_description;
                }
                else if ( frame_stream_version >= 4 )
                {
                    static Description v4_description;

                    if ( v4_description.size( ) == 0 )
                    {
                        //-----------------------------------------------
                        v4_description( FrSH( Data::FrameSpecName( ),
                                              Data::FrameSpecId( ),
                                              Data::FrameSpecDescription( ) ) );

                        //-----------------------------------------------
                        v4_description(
                            FrSE( "name",
                                  Description::Ascii< v4::name_type >( ),
                                  "Name of project or other experiment "
                                  "description" ) );
                        v4_description( FrSE(
                            "run",
                            Description::Ascii< v4::run_type >( ),
                            "Run number(number<0 reserved for simulated data);"
                            " monotonic for experimental runs." ) );
                        v4_description(
                            FrSE( "frame",
                                  Description::Ascii< v4::frame_type >( ),
                                  "Frame number, monotonically increasing "
                                  "until end of run,"
                                  " re-starting from 0 with each new run" ) );
                        v4_description(
                            FrSE( "dataQuality",
                                  Description::Ascii< v4::dataQuality_type >( ),
                                  "A logical 32-bit word to denote top level "
                                  "quality of data."
                                  " Lowest order bits are reserved in pairs "
                                  "for the various"
                                  " GW detectors" ) );
                        v4_description(
                            FrSE( "GTimeS",
                                  Description::Ascii< v4::GTimeS_type >( ),
                                  "Frame start time in GPS seconds" ) );
                        v4_description(
                            FrSE( "GTimeN",
                                  Description::Ascii< v4::GTimeS_type >( ),
                                  "Frame start time residual, integer "
                                  "nanoseconds" ) );
                        v4_description(
                            FrSE( "ULeapS",
                                  Description::Ascii< v4::ULeapS_type >( ),
                                  "The integer number of leap seconds between "
                                  "GPS/AI and UTC in the epoch when the frame "
                                  "is written" ) );
                        v4_description(
                            FrSE( "localTime",
                                  Description::Ascii< v4::localTime_type >( ),
                                  "Local seasonal time - UTC in seconds." ) );
                        v4_description(
                            FrSE( "dt",
                                  Description::Ascii< v4::dt_type >( ),
                                  "Frame length in seconds." ) );

                        //-----------------------------------------------
                        v4_description( FrSE(
                            "type",
                            PTR_STRUCT::Desc( FrVect::StructName( ) ),
                            "Identifier for array used to store general info "
                            "like the event type." ) );
                        v4_description(
                            FrSE( "user",
                                  PTR_STRUCT::Desc( FrVect::StructName( ) ),
                                  "Identifier for array for user-provided "
                                  "information." ) );
                        v4_description( FrSE(
                            "detectSim",
                            PTR_STRUCT::Desc( FrDetector::StructName( ) ),
                            "Identifier for array storing model or simulation "
                            "parameter data definition" ) );
                        v4_description(
                            FrSE( "detectProc",
                                  PTR_STRUCT::Desc( FrDetector::StructName( ) ),
                                  "Identifier for detector-derived data." ) );
                        v4_description(
                            FrSE( "history",
                                  PTR_STRUCT::Desc( "FrHistory" ),
                                  "Identifier for first history of "
                                  "post-processing with"
                                  " which frame may have been generated." ) );
                        v4_description( FrSE(
                            "rawData",
                            PTR_STRUCT::Desc(
                                rawData_type::element_type::StructName( ) ),
                            "Identifier for the raw data structure" ) );
                        v4_description( FrSE(
                            "procData",
                            PTR_STRUCT::Desc( FrProcData::StructName( ) ),
                            "Identifier for the first post-processed data" ) );
                        v4_description(
                            FrSE( "strain",
                                  PTR_STRUCT::Desc( FrProcData::StructName( ) ),
                                  "Identifier for the post-processed strain "
                                  "data (best estimate)" ) );
                        v4_description(
                            FrSE( "simData",
                                  PTR_STRUCT::Desc( FrSimData::StructName( ) ),
                                  "Identifier for the first simulated data "
                                  "buffers" ) );
                        v4_description( FrSE(
                            "trigData",
                            PTR_STRUCT::Desc( FrEvent::StructName( 4 ) ),
                            "Identifier for the first event structure" ) );
                        v4_description( FrSE(
                            "simEvent",
                            PTR_STRUCT::Desc( FrSimEvent::StructName( ) ),
                            "Identifier for the first simulated event data "
                            "structure." ) );
                        v4_description(
                            FrSE( "summaryData",
                                  PTR_STRUCT::Desc( FrSummary::StructName( ) ),
                                  "Identifier for the first statistical "
                                  "summary data" ) );
                        v4_description(
                            FrSE( "auxData",
                                  PTR_STRUCT::Desc( FrVect::StructName( ) ),
                                  "Identifier for the first auxiliary data" ) );
                        v4_description( FrSE(
                            "auxTable",
                            PTR_STRUCT::Desc( FrTable::StructName( ) ),
                            "Identifier for the first auxiliary table data" ) );
                    }

                    description = &v4_description;
                }
                else if ( frame_stream_version >= 3 )
                {
                    static Description v3_description;

                    if ( v3_description.size( ) == 0 )
                    {
                        //-----------------------------------------------
                        v3_description( FrSH( Data::FrameSpecName( ),
                                              Data::FrameSpecId( ),
                                              Data::FrameSpecDescription( ) ) );

                        //-----------------------------------------------
                        v3_description(
                            FrSE( "name",
                                  Description::Ascii< v3::name_type >( ),
                                  "Name of project or other experiment "
                                  "description" ) );
                        v3_description( FrSE(
                            "run",
                            Description::Ascii< v3::run_type >( ),
                            "Run number(number<0 reserved for simulated data);"
                            " monotonic for experimental runs." ) );
                        v3_description(
                            FrSE( "frame",
                                  Description::Ascii< v3::frame_type >( ),
                                  "Frame number, monotonically increasing "
                                  "until end of run,"
                                  " re-starting from 0 with each new run" ) );
                        v3_description(
                            FrSE( "GTimeS",
                                  Description::Ascii< v3::GTimeS_type >( ),
                                  "Frame start time in GPS seconds" ) );
                        v3_description(
                            FrSE( "GTimeN",
                                  Description::Ascii< v3::GTimeS_type >( ),
                                  "Frame start time residual, integer "
                                  "nanoseconds" ) );
                        v3_description(
                            FrSE( "ULeapS",
                                  Description::Ascii< v3::ULeapS_type >( ),
                                  "The integer number of leap seconds between "
                                  "GPS/AI and UTC in the epoch when the frame "
                                  "is written" ) );
                        v3_description(
                            FrSE( "localTime",
                                  Description::Ascii< v3::localTime_type >( ),
                                  "Local seasonal time - UTC in seconds." ) );
                        v3_description(
                            FrSE( "dt",
                                  Description::Ascii< v3::dt_type >( ),
                                  "Frame length in seconds." ) );

                        //-----------------------------------------------
                        v3_description( FrSE(
                            "type",
                            PTR_STRUCT::Desc( FrVect::StructName( ) ),
                            "Identifier for array used to store general info "
                            "like the event type." ) );
                        v3_description(
                            FrSE( "user",
                                  PTR_STRUCT::Desc( FrVect::StructName( ) ),
                                  "Identifier for array for user-provided "
                                  "information." ) );
                        v3_description( FrSE(
                            "detectSim",
                            PTR_STRUCT::Desc( FrDetector::StructName( ) ),
                            "Identifier for array storing model or simulation "
                            "parameter data definition" ) );
                        v3_description(
                            FrSE( "detectProc",
                                  PTR_STRUCT::Desc( FrDetector::StructName( ) ),
                                  "Identifier for detector-derived data." ) );
                        v3_description(
                            FrSE( "history",
                                  PTR_STRUCT::Desc( "FrHistory" ),
                                  "Identifier for first history of "
                                  "post-processing with"
                                  " which frame may have been generated." ) );
                        v3_description( FrSE(
                            "rawData",
                            PTR_STRUCT::Desc(
                                rawData_type::element_type::StructName( ) ),
                            "Identifier for the raw data structure" ) );
                        v3_description( FrSE(
                            "procData",
                            PTR_STRUCT::Desc( FrProcData::StructName( ) ),
                            "Identifier for the first post-processed data" ) );
                        v3_description(
                            FrSE( "strain",
                                  PTR_STRUCT::Desc( FrProcData::StructName( ) ),
                                  "Identifier for the post-processed strain "
                                  "data (best estimate)" ) );
                        v3_description(
                            FrSE( "simData",
                                  PTR_STRUCT::Desc( FrSimData::StructName( ) ),
                                  "Identifier for the first simulated data "
                                  "buffers" ) );
                        v3_description( FrSE(
                            "trigData",
                            PTR_STRUCT::Desc( FrEvent::StructName( 3 ) ),
                            "Identifier for the first event structure" ) );
                        v3_description(
                            FrSE( "summaryData",
                                  PTR_STRUCT::Desc( FrSummary::StructName( ) ),
                                  "Identifier for the first statistical "
                                  "summary data" ) );
                        v3_description(
                            FrSE( "auxData",
                                  PTR_STRUCT::Desc( FrVect::StructName( ) ),
                                  "Identifier for the first auxiliary data" ) );
                    }

                    description = &v3_description;
                }
                return description;
            }

            template <>
            void
            ClassicIO< FrameH >::assign( assign_stream_type&     Stream,
                                         frame_spec_version_type StreamVersion )
            {
                io_name_type io_name;

                if ( StreamVersion >= 3 )
                {
                    Stream >> io_name >> run >> frame >> dataQuality >> GTime >>
                        dt;
                }

                name = io_name;
            }

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

            template <>
            cmn_streamsize_type
            ClassicIO< FrameH >::pBytes( const Common::StreamBase& Stream ) const
            {
                auto frame_stream_version = StreamVersion( Stream );
                return ( io_name_type::Bytes( name ) // name
                         + sizeof( run ) // run;
                         + sizeof( frame ) // frame;
                         + ( ( frame_stream_version >= 4 ) // dataQuality;
                                 ? sizeof( dataQuality ) // Added
                                 : 0 ) //
                         + sizeof( GTimeS_type ) // GTime Seconds;
                         + sizeof( GTimeN_type ) // GTime Nanoeconds;
                         + ( ( frame_stream_version >= 9 ) // ULeapS
                                 ? 0 // Removed
                                 : sizeof( v3::ULeapS_type ) ) //
                         + ( ( frame_stream_version >= 5 ) // localTime
                                 ? 0 // Removed
                                 : sizeof( v3::localTime_type ) ) //
                         + sizeof( dt ) // dt;
                         + ( Stream.PtrStructBytes( ) // type
                             + Stream.PtrStructBytes( ) // user
                             + Stream.PtrStructBytes( ) // detectSim
                             + Stream.PtrStructBytes( ) // detectProc
                             + Stream.PtrStructBytes( ) // history
                             + Stream.PtrStructBytes( ) // rawData
                             + Stream.PtrStructBytes( ) // procData
                             + ( // strain
                                   ( frame_stream_version < 5 )
                                       ? Stream.PtrStructBytes( )
                                       : 0 ) //
                             + Stream.PtrStructBytes( ) // simData
                             + Stream.PtrStructBytes( ) // event
                             + ( // simEvent
                                   ( frame_stream_version >= 4 )
                                       ? Stream.PtrStructBytes( )
                                       : 0 ) //
                             + Stream.PtrStructBytes( ) // summaryData
                             + Stream.PtrStructBytes( ) // auxData
                             + ( // auxTable
                                   ( frame_stream_version >= 4 )
                                       ? Stream.PtrStructBytes( )
                                       : 0 ) //
                             ) // References
                );
            }

            template <>
            ClassicIO< FrameH >::self_type*
            ClassicIO< FrameH >::pCreate( istream_type& Stream ) const
            {
                using FrameCPP::Universal::FrameH;

                auto frame_stream_version = StreamVersion( Stream );
                io_name_type io_name;

                FrameH* obj( new FrameH( ) );

                Stream //
                    >> io_name //
                    >> obj->run //
                    >> obj->frame //
                    ;
                if ( frame_stream_version >= 4 )
                {
                    Stream >> obj->dataQuality;
                }
                Stream >> obj->GTime;
                if ( frame_stream_version <= 8 )
                {
                    // Removed in Version 9
                    v3::ULeapS_type uLeapS;
                    Stream >> uLeapS;
                }
                if ( frame_stream_version < 5 )
                {
                    // Removed in Version 5
                    v3::localTime_type localTime;

                    Stream >> localTime;
                }
                Stream >> obj->dt;
                //
                // Output links to other data structures
                //
                Stream //
                    >> obj->type //
                    >> obj->user //
                    >> obj->detectSim //
                    >> obj->detectProc //
                    >> obj->history //
                    >> &( obj->rawData ) //
                    ;
                Stream //
                    >> obj->procData //
                    ;

                if ( frame_stream_version < 5 )
                {
                    // Removed in Version 5
                    v3::strain_type strain;

                    Stream >> strain;
                }
                Stream //
                    >> obj->simData //
                    >> obj->event //
                    ;
                if ( frame_stream_version >= 4 )
                {
                    Stream >> obj->simEvent;
                }
                Stream //
                    >> obj->summaryData //
                    >> obj->auxData //
                    ;
                if ( frame_stream_version >= 4 )
                {
                    Stream >> obj->auxTable;
                }

                obj->name = io_name;

                return obj;
            }

            template <>
            void
            ClassicIO< FrameH >::pWrite( ostream_type& Stream ) const
            {
                auto frame_stream_version = StreamVersion( Stream );
                Common::OStream::Pointer raw_data_ptr( rawData );

                Stream << io_name_type( name ) << run << frame;
                if ( frame_stream_version >= 4 )
                {
                    Stream << dataQuality;
                }
                Stream << GTime;
                if ( frame_stream_version <= 8 )
                {
                    // Removed in Version 9
                    Stream << v3::ULeapS_type( GetGTime( ).GetLeapSeconds( ) );
                }
                if ( frame_stream_version < 5 )
                {
                    // Removed in Version 5
                    v3::localTime_type localTime(
                        GetGTime( ).GetSeconds( GPSTime::UTC ) );

                    Stream << localTime;
                }
                Stream << dt;
                //
                // Output links to other data structures
                //
                Stream << type << user << detectSim << detectProc << history
                       << raw_data_ptr;
                Stream << procData;
                if ( frame_stream_version < 5 )
                {
                    // Removed in Version 5
                    Stream << v3::strain_type( );
                }
                Stream << simData << event;
                if ( frame_stream_version >= 4 )
                {
                    Stream << simEvent;
                }
                Stream << summaryData << auxData;
                if ( frame_stream_version >= 4 )
                {
                    Stream << auxTable;
                }

                boost::shared_ptr< FrEndOfFrame > eof =
                    boost::make_shared< FrEndOfFrame >( GetRun( ),
                                                        GetFrame( ) );
                Stream.PushSingle( eof );
            }

            template <>
            void
            ClassicIO< FrameH >::readSubset( istream_type& Stream,
                                             INT_4U        ElementMask )
            {
                if ( !( ElementMask & Common::FrameH::DETECT_SIM ) )
                {
                    Stream.RemoveResolver( &( detectSim ), MAX_REF );
                }
                if ( !( ElementMask & Common::FrameH::DETECT_PROC ) )
                {
                    Stream.RemoveResolver( &( detectProc ), MAX_REF );
                }
                if ( !( ElementMask & Common::FrameH::HISTORY ) )
                {
                    Stream.RemoveResolver( &( history ), MAX_REF );
                }
                if ( !( ElementMask & Common::FrameH::TYPE ) )
                {
                    Stream.RemoveResolver( &( type ), MAX_REF );
                }
                if ( !( ElementMask & Common::FrameH::USER ) )
                {
                    Stream.RemoveResolver( &( user ), MAX_REF );
                }
#if WORKING
                if ( !( ElementMask & Common::FrameH::RAW_DATA ) )
                {
                    Stream.RemoveResolver( &( rawData ), MAX_REF );
                }
#endif /* WORKING */
                Stream.RemoveResolver( &( procData ), MAX_REF );
                Stream.RemoveResolver( &( simData ), MAX_REF );
                Stream.RemoveResolver( &( event ), MAX_REF );
                Stream.RemoveResolver( &( simEvent ), MAX_REF );
                Stream.RemoveResolver( &( summaryData ), MAX_REF );
                if ( !( ElementMask & Common::FrameH::AUX_DATA ) )
                {
                    Stream.RemoveResolver( &( auxData ), MAX_REF );
                }
                if ( !( ElementMask & Common::FrameH::AUX_TABLE ) )
                {
                    Stream.RemoveResolver( &( auxTable ), MAX_REF );
                }
            }

            template <>
            void
            ClassicIO< FrameH >::
#if WORKING_VIRTUAL_TOCQUERY
                TOCQuery( int InfoClass, ... ) const
#else /*  WORKING_VIRTUAL_TOCQUERY */
                vTOCQuery( int InfoClass, va_list vl ) const
#endif /*  WORKING_VIRTUAL_TOCQUERY */
            {
                using Common::TOCInfo;

#if WORKING_VIRTUAL_TOCQUERY
                va_list vl;
                va_start( vl, InfoClass );
#endif /*  WORKING_VIRTUAL_TOCQUERY */

                while ( InfoClass != TOCInfo::IC_EOQ )
                {
                    int data_type = va_arg( vl, int );
                    switch ( data_type )
                    {
                    case TOCInfo::DT_INT_2S:
                    {
                        switch ( InfoClass )
                        {
                        default:
                            goto cleanup;
                            break;
                        }
                    }
                    break;
                    case TOCInfo::DT_INT_4S:
                    {
                        INT_4S* data = va_arg( vl, INT_4S* );
                        switch ( InfoClass )
                        {
                        case TOCInfo::IC_RUN:
                            *data = GetRun( );
                            break;
                        default:
                            goto cleanup;
                            break;
                        }
                    }
                    break;
                    case TOCInfo::DT_INT_4U:
                    {
                        INT_4U* data = va_arg( vl, INT_4U* );
                        switch ( InfoClass )
                        {
                        case TOCInfo::IC_DATA_QUALITY:
                            *data = GetDataQuality( );
                            break;
                        case TOCInfo::IC_GTIME_S:
                            *data = GetGTime( ).GetSeconds( );
                            break;
                        case TOCInfo::IC_GTIME_N:
                            *data = GetGTime( ).GetNanoseconds( );
                            break;
                        case TOCInfo::IC_FRAME:
                            *data = GetFrame( );
                            break;
                        default:
                            goto cleanup;
                            break;
                        }
                    }
                    break;
                    case TOCInfo::DT_REAL_8:
                    {
                        REAL_8* data = va_arg( vl, REAL_8* );
                        switch ( InfoClass )
                        {
                        case TOCInfo::IC_DT:
                            *data = GetDt( );
                            break;
                        default:
                            goto cleanup;
                            break;
                        }
                    }
                    break;
                    default:
                        // Stop processing
                        goto cleanup;
                    }
                    InfoClass = va_arg( vl, int );
                }
            cleanup:
#if WORKING_VIRTUAL_TOCQUERY
                va_end( vl )
#endif /*  WORKING_VIRTUAL_TOCQUERY */
                    ;
            }
        } // namespace FrameHImpl
    } // namespace Universal
} // namespace FrameCPP
