//
// 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__PTR_STRUCTData_HH
#define FrameCPP_UNIVERSAL__IMPL__PTR_STRUCTData_HH

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

namespace FrameCPP
{
    namespace Universal
    {
        namespace PTR_STRUCTImpl
        {
            //-----------------------------------------------------------
            /// @brief Storage space for PTR_STRUCT information
            ///
            /// This stores information about an PTR_STRUCT element that
            /// needs to persist beyond an I/O operation
            //-----------------------------------------------------------
            class Data : public Impl::FrObjectMetaData< Data >
            {
            public:
                struct v3
                {
                    typedef INT_2U class_type;
                    typedef INT_2U instance_type;
                };

                using v4 = v3;

                struct v5
                {
                    using class_type = typename v4::class_type;
                    typedef INT_4U instance_type;
                };

                using v6 = v5;
                using v7 = v6;
                using v8 = v7;
                using v9 = v8;

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

                using current_version = v9;

                using class_type = typename current_version::class_type;
                using instance_type = typename current_version::instance_type;

                using data_class_type = class_type;
                using data_instance_type = instance_type;

                //-----------------------------------------------------------------
                /// \brief Retrieve the class identifier.
                ///
                /// \return
                ///     The class identifier.
                //-----------------------------------------------------------------
                virtual class_type
                Class( ) const
                {
                    return ( data_class );
                }

                //-----------------------------------------------------------------
                /// \brief Establish the class identifier.
                ///
                /// \param[in] Value
                ///     The class identifier.
                //-----------------------------------------------------------------
                virtual void
                Class( class_type Value )
                {
                    data_class = Value;
                }

                //-----------------------------------------------------------------
                /// \brief Retrieve the class identifier.
                //-----------------------------------------------------------------
                inline data_class_type
                ClassRaw( ) const
                {
                    return data_class;
                }

                //-----------------------------------------------------------------
                /// \brief Retrieve the instance of the class.
                ///
                /// \return
                ///     The instance of the class.
                //-----------------------------------------------------------------
                virtual instance_type
                Instance( ) const
                {
                    return ( data_instance );
                }

                //-----------------------------------------------------------------
                /// \brief Establish the instance of the class.
                ///
                /// \param[in] Value
                ///     The instance of the class.
                //-----------------------------------------------------------------
                virtual void
                Instance( instance_type Value )
                {
                    data_instance = Value;
                }

                //-----------------------------------------------------------------
                /// \brief Establish the instance of the class.
                ///
                /// \return
                ///     The instance of the class.
                //-----------------------------------------------------------------
                inline data_instance_type
                InstanceRaw( ) const
                {
                    return data_instance;
                }

                inline bool
                operator==( const Data& RHS ) const
                {
                    return ( ( RHS == *this ) ||
                             ( ( data_class == RHS.data_class ) &&
                               ( data_instance == RHS.data_instance ) ) );
                }

            protected:
                //-----------------------------------------------------------------
                /// \brief The class identifier
                ///
                /// The class identifier of the object.
                /// The values of 0, 1, and 2 are reserved by the frame
                /// specification.
                /// The value 0 is used to partially identify the end of
                /// series of chained objects.
                /// The value 1 is reserved to identify the FrSH class of
                /// objects. The vlaue 2 is reserved to identify the FrSE class
                /// of objects. All other values are at the descretion of the
                /// library implementing the frame specification.
                //-----------------------------------------------------------------
                data_class_type data_class = 0;

                //-----------------------------------------------------------------
                /// \brief Occurence counter.
                ///
                /// Counter for occurrence of this class of object within the
                /// current frame or current file.
                /// It starts from zero (0).
                ///
                /// \note
                /// All instance counters are set to zero (0) after FrEndOfFrame
                /// \b and FrEndOfFile.
                //-----------------------------------------------------------------
                data_instance_type data_instance = 0;
            };
        }; // namespace PTR_STRUCTImpl

    } // namespace Universal

} // namespace FrameCPP

FR_OBJECT_META_DATA_DECLARE_UNIVERSAL( PTR_STRUCTImpl )

#endif /* FrameCPP_UNIVERSAL__IMPL__PTR_STRUCTData_HH */
