//
// 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 <sstream>
#include <string>

#define BOOST_TEST_MAIN
#include <boost/test/included/unit_test.hpp>

#include "framecpp/Common/FrameFilename.hh"

using FrameCPP::Common::FrameFilename;

void
test( const std::string& Filename )
{
    try
    {
        FrameFilename ff( Filename );

        BOOST_TEST_MESSAGE( Filename << ": S does not contain any hypens" );
        BOOST_CHECK( ff.S( ).find( '-' ) == std::string::npos );
        BOOST_TEST_MESSAGE( Filename << ": D does not contain any hypens" );
        BOOST_CHECK( ff.D( ).find( '-' ) == std::string::npos );
        BOOST_TEST_MESSAGE( Filename << ": GPS start time > 0" );
        BOOST_CHECK( ff.G( ) > 0 );
        BOOST_TEST_MESSAGE( Filename << ": Total Time > 0" );
        BOOST_CHECK( ff.T( ) > 0 );
    }
    catch ( const FrameFilename::InvalidFrameFilename& e )
    {
        for ( size_t x = 0, end = e.getSize( ); x < end; ++x )
        {
            BOOST_TEST_MESSAGE( Filename << e[ x ].getMessage( ) );
        }
        BOOST_CHECK( false );
    }
}

void
valid( const std::string& Frame ) try
{
    // This test simply checks that the class can be constructed.
    FrameFilename ffn( Frame );
    ffn.D( );
    BOOST_TEST_MESSAGE( "Created class for valid framefile name: " << Frame );
    BOOST_CHECK( true );
}
catch ( ... )
{
    BOOST_TEST_MESSAGE( "Caught exception when validating framefile name: " );
    BOOST_CHECK( false );
}

void
valid( const std::string&                            Dir,
       const std::string&                            S,
       const std::string&                            D,
       const FrameFilename::gps_seconds_type         G,
       const FrameFilename::total_time_interval_type T,
       const std::string&                            Ext ) try
{
    // This test simply checks that the class can be constructed.
    std::ostringstream filename;
    if ( Dir.length( ) > 0 )
    {
        filename << Dir << "/";
    }
    filename << S << "-" << D << "-" << G << "-" << T << "." << Ext;

    FrameFilename ffn( filename.str( ) );
    BOOST_TEST_MESSAGE( "Validating directory: " << filename.str( ) );
    BOOST_CHECK(
        ( ( Dir.length( ) > 0 ) && ( Dir.compare( ffn.Dir( ) ) == 0 ) ) ||
        ( ( Dir.length( ) == 0 ) && ( ffn.Dir( ).compare( "." ) == 0 ) ) );
    BOOST_TEST_MESSAGE( "Validating S component: " << filename.str( ) );
    BOOST_CHECK( S.compare( ffn.S( ) ) == 0 );
    BOOST_TEST_MESSAGE( "Validating D component: " << filename.str( ) );
    BOOST_CHECK( D.compare( ffn.D( ) ) == 0 );
    BOOST_TEST_MESSAGE( "Validating G component: " << filename.str( ) );
    BOOST_CHECK( ffn.G( ) == G );
    BOOST_TEST_MESSAGE( "Validating T component: " << filename.str( ) );
    BOOST_CHECK( ffn.T( ) == T );
    BOOST_TEST_MESSAGE(
        "Validating file extension component: " << filename.str( ) );
    BOOST_CHECK( Ext.compare( ffn.Ext( ) ) == 0 );
}
catch ( ... )
{
    std::ostringstream filename;
    if ( Dir.length( ) > 0 )
    {
        filename << Dir << "/";
    }
    filename << S << "-" << D << "-" << G << "-" << T << "." << Ext;

    BOOST_TEST_MESSAGE(
        "Caught exception when validating framefile name pieces: "
        << filename.str( ) );
    BOOST_CHECK( false );
}

void
invalid( const std::string& Frame ) try
{
    // These are expected to throw an exception
    FrameFilename ffn( Frame );
    ffn.D( );
    BOOST_TEST_MESSAGE(
        "To throw an exception for the invalid framefile name: " << Frame );
    BOOST_CHECK( false );
}
catch ( const FrameFilename::InvalidFrameFilename& e )
{
    BOOST_TEST_MESSAGE(
        "Caught proper exception for invalid framefile name: " << Frame );
    BOOST_CHECK( true );
}
catch ( ... )
{
    BOOST_TEST_MESSAGE(
        "Threw wrong exception for the invalid framefile name: " << Frame );
    BOOST_CHECK( false );
}

BOOST_AUTO_TEST_CASE( Filenames )
{
    //---------------------------------------------------------------------
    // Testing of class 1
    //---------------------------------------------------------------------
    // 1 second of raw GEO data
    test( "G-R-650123123-1.gwf" );
    // 8 seconds of raw LIGO data from Hanford
    test( "H-R-688775627-8.gwf" );
    // One minute of second-trend data from Livingston
    test( "L-T-688775600-60.gwf" );
    // One hour of minute-trend data fro mboth Hanford and Livingston
    test( "HL-M-68877500-3600.gwf" );
    //---------------------------------------------------------------------
    // Testing of class 2
    //---------------------------------------------------------------------
    // 256 seconds of "Level 2" data (e.g. selected channesl, possibly
    //   with some offline processing) from Hanford
    test( "H-level2-693020060-256.gwf" );
    // 1000 seocnds of PEM data from Livingston
    test( "L-PEM-720878444-1000.gwf" );
    // Some simultated data containing inspiral signals
    test( "HL-SimInspiral-730282200-16.gwf" );
    //---------------------------------------------------------------------
    // Testing of class 3
    //---------------------------------------------------------------------
    test( "pss-filter_test-787384722-8.gwf" );
    test( "iul-simset1-694215520-32.gwf" );
    test( "H-calibPEM-720878444-1000.gwf" );

    //---------------------------------------------------------------------
    // Valid frame filename tests
    //---------------------------------------------------------------------
    // Class 1
    valid( "G-R-650123123-1.gwf" );
    valid( "H-R-688775627-8.gwf" );
    valid( "L-T-688775600-60.gwf" );
    valid( "HL-M-688775000-3600.gwf" );

    // Class 2
    valid( "H-level2-693020060-256.gwf" );
    valid( "L-PEM-720878444-1000.gwf" );
    valid( "HL-SimInspiral-730282200-16.gwf" );

    // Class 3
    valid( "pss-filter_test-787384722-8.gwf" );
    valid( "iul-simset1-694215520-32.gwf" );
    valid( "H-calibPEM-720878444-1000.gwf" );

    // Other valid frame files
    valid( "/ldas_outgoing/test/frames/S2/LHO/full/H-R-7307020/"
           "H-R-730702080-16.gwf" );

    //---------------------------------------------------------------------
    // Validate the parsing of the components
    //---------------------------------------------------------------------
    valid( "", "G", "R", 650123123, 1, "gwf" );
    valid( "/ldas_outgoing/test/frames/S2/LHO/full/H-R-7307020",
           "H",
           "R",
           730702080,
           16,
           "gwf" );

    //---------------------------------------------------------------------
    // Invalid frame filename tests
    //---------------------------------------------------------------------
    invalid( "H-calibPEM-720878444-extra-1000.gwf" );
    invalid( "H-720878444-1000.gwf" );
}
