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

#if HAVE_CONFIG_H
#include <framecpp_config.h>
#endif /* HAVE_CONFIG_H */

#include <stdio.h>
#include <stdlib.h>

#include <fstream>
#include <iomanip>
#include <memory>
#include <stdexcept>

#include "framecpp/Version6/FrCommon.hh"
#include "framecpp/Version6/FrEndOfFile.hh"
#include "framecpp/Version6/FrSE.hh"
#include "framecpp/Version6/FrSH.hh"
#include "framecpp/Version6/IFrameStream.hh"
#include "framecpp/Version6/Util.hh"

using namespace FrameCPP::Version_6;

char* Program;

namespace
{
    void
    usage( )
    {
        std::cerr << "Usage: " << Program << " frame_file [ frame_file ... ]"
                  << std::endl;
    }

    class EndOfFileCB : public FrameCPP::Version_6::Dictionary::Callback
    {
    public:
        EndOfFileCB( );

        bool IsEndOfFile( ) const;

        virtual void operator( )( FrBase& Base );

    private:
        bool m_end_of_file;
    };

    class FrSECB : public FrameCPP::Version_6::Dictionary::Callback
    {
    public:
        virtual void operator( )( FrBase& Base );
    };

    class FrSHCB : public FrameCPP::Version_6::Dictionary::Callback
    {
    public:
        virtual void operator( )( FrBase& Base );
    };
} // namespace

int
main( int ArgC, char** ArgV ) try
{
    Program = ArgV[ 0 ];
    EndOfFileCB eof_cb;
    FrSHCB      frsh_cb;
    FrSECB      frse_cb;

    if ( ArgC < 2 )
    {
        usage( );
        exit( 1 );
    }
    for ( int x = 1; x < ArgC; x++ )
    {
        std::fstream ifile( ArgV[ x ], std::ios::in );
        IFrameStream frame_stream( ifile,
                                   GetClassIO( ),
                                   CLASS_LAST_ENTRY,
                                   IFrameStream::MODE_SEQUENTIAL );
        frame_stream.AddCallback( CLASS_FR_END_OF_FILE, eof_cb );
        frame_stream.AddCallback( FrBase::CLASS_FR_SH, frsh_cb );
        frame_stream.AddCallback( FrBase::CLASS_FR_SE, frse_cb );
        printf( "Version: %d\n", (int)frame_stream.GetVersion( ) );
        while ( ( frame_stream.good( ) ) && ( eof_cb.IsEndOfFile( ) == false ) )
        {
            frame_stream.ReadObject( );
        }
    }
    exit( 0 );
}
catch ( std::exception& e )
{
    std::cerr << "ABORT: Caught exception: " << e.what( ) << std::endl;
    exit( 1 );
}
catch ( ... )
{
    std::cerr << "ABORT: Caught unknown exception: " << std::endl;
    exit( 1 );
}

namespace
{
    EndOfFileCB::EndOfFileCB( ) : m_end_of_file( false )
    {
    }

    bool
    EndOfFileCB::IsEndOfFile( ) const
    {
        return m_end_of_file;
    }

    void
    EndOfFileCB::operator( )( FrBase& Base )
    {
        m_end_of_file = true;
    }

    void
    FrSECB::operator( )( FrBase& Base )
    {
        const FrSE& se( dynamic_cast< const FrSE& >( Base ) );
        printf( "   %-20.20s %-30.30s %s\n",
                se.GetName( ).c_str( ),
                se.GetClass( ).c_str( ),
                se.GetComment( ).c_str( ) );
    }

    void
    FrSHCB::operator( )( FrBase& Base )
    {
        const FrSH& sh( dynamic_cast< const FrSH& >( Base ) );
        printf( "\n-- %-20.20s %4d %s --\n",
                sh.GetName( ).c_str( ),
                sh.GetClass( ),
                sh.GetComment( ).c_str( ) );
    }
} // namespace
