//
// 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__FrTOCAdcDataData_HH
#define FrameCPP_UNIVERSAL__IMPL__FrTOCAdcDataData_HH

#include "ldastoolsal/Logger.hh"

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

#if defined( __cplusplus )
#if !defined( SWIG )

namespace FrameCPP
{
    namespace Universal
    {
        namespace FrTOCImpl
        {
            class FrTOCAdcDataData
            {
            public:
                struct v4
                {
                    using nadc_type = INT_4U;
                    using name_type = std::string;
                    using channel_id_type = INT_4U;
                    using group_id_type = INT_4U;
                    using position_type = INT_8U;
                };
                using v5 = v4;
                using v6 = v5;
                using v7 = v6;
                using v8 = v7;
                using v9 = v8;

                using current_version = v9;

                using nadc_type = current_version::nadc_type;
                using name_type = current_version::name_type;
                using channel_id_type = current_version::channel_id_type;
                using group_id_type = current_version::group_id_type;
                using position_type = current_version::position_type;

                struct adc_info_type
                {
                    //---------------------------------------------------
                    std::vector< position_type > m_positionADC;
                    //---------------------------------------------------
                    /// \brief Adc channel index number, sequential as read from
                    /// the TOC
                    //---------------------------------------------------
                    INT_4U m_index;
                    //---------------------------------------------------
                    /// \brief Channel ID array (v4-v8 only, not in v9+)
                    //---------------------------------------------------
                    std::vector< channel_id_type > m_channelID;
                    //---------------------------------------------------
                    /// \brief Group ID array (v4-v8 only, not in v9+)
                    //---------------------------------------------------
                    std::vector< group_id_type > m_groupID;

                    //---------------------------------------------------
                    //---------------------------------------------------
                    inline adc_info_type( )
                        : m_index( 0 )
                    {
                    }

                    //---------------------------------------------------
                    //---------------------------------------------------
                    inline adc_info_type(
                        const std::vector< position_type > Positions,
                        INT_4U                             Index )
                        : m_positionADC( Positions ), m_index( Index )
                    {
                    }

                    //---------------------------------------------------
                    //---------------------------------------------------
                    adc_info_type(
                        const std::vector< position_type >::const_iterator
                            BeginPos,
                        const std::vector< position_type >::const_iterator
                               EndPos,
                        INT_4U Index )
                        : m_positionADC( BeginPos, EndPos ), m_index( Index )
                    {
                    }
                };

                using key_container_type = std::vector< name_type >;

                //-----------------------------------------------------------------
                /// \brief Container of indexed FrAdcData elements.
                ///
                /// This structure is ordered by the name of the FrAdcData
                /// channel name.
                /// There is one element for each channel of indexed data.
                //-----------------------------------------------------------------
                using MapADC_type = std::map< name_type, adc_info_type >;

                inline const MapADC_type&
                GetADC( ) const
                {
                    if (logger()) {
                        logger_log_debug(logger(), 15, "FrTOCAdcDataData::GetADC() called, m_info.size()=", m_info.size(),
                                       " this=", static_cast<const void*>(this));
                    }
                    return m_info;
                }

                MapADC_type::const_iterator GetADC( int ChannelIndex ) const;

                MapADC_type::const_iterator
                GetADC( const name_type& ChannelName ) const;

                const FrTOCAdcDataData&
                operator=( const FrTOCAdcDataData& Source )
                {
                    m_keys = Source.m_keys;
                    m_info = Source.m_info;
                    return ( *this );
                }

                inline const key_container_type&
                GetADCKeysByName( ) const
                {
                    return ( m_keys );
                }

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

                /// @brief Get the logger for FrTOCAdcData 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);

                key_container_type m_keys;
                MapADC_type        m_info;

                inline MapADC_type&
                getADC( )
                {
                    return m_info;
                }

                inline MapADC_type::iterator
                getADC( const std::string& Channel )
                {
                    return m_info.find( Channel );
                }

                inline MapADC_type::iterator
                getADC( INT_4U Channel )
                {
                    MapADC_type& i( getADC( ) );

                    if ( Channel >= i.size( ) )
                    {
                        return i.end( );
                    }
                    return i.find( m_keys[ Channel ] );
                }
            };
        } // namespace FrTOCImpl
    } // namespace Universal
} // namespace FrameCPP
#endif /* !defined( SWIG ) */
#endif /* defined( __cplusplus ) */

#endif /* FrameCPP_UNIVERSAL__IMPL__FrTOCAdcDataData_HH */
