//
// 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 <algorithm>
#include <fstream>
#include <iomanip>
#include <memory>
#include <stdexcept>

#include "framecpp/Version6/Dictionary.hh"
#include "framecpp/Version6/FrCommon.hh"
#include "framecpp/Version6/FrTOC.hh"
#include "framecpp/Version6/IFrameStream.hh"
#include "framecpp/Version6/Util.hh"

using namespace FrameCPP::Version_6;

char* Program;

namespace
{
    template < class T >
    void
    dump( const T& Data )
    {
        std::cout << Data << " ";
    }

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

    template < class T >
    void
    dump_vector( const std::vector< T >& Data, const std::string& Desc )
    {
        std::cout << "  " << Desc << ":" << std::endl << "    ";
        for ( typename std::vector< T >::const_iterator cur = Data.begin( ),
                                                        last = Data.end( );
              cur != last;
              ++cur )
        {
            dump< T >( *cur );
        }
        std::cout << std::endl;
    }

    void
    DumpTOC( const FrTOC* TOC )
    {
        //-----------------------------------------------------------------
        // Check for TOC
        //-----------------------------------------------------------------
        if ( TOC == (const FrTOC*)NULL )
        {
            std::cout << "No TOC available" << std::endl;
            return;
        }
        //-----------------------------------------------------------------
        // Dump it out to the screen
        //-----------------------------------------------------------------
        std::cout << "  ULeapS: " << TOC->GetULeapS( ) << std::endl
                  << "  nFrame: " << TOC->GetNFrame( ) << std::endl;
        dump_vector( TOC->GetDataQuality( ), "dataQuality" );
        dump_vector( TOC->GetGTimeS( ), "GTimeS" );
        dump_vector( TOC->GetGTimeN( ), "GTimeN" );
        dump_vector( TOC->GetDt( ), "dt" );
        dump_vector( TOC->GetRuns( ), "runs" );
        dump_vector( TOC->GetFrame( ), "frame" );
        dump_vector( TOC->GetPositionH( ), "positionH" );
        dump_vector( TOC->GetNFirstADC( ), "nFirstADC" );
        dump_vector( TOC->GetNFirstSer( ), "nFirstSer" );
        dump_vector( TOC->GetNFirstTable( ), "nFirstTable" );
        dump_vector( TOC->GetNFirstMsg( ), "nFirstMsg" );
        //-----------------------------------------------------------------
        std::cout << "  nSH: " << TOC->GetNSH( ) << std::endl;
        dump_vector( TOC->GetSHid( ), "SHid" );
        dump_vector( TOC->GetSHname( ), "SHname" );
        //-----------------------------------------------------------------
        std::cout << "  nDetector: " << TOC->GetNDetector( ) << std::endl;
        //-----------------------------------------------------------------
        std::cout << "  nStatType: " << TOC->GetNStatType( ) << std::endl;
        //-----------------------------------------------------------------
        std::cout << "  nADC: " << TOC->GetNADC( ) << std::endl;
        //-----------------------------------------------------------------
        std::cout << "  nProc: " << TOC->GetNProc( ) << std::endl;
        //-----------------------------------------------------------------
        std::cout << "  nSim: " << TOC->GetNSim( ) << std::endl;
        //-----------------------------------------------------------------
        std::cout << "  nSer: " << TOC->GetNSer( ) << std::endl;
        //-----------------------------------------------------------------
        std::cout << "  nSummary: " << TOC->GetNSummary( ) << std::endl;
        //-----------------------------------------------------------------
        std::cout << "  nEventType: " << TOC->GetNEventType( ) << std::endl;
        //-----------------------------------------------------------------
        std::cout << "  nSimEventType: " << TOC->GetNSimEventType( )
                  << std::endl;
    }

} // namespace

int
main( int ArgC, char** ArgV ) try
{
    Program = ArgV[ 0 ];

    //---------------------------------------------------------------------
    // Make sure at least one file was requested
    //---------------------------------------------------------------------
    if ( ArgC < 2 )
    {
        usage( );
        exit( 1 );
    }
    //---------------------------------------------------------------------
    // Loop through list of files dumping the TOC for each file
    //---------------------------------------------------------------------
    for ( int x = 1; x < ArgC; x++ )
    {
        std::ifstream ifile( ArgV[ x ] );
        IFrameStream  frame_stream( ifile );

        DumpTOC( frame_stream.GetTOC( ) );
    }
    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 );
}
