//
// LDASTools - A library implementing the LIGO/Virgo frame
// specification
//
// Copyright (C) 2020 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__FrTOCEventData_HH
#define FrameCPP_UNIVERSAL__IMPL__FrTOCEventData_HH

#include "ldastoolsal/Logger.hh"
#include "framecpp/Universal/GPSTime.hh"

// Forward declaration to avoid circular dependencies
namespace FrameCPP {
namespace Common {
    struct FrameCPPServices;
}
}

namespace FrameCPP
{
    namespace Universal
    {
        namespace FrTOCImpl
        {
            class FrTOCEventData
            {
            public:
                struct v4
                {
                    using nTrig_type = INT_4U;
                    using nameTrig_type = std::string;
                    using GTimeSTrig_type = INT_4U;
                    using GTimeNTrig_type = INT_4U;
                    using GTimeTrig_type = GPSTime;
                    using positionTrig_type = INT_8U;
                };
                struct v5
                {
                    using nEventType_type = v4::nTrig_type;
                    using nameEvent_type = v4::nameTrig_type;
                    using nEvent_type = INT_4U;
                    using GTimeSEvent_type = v4::GTimeSTrig_type;
                    using GTimeNEvent_type = v4::GTimeNTrig_type;
                    using GTimeEvent_type = v4::GTimeTrig_type;
                    using amplitudeEvent_type = REAL_4;
                    using positionEvent_type = v4::positionTrig_type;
                };
                using v6 = v5;
                using v7 = v6;
                struct v8
                {
                    using nEventType_type = v7::nEventType_type;
                    using nameEvent_type = v7::nameEvent_type;
                    using nEvent_type = v7::nEvent_type;
                    using nTotalEvent_type = INT_4U;
                    using GTimeSEvent_type = v7::GTimeSEvent_type;
                    using GTimeNEvent_type = v7::GTimeNEvent_type;
                    using GTimeEvent_type = v7::GTimeEvent_type;
                    using amplitudeEvent_type = v7::amplitudeEvent_type;
                    using positionEvent_type = v7::positionEvent_type;

                    struct event_type
                    {
                        //---------------------------------------------------------------
                        /// \brief Start time of event.
                        //---------------------------------------------------------------
                        GTimeEvent_type GTime;
                        //---------------------------------------------------------------
                        /// \brief Amplitude of event.
                        //---------------------------------------------------------------
                        amplitudeEvent_type amplitudeEvent;
                        //---------------------------------------------------------------
                        /// \brief FrEvent offset positions.
                        ///
                        /// FrEvent offset positions, in bytes,
                        /// from the beginning of the file.
                        //---------------------------------------------------------------
                        positionEvent_type positionEvent;
                    };

                    using events_container_type = std::vector< event_type >;
                    /* typedef std::vector< event_container_type >
                     * events_container_type; */
                    using nameEvent_container_type =
                        std::map< nameEvent_type, events_container_type >;

                    static constexpr Common::FrameSpec::size_type
                                     event_type_size = //
                        sizeof( GTimeSEvent_type ) + //
                        sizeof( GTimeNEvent_type ) + //
                        sizeof( amplitudeEvent_type ) + //
                        sizeof( positionEvent_type ) //
                        ;
                };
                using v9 = v8;
                //-------------------------------------------------------
                using current_version = v9;
                //-------------------------------------------------------
                using nEventType_type = current_version::nEventType_type;
                using nameEvent_type = current_version::nameEvent_type;
                using nEvent_type = current_version::nEvent_type;
                using nTotalEvent_type = INT_4U;
                using GTimeSEvent_type = current_version::GTimeSEvent_type;
                using GTimeNEvent_type = current_version::GTimeNEvent_type;
                using GTimeEvent_type = current_version::GTimeEvent_type;
                using amplitudeEvent_type =
                    current_version::amplitudeEvent_type;
                using positionEvent_type = current_version::positionEvent_type;

                using event_type = current_version::event_type;
                using events_container_type =
                    current_version::events_container_type;
                using nameEvent_container_type =
                    current_version::nameEvent_container_type;
                //-------------------------------------------------------

                constexpr static INT_4U NO_DATA_AVAILABLE = 0xFFFFFFFF;

                virtual ~FrTOCEventData( ) = default;

                //-------------------------------------------------------
                /// \brief Return all events
                ///
                /// \return
                ///     Constant container to the indexed FrEvent elements.
                //-------------------------------------------------------
                inline const nameEvent_container_type&
                GetEvent( ) const
                {
                    return events;
                }

            protected:
                /// @brief Get the logger for FrTOCEvent debugging (static version)
                /// @return Static logger instance (thread-safe, lazy initialization)
                /// Moved to FrTOCEvent.cc to avoid ODR violations from function-local statics
                static SimpleLogger* logger();

                /// @brief Get the logger for FrTOCEvent debugging (dependency injection version)
                /// @param services Services context containing logger manager
                /// @return Logger instance from services context
                static SimpleLogger* logger(const FrameCPP::Common::FrameCPPServices& services);

                //-----------------------------------------------------------------
                /// \brief Locate the position of the event
                ///
                /// \param[in] Frame
                ///     Frame offset of the event.
                /// \param[in] Event
                ///     The name of the event.
                ///
                /// \return
                ///     The file position of the requested event.
                //-----------------------------------------------------------------
                positionEvent_type
                positionEvent( INT_4U Frame, const std::string& Event ) const;

                positionEvent_type positionEvent( const std::string& Event,
                                                  INT_4U Index ) const;

                //=======================================================
                nameEvent_container_type events;
            };

        } // namespace FrTOCImpl
    } // namespace Universal
} // namespace FrameCPP

#endif /* FrameCPP_UNIVERSAL__IMPL__FrTOCEventData_HH */
