/*
 * 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
 */

#ifndef FrameCPP__UNIVERSAL__Specs_HH
#define FrameCPP__UNIVERSAL__Specs_HH

#include "ldastoolsal/types.hh"

#ifndef SWIGIMPORTED
#include "framecpp/Common/DetectorNames.hh"
#endif /* SWIGIMPORTED */
#include "framecpp/Common/FrameSpec.hh"

#if defined( __cplusplus ) && !defined( SWIG )
namespace FrameCPP
{
    namespace Common
    {
        class OFrameStreamGen;
    }

    namespace Universal
    {
        typedef REAL_4 dt_type;
        typedef INT_8U position_type;

        typedef INT_4U                        checksum_type;
        typedef Common::FrameSpec::class_type class_type;

        const CHAR_U DATA_FORMAT_VERSION = 0;
        const CHAR_U LIBRARY_MINOR_VERSION = 0;

        template < typename ObjectType >
        class ObjectWithChecksum
            : public Common::FrameSpec::ObjectWithChecksum< ObjectType,
                                                            checksum_type >
        {
        private:
            typedef Common::FrameSpec::ObjectWithChecksum< ObjectType,
                                                           checksum_type >
                object_base_type;

        public:
            typedef Common::FrameSpec::Object::demote_arg_type demote_arg_type;
            typedef Common::FrameSpec::Object::demote_stream_type
                demote_stream_type;
            typedef Common::FrameSpec::Object::promote_arg_type
                promote_arg_type;
            typedef Common::FrameSpec::Object::promote_stream_type
                promote_stream_type;

            ObjectWithChecksum( ) : object_base_type( DATA_FORMAT_VERSION )
            {
            }

            /**
             * \brief Constructor
             */
            ObjectWithChecksum( const Common::Description* Description )
                : object_base_type( Description, DATA_FORMAT_VERSION )
            {
            }

            /**
             * \brief Constructor
             */
            ObjectWithChecksum( class_type                 Class,
                                const Common::Description* Description )
                : object_base_type( Class, Description, DATA_FORMAT_VERSION )
            {
            }

            /**
             * \brief copy constructor
             */
            ObjectWithChecksum( const ObjectWithChecksum& Source )
                : object_base_type( Source )
            {
            }

            /**
             * \brief Constructor - Stream
             */
            ObjectWithChecksum( Common::IStream& Source )
                : object_base_type( Source )
            {
            }

            /**
             * \brief Destructor
             */
            ~ObjectWithChecksum( )
            {
            }

        protected:
            //-----------------------------------------------------------------
            /// \brief Demotes object to previous version of the frame spec
            ///
            /// \param[in] Target
            ///     The version of the frame specification to demote too.
            /// \param[in] Obj
            ///     The version of the object to demote.
            /// \param[in] Stream
            ///     The input stream from which the original object was
            ///     read.
            ///
            /// \return
            ///     Obj since in the univeral model, all versions of the
            ///     frame specification are represented by a single object
            //-----------------------------------------------------------------
            virtual typename ObjectType::demote_ret_type
            demote( INT_2U              Target,
                    demote_arg_type     Obj,
                    demote_stream_type* Stream ) const
            {
                return ( Obj );
            }

            //-----------------------------------------------------------------
            /// \brief Promotes object to another version of the frame spec
            ///
            /// \param[in] Target
            ///     The version of the promoted frame specification.
            /// \param[in] Obj
            ///     The object to be promoted.
            /// \param[in] Stream
            ///     The input stream from which the original object was
            ///     read.
            ///
            /// \return
            ///     Obj since in the univeral model, all versions of the
            ///     frame specification are represented by a single object
            //-----------------------------------------------------------------
            virtual typename ObjectType::promote_ret_type
            promote( INT_2U               Target,
                     promote_arg_type     Obj,
                     promote_stream_type* Stream ) const
            {
                return ( Obj );
            }
        };

#if 0
        bool init_frame_spec( );
#endif /* 0 */

#ifndef SWIGIMPORTED
        extern const Common::DetectorNames& DetectorNameTable;
#endif /* SWIGIMPORTED */

    } // namespace Universal
} /* namespace FrameCPP */
#endif /* defined(__cplusplus) && !defined(SWIG) */
#endif /* FrameCPP__UNIVERSAL__Specs_HH */
