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

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

#include <cstdio>  // For std::remove

#include "framecpp/FrameCPP.hh"
#include "framecpp/GPSTime.hh"
#include "framecpp/IFrameStream.hh"
#include "framecpp/OFrameStream.hh"
#include "framecpp/Common/FrameBuffer.hh"
#include "ldastoolsal/fstream.hh"

using namespace FrameCPP;
using FrameCPP::GPSTime;

//-----------------------------------------------------------------------
// Test CMake-configured constants
//-----------------------------------------------------------------------
BOOST_AUTO_TEST_CASE( test_cmake_configuration )
{
    // Verify CMake configured values correctly
    BOOST_CHECK_EQUAL(FRAME_SPEC_MIN, 3);
    BOOST_CHECK_EQUAL(FRAME_SPEC_MAX, 9);
    BOOST_CHECK_EQUAL(FRAME_SPEC_DEFAULT, 8);

    // Verify backward compatibility alias
    BOOST_CHECK_EQUAL(FRAME_SPEC_CURRENT, FRAME_SPEC_MAX);

    // Verify runtime constants match
    BOOST_CHECK_EQUAL(FrameCPP::FrameSpecMinimum, 3);
    BOOST_CHECK_EQUAL(FrameCPP::FrameSpecMaximum, 9);
    BOOST_CHECK_EQUAL(FrameCPP::FrameSpecDefault, 8);
    BOOST_CHECK_EQUAL(FrameCPP::FrameSpecCurrent, 9);
}

//-----------------------------------------------------------------------
// Test OFrameFStream default constructor uses FRAME_SPEC_DEFAULT
//-----------------------------------------------------------------------
BOOST_AUTO_TEST_CASE( test_oframefstream_default_version )
{
    const std::string filename = "test_default_version_fstream.gwf";

    // Write frame using default constructor (no version parameter)
    {
        FrameCPP::OFrameFStream ofs(filename.c_str());
        auto frame = boost::make_shared<FrameCPP::FrameH>(
            "Test", 0, 0, GPSTime(1234567890, 0), 1.0);
        ofs.WriteFrame(frame);
    }

    // Read back and verify version is FRAME_SPEC_DEFAULT (8)
    {
        FrameCPP::IFrameFStream ifs(filename.c_str());
        BOOST_CHECK_EQUAL(ifs.Version(), FRAME_SPEC_DEFAULT);
        BOOST_CHECK_EQUAL(ifs.Version(), 8);
    }

    std::remove(filename.c_str());
}

//-----------------------------------------------------------------------
// Test OFrameStream default constructor uses FRAME_SPEC_DEFAULT
//-----------------------------------------------------------------------
BOOST_AUTO_TEST_CASE( test_oframestream_default_version )
{
    const std::string filename = "test_default_version_stream.gwf";

    // Write using OFrameStream with default parameter
    {
        FrameCPP::Common::FrameBuffer<LDASTools::AL::filebuf> buf(std::ios::out);
        buf.open(filename.c_str(), std::ios::out | std::ios::binary);

        FrameCPP::OFrameStream ofs(false, &buf);  // AutoDelete=false, Uses FRAME_SPEC_DEFAULT

        auto frame = boost::make_shared<FrameCPP::FrameH>(
            "Test", 0, 0, GPSTime(1234567890, 0), 1.0);
        ofs.WriteFrame(frame);
        ofs.Close();
    }

    // Verify written version
    {
        FrameCPP::IFrameFStream ifs(filename.c_str());
        BOOST_CHECK_EQUAL(ifs.Version(), FRAME_SPEC_DEFAULT);
        BOOST_CHECK_EQUAL(ifs.Version(), 8);
    }

    std::remove(filename.c_str());
}

//-----------------------------------------------------------------------
// Test explicit version parameter overrides default
//-----------------------------------------------------------------------
BOOST_AUTO_TEST_CASE( test_explicit_version_override )
{
    const std::string filename = "test_explicit_version.gwf";

    // Write frame with explicit version 9
    {
        FrameCPP::OFrameFStream ofs(filename.c_str(), 9);
        auto frame = boost::make_shared<FrameCPP::FrameH>(
            "Test", 0, 0, GPSTime(1234567890, 0), 1.0);
        ofs.WriteFrame(frame);
    }

    // Read back and verify version is 9 (not default 8)
    {
        FrameCPP::IFrameFStream ifs(filename.c_str());
        BOOST_CHECK_EQUAL(ifs.Version(), 9);
        BOOST_CHECK_NE(ifs.Version(), FRAME_SPEC_DEFAULT);
    }

    std::remove(filename.c_str());
}

//-----------------------------------------------------------------------
// Test that FRAME_SPEC_CURRENT != FRAME_SPEC_DEFAULT (separation)
//-----------------------------------------------------------------------
BOOST_AUTO_TEST_CASE( test_current_vs_default_separation )
{
    // Verify we maintain separation between capability and policy
    BOOST_CHECK_NE(FRAME_SPEC_CURRENT, FRAME_SPEC_DEFAULT);
    BOOST_CHECK_EQUAL(FRAME_SPEC_CURRENT, 9);  // Maximum capability
    BOOST_CHECK_EQUAL(FRAME_SPEC_DEFAULT, 8);  // Default output

    // FRAME_SPEC_CURRENT should equal FRAME_SPEC_MAX
    BOOST_CHECK_EQUAL(FRAME_SPEC_CURRENT, FRAME_SPEC_MAX);
}
