//
// 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__FrEndOfFrameData_HH
#define FrameCPP_UNIVERSAL__IMPL__FrEndOfFrameData_HH

#if !defined( SWIGIMPORTED )

#include "ldastoolsal/types.hh"

#include "framecpp/Common/SearchContainer.hh"

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

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

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

namespace FrameCPP
{
    namespace Universal
    {
        namespace FrEndOfFrameImpl
        {
            class Data : public Impl::FrObjectMetaData< Data >
            {
            public:
                struct v3
                {
                    using run_type = INT_4U; ///< Run number
                    using frame_type = INT_4U; ///< Frame number
                };
                struct v4
                {
                    using run_type = INT_4S; ///< Run number
                    using frame_type = v3::frame_type; ///< Frame number
                };
                struct v5
                {
                    using run_type = v4::run_type;
                    using frame_type = v4::frame_type;
                    typedef INT_4U chkType_type; ///< File checksum
                    typedef INT_4U chkSum_type; ///< File checksum
                };

                using v6 = v5;
                using v7 = v6;

                struct v8
                {
                    using run_type = v7::run_type;
                    using frame_type = v7::frame_type;
                    using GTimeS_type =
                        INT_4U; ///< Frame start time in GPS seconds
                    using GTimeN_type = INT_4U; ///< Frame start time residual
                    using GTime_type =
                        GPSTime; ///< Frmae start time in GPS units
                    using chkSum_type = v7::chkSum_type; ///< File checksum
                };
                using v9 = v8;

                using current_version = v9;

                using run_type = current_version::run_type;
                using frame_type = current_version::frame_type;
                using GTimeS_type = current_version::GTimeS_type;
                using GTimeN_type = current_version::GTimeN_type;
                using GTime_type = current_version::GTime_type;
                using chkSum_type =
                    current_version::chkSum_type; ///< File checksum

                static run_type constexpr DEFAULT_RUN{
                    0
                }; ///< Default run number
                static frame_type constexpr DEFAULT_FRAME{
                    0
                }; ///< Default frame number
                static GTimeS_type constexpr DEFAULT_GTIME_S{
                    0
                }; ///< Default start time in GPS seconds
                static GTimeN_type constexpr DEFAULT_GTIME_N{
                    0
                }; ///< Default start time residual

                //-----------------------------------------------------------------
                /// @brief Default constructor
                //-----------------------------------------------------------------
                Data( )
                    : run( DEFAULT_RUN ), frame( DEFAULT_FRAME ),
                      GTime( DEFAULT_GTIME_S, DEFAULT_GTIME_N )
                {
                }

                //-----------------------------------------------------------------
                /// \brief Run number of the frame
                /// \return
                ///     The run number of frame.
                ///     It is the same as the value in the FrameH run datum.
                //-----------------------------------------------------------------
                inline run_type
                GetRun( ) const
                {
                    return ( run );
                }

                //-----------------------------------------------------------------
                /// \brief frame number
                ///
                /// \return
                ///     The frame number.
                ///     It is the same as the value in the FrameH frame datum.
                //-----------------------------------------------------------------
                inline frame_type
                GetFrame( ) const
                {
                    return ( frame );
                }

                //-----------------------------------------------------------------
                /// \brief Get the GPS start time of this frame
                ///
                /// \return
                ///     The start time of the frame.
                //-----------------------------------------------------------------
                inline const GTime_type&
                GetGTime( ) const
                {
                    return ( GTime );
                }

                //-----------------------------------------------------------------
                /// \brief Field-by-field equality on the FrEndOfFrame data slice.
                //-----------------------------------------------------------------
                bool
                operator==( const Data& RHS ) const
                {
                    return ( ( run == RHS.run ) &&
                             ( frame == RHS.frame ) &&
                             ( GTime == RHS.GTime ) );
                }

            protected:
                //-------------------------------------------------------
                /// Run number.
                /// This is the same as the FrameH::rum member
                //-------------------------------------------------------
                run_type run;
                //-------------------------------------------------------
                /// Frame number, monotonically increasing until end of run;
                /// This is the same as the FrameH::frame number datum.
                //-------------------------------------------------------
                frame_type frame;
                //-------------------------------------------------------
                /// Frame start time in GPS seconds.
                //-------------------------------------------------------
                GTime_type GTime;
            };

        } // namespace FrEndOfFrameImpl
    } // namespace Universal
} // namespace FrameCPP

FR_OBJECT_META_DATA_DECLARE_UNIVERSAL( FrEndOfFrameImpl )

#endif /* ! defined(SWIGIMPORTED) */

#endif /* FrameCPP_UNIVERSAL__IMPL__FrEndOfFrameData_HH */
