// -*- mode: c++ -*-
//
// 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
//

#include <framecpp_config.h>

#include "framecpp/Universal/FrameH.hh"
#include "framecpp/Universal/FrEndOfFile.hh"

namespace
{
    namespace Version7
    {
        using FrameCPP::Universal::FrameH;

        using FrameCPP::Universal::FrEvent;
        using FrameCPP::Universal::FrSimEvent;

        class DumpFrStruct : public ::DumpFrStruct
        {
        public:
            DumpFrStruct( bool VerboseDataMode, bool ScientificDataMode );

            DumpFrStruct( const ::DumpFrStruct& Source );

            virtual void Dump( const Object& Base );
        };

        DumpFrStruct::DumpFrStruct( bool VerboseDataMode,
                                    bool ScientificDataMode )
            : ::DumpFrStruct( VerboseDataMode,
                              ScientificDataMode,
                              ::DumpFrStruct::OUTPUT_MODE_DUMP )
        {
        }

        void
        DumpFrStruct::Dump( const Object& Base )
        {
            switch ( Base.GetClass( ) )
            {
            case FrameCPP::Common::FrameSpec::Info::FSI_FR_ADC_DATA:
            case FrameCPP::Common::FrameSpec::Info::FSI_FR_DETECTOR:
            case FrameCPP::Common::FrameSpec::Info::FSI_FR_END_OF_FILE:
            case FrameCPP::Common::FrameSpec::Info::FSI_FR_END_OF_FRAME:
            case FrameCPP::Common::FrameSpec::Info::FSI_FR_HISTORY:
            case FrameCPP::Common::FrameSpec::Info::FSI_FR_MSG:
            case FrameCPP::Common::FrameSpec::Info::FSI_FR_PROC_DATA:
            case FrameCPP::Common::FrameSpec::Info::FSI_FR_STAT_DATA:
            case FrameCPP::Common::FrameSpec::Info::FSI_FR_SUMMARY:
            case FrameCPP::Common::FrameSpec::Info::FSI_FR_TABLE:
            case FrameCPP::Common::FrameSpec::Info::FSI_FR_VECT:
            {
                //---------------------------------------------------------------------
                // Structures that were not changed
                //---------------------------------------------------------------------
                Version6::DumpFrStruct dumper( *this );

                dumper.Dump( Base );
            }
            break;
            case FrameCPP::Common::FrameSpec::Info::FSI_FRAME_H:
            {
                const FrameH& o( dynamic_cast< const FrameH& >( Base ) );
                dump_label    l( std::cout, m_pad, 12, m_scientific_data_mode );

                header( "FrameH" );

                l( "name", o.GetName( ) );
                l( "run", o.GetRun( ) );
                l( "frame", o.GetFrame( ) );
                l( "dataQuality", o.GetDataQuality( ) );
                l( "GTimeS", o.GetGTime( ).GetSeconds( ) );
                l( "GTimeN", o.GetGTime( ).GetNanoseconds( ) );
                l( "dt", o.GetDt( ) );

                switch ( m_output_mode )
                {
                case OUTPUT_MODE_DUMP:
                    dump_container( "type", o.RefType( ) );
                    dump_container( "user", o.RefUser( ) );
                    dump_container( "detectSim", o.RefDetectSim( ) );
                    dump_container( "detectProc", o.RefDetectProc( ) );
                    dump_container( "history", o.RefHistory( ) );
                    if ( o.GetRawData( ) )
                    {
                        Dump( *( o.GetRawData( ) ) );
                    }
                    else
                    {
                        std::cout << m_pad << "FrRawData - NULL" << std::endl;
                    }
                    dump_container( "procData", o.RefProcData( ) );
                    dump_container( "simData", o.RefSimData( ) );
                    dump_container( "event", o.RefEvent( ) );
                    dump_container( "simEvent", o.RefSimEvent( ) );
                    dump_container( "summaryData", o.RefSummaryData( ) );
                    dump_container( "auxData", o.RefAuxData( ) );
                    dump_container( "auxTable", o.RefAuxTable( ) );
                    break;
                case OUTPUT_MODE_DUMP_OBJECTS:
                    break;
                }

                trailer( );
            }
            break;
            case FrameCPP::Common::FrameSpec::Info::FSI_FR_EVENT:
            {
                const FrEvent& o( dynamic_cast< const FrEvent& >( Base ) );
                std::vector< REAL_8 >      parameters;
                std::vector< std::string > parameterNames;

                header( "FrEvent" );

                dump_label l( std::cout, m_pad, 10, m_scientific_data_mode );
                l( "name", o.GetName( ) );
                l( "comment", o.GetComment( ) );
                l( "inputs", o.GetInputs( ) );
                l( "GTimeS", o.GetGTime( ).GetSeconds( ) );
                l( "GTimeN", o.GetGTime( ).GetNanoseconds( ) );
                l( "timeBefore", o.GetTimeBefore( ) );
                l( "timeAfter", o.GetTimeAfter( ) );
                l( "eventStatus", o.GetEventStatus( ) );
                l( "amplitude", o.GetAmplitude( ) );
                l( "probability", o.GetProbability( ) );
                l( "statistics", o.GetStatistics( ) );
                l( "nParam", o.GetParam( ).size( ) );
                for ( FrEvent::ParamList_type::const_iterator
                          cur = o.GetParam( ).begin( ),
                          end = o.GetParam( ).end( );
                      cur != end;
                      ++cur )
                {
                    parameterNames.push_back( ( *cur ).first );
                    parameters.push_back( ( *cur ).second );
                }
                l( "parameters", parameters );
                l( "parameterNames", parameterNames );

                switch ( m_output_mode )
                {
                case OUTPUT_MODE_DUMP:
                    dump_container( "data", o.RefData( ) );
                    dump_container( "table", o.RefTable( ) );
                    break;
                case OUTPUT_MODE_DUMP_OBJECTS:
                    break;
                }

                trailer( );
            }
            break;
            case FrameCPP::Common::FrameSpec::Info::FSI_FR_RAW_DATA:
            {
                using FrameCPP::Universal::FrRawData;

                const FrRawData& o( dynamic_cast< const FrRawData& >( Base ) );

                header( "FrRawData" );

                dump_label l( std::cout, m_pad, 10, m_scientific_data_mode );
                l( "name", o.GetName( ) );

                switch ( m_output_mode )
                {
                case OUTPUT_MODE_DUMP:
                    dump_container( "firstSer", o.RefFirstSer( ) );
                    dump_container( "firstAdc", o.RefFirstAdc( ) );
                    dump_container( "firsTable", o.RefFirstTable( ) );
                    dump_container( "logMsg", o.RefLogMsg( ) );
                    dump_container( "more", o.RefMore( ) );
                case OUTPUT_MODE_DUMP_OBJECTS:
                    break;
                }

                trailer( );
            }
            break;
            case FrameCPP::Common::FrameSpec::Info::FSI_FR_SER_DATA:
            {
                using FrameCPP::Universal::FrSerData;

                const FrSerData& o( dynamic_cast< const FrSerData& >( Base ) );

                header( "FrSerData" );

                dump_label l( std::cout, m_pad, 10, m_scientific_data_mode );
                l( "name", o.GetName( ) );
                l( "timeSec", o.GetTime( ).GetSeconds( ) );
                l( "timeNsec", o.GetTime( ).GetNanoseconds( ) );
                l( "sampleRate", o.GetSampleRate( ) );
                l( "data", o.GetData( ) );

                switch ( m_output_mode )
                {
                case OUTPUT_MODE_DUMP:
                    dump_container( "serial", o.RefSerial( ) );
                    dump_container( "table", o.RefTable( ) );
                case OUTPUT_MODE_DUMP_OBJECTS:
                    break;
                }

                trailer( );
            }
            break;
            case FrameCPP::Common::FrameSpec::Info::FSI_FR_SIM_DATA:
            {
                using FrameCPP::Universal::FrSimData;

                const FrSimData& o( dynamic_cast< const FrSimData& >( Base ) );

                header( "FrSimData" );

                dump_label l( std::cout, m_pad, 10, m_scientific_data_mode );
                l( "name", o.GetName( ) );
                l( "comment", o.GetComment( ) );
                l( "sampleRate", o.GetSampleRate( ) );
                l( "timeOffset", o.GetTimeOffset( ) );
                l( "fShift", o.GetFShift( ) );
                l( "phase", o.GetPhase( ) );

                switch ( m_output_mode )
                {
                case OUTPUT_MODE_DUMP:
                    dump_container( "data", o.RefData( ) );
                    dump_container( "input", o.RefInput( ) );
                    dump_container( "table", o.RefTable( ) );
                case OUTPUT_MODE_DUMP_OBJECTS:
                    break;
                }

                trailer( );
            }
            break;
            case FrameCPP::Common::FrameSpec::Info::FSI_FR_SIM_EVENT:
            {
                const FrSimEvent& o(
                    dynamic_cast< const FrSimEvent& >( Base ) );
                std::vector< REAL_8 >      parameters;
                std::vector< std::string > parameterNames;

                header( "FrSimEvent" );

                dump_label l( std::cout, m_pad, 10, m_scientific_data_mode );
                l( "name", o.GetName( ) );
                l( "comment", o.GetComment( ) );
                l( "inputs", o.GetInputs( ) );
                l( "GTimeS", o.GetGTime( ).GetSeconds( ) );
                l( "GTimeN", o.GetGTime( ).GetNanoseconds( ) );
                l( "timeBefore", o.GetTimeBefore( ) );
                l( "timeAfter", o.GetTimeAfter( ) );
                l( "amplitude", o.GetAmplitude( ) );
                l( "nParam", o.GetParam( ).size( ) );
                for ( FrSimEvent::ParamList_type::const_iterator
                          cur = o.GetParam( ).begin( ),
                          end = o.GetParam( ).end( );
                      cur != end;
                      ++cur )
                {
                    parameterNames.push_back( ( *cur ).first );
                    parameters.push_back( ( *cur ).second );
                }
                l( "parameters", parameters );
                l( "parameterNames", parameterNames );

                switch ( m_output_mode )
                {
                case OUTPUT_MODE_DUMP:
                    dump_container( "data", o.RefData( ) );
                    dump_container( "table", o.RefTable( ) );
                    break;
                case OUTPUT_MODE_DUMP_OBJECTS:
                    break;
                }

                trailer( );
            }
            break;
            default:
            {
                std::ostringstream msg;

                msg << "Unable to dump structure of type: " << Base.GetClass( );
                throw std::invalid_argument( msg.str( ) );
            }
            break;
            }
        }
    } // namespace Version7
} // namespace

template <>
void
dump< 7 >( Object* Obj, const CommandLine& Options )
{
    if ( Obj )
    {
        ::Version7::DumpFrStruct dumper( ( Options.SilentData( ) == false ),
                                         Options.ScientificNotation( ) );

        dumper.Dump( *Obj );
    }
}

template <>
void
dump_toc_list< 7 >( const Object* TOC, object_type Type )
{
    //---------------------------------------------------------------------
    // The table of contents remained the same between version 6 and 7.
    // Reuse the version 6 code.
    //---------------------------------------------------------------------
    dump_toc_list< 6 >( TOC, Type );
}
