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

#include <algorithm>
#include <exception>
#include <fstream>
#include <sstream>
#include <typeinfo>

#include <boost/config.hpp>
#include <boost/core/demangle.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>

#include "gtest/gtest.h"

#include "framecpp/Common/Description.hh"

template < typename FR_TYPE >
class test_source
{
public:
    typedef FR_TYPE data_type;

    test_source( const data_type& Source ) : source( Source )
    {
    }

    const data_type&
    Source( ) const
    {
        return ( source );
    }

private:
    const data_type& source;
};

template < typename INPUT_ARCHIVE_T, typename OUTPUT_ARCHIVE_T, typename T >
int
test_read_write( const T& Source )
{
    try
    {
        int               status = 0;
        std::stringstream buffer;
        std::string       tag{ boost::core::demangle(
            typeid( typename T::data_type ).name( ) ) };
        std::replace( tag.begin( ), tag.end( ), ':', '_' );

        const typename T::data_type& output_obj{ Source.Source( ) };

        EXPECT_NO_THROW( {
            // ------------------------------------------------------------------
            //  Writing output
            // ------------------------------------------------------------------
            OUTPUT_ARCHIVE_T output{ buffer };

            output << boost::serialization::make_nvp( tag.c_str( ),
                                                      output_obj );
        } );

        EXPECT_NO_THROW( {
            // ------------------------------------------------------------------
            //  Reading input
            // ------------------------------------------------------------------

            INPUT_ARCHIVE_T input( buffer );

            typename T::data_type input_obj;

            input >> boost::serialization::make_nvp( tag.c_str( ), input_obj );

            status = ( ( input_obj == output_obj ) ? 1 : 0 );
        } );
        return ( ( status ) ? 1 : 0 );
    }
    catch ( ... )
    {
        return ( 0 );
    }
}

template < typename SOURCE_TYPE >
int
test_using_text_archiver( const SOURCE_TYPE& Source )
{
    return ( test_read_write< boost::archive::text_iarchive,
                              boost::archive::text_oarchive,
                              SOURCE_TYPE >( Source ) );
}

template < typename SOURCE_TYPE >
int
test_using_xml_archiver( const SOURCE_TYPE& Source )
{
    return ( test_read_write< boost::archive::xml_iarchive,
                              boost::archive::xml_oarchive,
                              SOURCE_TYPE >( Source ) );
}

#include "FrSE_test.cc"
#include "FrSH_test.cc"

#include "FrDetector_test.cc"
#include "FrEndOfFile_test.cc"
#include "FrEndOfFrame_test.cc"
#include "FrEvent_test.cc"
#include "FrHistory_test.cc"
#include "FrMsg_test.cc"
#include "FrVect_test.cc"
#include "FrTable_test.cc"
#include "FrProcData_serialization_test.cc"
#include "FrAdcData_test.cc"
#include "FrRawData_test.cc"
#include "FrSerData_test.cc"
#include "FrSimData_test.cc"
#include "FrSimEvent_test.cc"
#include "FrSummary_test.cc"
#include "FrameH_test.cc"
#include "FrTOC_test.cc"

int
main( int argc, char** argv )
try
{
    testing::InitGoogleTest( &argc, argv );
    return RUN_ALL_TESTS( );
}
catch ( ... )
{
}
