// Copyright (c) 2020 Metrolab Technology S.A., Geneva, Switzerland (www.metrolab.com)
// See the included file LICENSE.txt for the licensing conditions.

//////////////////////////////////////////////////////////////////////////
/// \file
/// \brief Test IEEE488 Instrument: Read and Write methods.

#pragma once

#include <gtest/gtest.h>
#include <regex>

#include "IEEE488InstrumentTest.h"

using namespace testing;

class IEEE488InstrumentMiscUtilitiesTest : public ::testing::Test
{
protected:
    static IEEE4888_TEST_RESOURCE_MANAGER_CLASS *	pResourceManager;
    static IEEE4888_TEST_INSTRUMENT_CLASS *         pInstrument;

    static void SetUpTestCase()
    {
        ASSERT_EQ(true, ConnectToIEEE488Instrument(pResourceManager, pInstrument));
        ASSERT_NE(nullptr, pResourceManager);
        ASSERT_NE(nullptr, pInstrument);
        ASSERT_EQ(true, pInstrument->IsOpen());
        ASSERT_EQ(true, pInstrument->Clear());
    }

    static void TearDownTestCase()
    {
        delete pInstrument;
        pInstrument = nullptr;
        delete pResourceManager;
        pResourceManager = nullptr;
    }
};

IEEE4888_TEST_RESOURCE_MANAGER_CLASS *  IEEE488InstrumentMiscUtilitiesTest::pResourceManager    = nullptr;
IEEE4888_TEST_INSTRUMENT_CLASS *        IEEE488InstrumentMiscUtilitiesTest::pInstrument         = nullptr;

/// \brief Test Clear and ReadSTB.
TEST_F(IEEE488InstrumentMiscUtilitiesTest, Clear)
{
    // Write the command and wait until the STB>MAV bit is set.
    ASSERT_EQ(true, pInstrument->Write ("*IDN?"));
    U16 l_Status = 0;
    do
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
        ASSERT_EQ(true, pInstrument->ReadSTB (l_Status));
    } while ((l_Status & 0x0010) == 0);

    // A Clear should clear the output buffer, and therefore the MAV bit.
    pInstrument->Clear();
    ASSERT_EQ(true, pInstrument->ReadSTB (l_Status));
    ASSERT_EQ(0, (l_Status & 0x0010));
    CSCPIBuffer l_Buffer;
    ASSERT_EQ(false, pInstrument->Read (l_Buffer));

    // Verify that the *IDN? query still works after all that.
    ASSERT_EQ(true, pInstrument->Write ("*IDN?"));
    ASSERT_EQ(true, pInstrument->Read (l_Buffer));
    EXPECT_EQ(true, CheckIDNResponse (l_Buffer));

}

/// \brief Test Trigger.
TEST_F(IEEE488InstrumentMiscUtilitiesTest, Trigger)
{
#ifndef INSTRUMENT_TYPE_IS_VXI11
    // Start triggered acquisition, with ten triggers.
    ASSERT_EQ(true, pInstrument->Write(":TRIG:SOUR BUS;COUN 10;:INIT"));

    // Issue the triggers. Before each one, verify that we're waiting for trigger.
    CSCPIBuffer l_Buffer;
    std::string l_Result;
    U16 l_OperStatus;
    for (int i = 0; i < 10; i++)
    {
        ASSERT_EQ(true, pInstrument->Write (":STAT:OPER?"));
        ASSERT_EQ(true, pInstrument->Read (l_Buffer));
        l_Result = std::string(l_Buffer.begin(), l_Buffer.end());
        l_OperStatus = static_cast<U16>(std::stoul(l_Result));
        EXPECT_EQ(0x0020, (l_OperStatus & 0x0020));
        ASSERT_EQ(true, pInstrument->AssertTrigger());
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }

    // Now we should no longer be waiting for trigger.
    ASSERT_EQ(true, pInstrument->Write (":STAT:OPER?"));
    ASSERT_EQ(true, pInstrument->Read (l_Buffer));
    l_Result = std::string(l_Buffer.begin(), l_Buffer.end());
    l_OperStatus = static_cast<U16>(std::stoul(l_Result));
    EXPECT_EQ(0x0000, (l_OperStatus & 0x0020));

    // Fetch the measurements. There should be ten of them.
    ASSERT_EQ(true, pInstrument->Write (":FETC:ARR? 10"));
    ASSERT_EQ(true, pInstrument->Read (l_Buffer));
    l_Result = std::string(l_Buffer.begin(), l_Buffer.end());
    std::regex  l_Regex("(([^,]+),){9}([^,]+)");
    std::smatch l_Match;
    EXPECT_EQ(true, std::regex_match(l_Result, l_Match, l_Regex));

    // Verify that the *IDN? query still works after all that.
    ASSERT_EQ(true, pInstrument->Write ("*IDN?"));
    ASSERT_EQ(true, pInstrument->Read (l_Buffer));
    EXPECT_EQ(true, CheckIDNResponse (l_Buffer));
#else
    // The VXI11 test uses the NI-Device TcpIpDevice example, which is dumb.
    for (int i = 0; i < 10; i++)
    {
        ASSERT_EQ(true, pInstrument->AssertTrigger());
    }
    std::cout << "Need to verify that NI-Device TcpIpDevice saw 10 triggers!" << std::endl;
#endif
}
