/*
 * 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_Dimension_HH
#define FrameCPP_UNIVERSAL_Dimension_HH

#if !defined( SWIGIMPORTED )
#include "framecpp/Universal/impl/DimensionClassicIO.hh"
#include "framecpp/Universal/impl/DimensionSerialIO.hh"
#endif /* !defined( SWIGIMPORTED ) */

#if defined( __cplusplus )
namespace FrameCPP
{
    namespace Universal
    {
        //===================================================================
        /// \brief Dimension information for a Vect.
        ///
        /// This class stores dimension information for a Vect object,
        /// including dimension length, scale factor, and units.
        //===================================================================
        class Dimension
#if !defined( SWIG )
            : public DimensionImpl::ClassicIO< Dimension >,
              public DimensionImpl::SerialIO< Dimension >
#endif /* ! defined(SWIG) */
        {
        public:
            // Import type definitions from DimensionImpl::Data
            typedef DimensionImpl::Data::nDim_type   nDim_type;
            typedef DimensionImpl::Data::nx_type     nx_type;
            typedef DimensionImpl::Data::dx_type     dx_type;
            typedef DimensionImpl::Data::startX_type startX_type;

            //-----------------------------------------------------------------
            /// \brief Default initialization values
            ///
            /// These constants define the default values used by the default
            /// constructor. They are exposed in the public API to allow tests
            /// and client code to verify expected default behavior.
            //-----------------------------------------------------------------
            static constexpr nx_type     DEFAULT_NX = 0;
            static constexpr dx_type     DEFAULT_DX = 1.0;
            static constexpr startX_type DEFAULT_STARTX = 0.0;

            //-----------------------------------------------------------------
            /// \brief Default constructor
            ///
            /// \return
            ///    A new instance of this object.
            //-----------------------------------------------------------------
            Dimension( );

            //-----------------------------------------------------------------
            /// \brief Copy Constructor
            ///
            /// \param[in] dim
            ///     The object from which to copy the information.
            ///
            /// \return
            ///    A new instance of this object.
            //-----------------------------------------------------------------
            Dimension( const Dimension& dim );

            //-----------------------------------------------------------------
            /// \brief Constructor
            ///
            /// \param[in] nx
            ///     The dimension length.
            /// \param[in] dx
            ///     The scale factor.
            /// \param[in] unitX
            ///     Units for the dimension.
            /// \param[in] startX
            ///     Data set origin.
            ///
            /// \return
            ///    A new instance of this object.
            //-----------------------------------------------------------------
            Dimension( nx_type nx, dx_type dx, const char* unitX, startX_type startX );

            //-----------------------------------------------------------------
            /// \brief Get the dimension length.
            ///
            /// \return
            ///     The dimension length.
            //-----------------------------------------------------------------
            nx_type GetNx( ) const;

            //-----------------------------------------------------------------
            /// \brief Get the scale factor.
            ///
            /// \return
            ///     The scale factor.
            //-----------------------------------------------------------------
            dx_type GetDx( ) const;

            //-----------------------------------------------------------------
            /// \brief Get data set origin.
            ///
            /// \return
            ///     Data set origin.
            //-----------------------------------------------------------------
            startX_type GetStartX( ) const;

            //-----------------------------------------------------------------
            /// \brief Retrieve the description of how to interpret each element
            ///
            /// \return
            ///     The description of how to interpret each element
            //-----------------------------------------------------------------
            const std::string& GetUnitX( ) const;

            //-----------------------------------------------------------------
            /// \brief Set the scale factor.
            ///
            /// \param[in] dx
            ///     The scale factor.
            //-----------------------------------------------------------------
            void SetDx( dx_type dx );

            //-----------------------------------------------------------------
            /// \brief Set the dimension length.
            ///
            /// \param[in] nx
            ///     The dimension length.
            //-----------------------------------------------------------------
            void SetNx( nx_type nx );

            //-----------------------------------------------------------------
            /// \brief Set data set origin.
            ///
            /// \param[in] startX
            ///     Data set origin.
            //-----------------------------------------------------------------
            void SetStartX( startX_type startX );

#if !defined( SWIG )
            //-----------------------------------------------------------------
            /// \brief Assignment operator.
            ///
            /// \param[in] dim
            ///     The object to assign from.
            ///
            /// \return
            ///     This object.
            //-----------------------------------------------------------------
            const Dimension& operator=( const Dimension& dim );

            //-----------------------------------------------------------------
            /// \brief Equal comparison.
            ///
            /// \param[in] dim
            ///     The object to compare with.
            ///
            /// \return
            ///     true if the objects are equal, false otherwise.
            //-----------------------------------------------------------------
            bool operator==( const Dimension& dim ) const;

            //-----------------------------------------------------------------
            /// \brief Not equal comparison.
            ///
            /// \param[in] dim
            ///     The object to compare with.
            ///
            /// \return
            ///     false if the objects are equal, true otherwise.
            //-----------------------------------------------------------------
            bool operator!=( const Dimension& dim ) const;

            // Pure virtual function implementations required by ClassicIO
            bool operator==( const Common::FrameSpec::Object& Obj ) const;

            // GetDescription method implementations
            using Common::FrameSpec::Object::GetDescription;
            virtual const Common::Description* GetDescription( unsigned int version ) const;
#endif /* ! defined(SWIG) */
        };

        // Type aliases for compatibility
        using Dimension_type = Dimension;

    } // namespace Universal

    // Export types to FrameCPP namespace for compatibility
    using Dimension = Universal::Dimension;

} // namespace FrameCPP
#endif /* defined( __cplusplus ) */

#endif /* FrameCPP_UNIVERSAL_Dimension_HH */