/** \file
 *
 *  Contains unit tests for the ValueDetect class
 *
 *  Copyright (c) 2007,2008,2009 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 */

#ifndef _VALUEDETECT_TEST_H_
#define _VALUEDETECT_TEST_H_

#include "controlModule/SpeedControlIF.h"
#include "triggerModule/ValueDetect.h"
#include "triggerModule/ValueDetectIF.h"

#include "component/TestAsyncComponent.h"
#include "data/Slate.h"
#include "data/UniversalDataWriter.h"
#include "logger/LogEngine.h"
#include "units/Units.h"

#include <cxxtest/TestSuite.h>

/**
 *  Units tests for ValueDetect class
 *
 *  \ingroup modules_guidance
 */
class ValueDetect_Test : public CxxTest::TestSuite
{
public:

    // Ensures the syslog is empty at the end of the run.
    void tearDown( void )
    {
        LogEngine logEngine;
        logEngine.processQueue( Timespan::ZERO_TIMESPAN );
    }

    // run test with delta
    void testRunDelta( void )
    {
        BehaviorRegistry::Initialize();
        BehaviorRegistry::Insert( ValueDetectIF::NAME, &ValueDetect::CreateBehavior, NULL );
        TestAsyncComponent testComponent( "ValueDetect_TestComponent" );

        // Slate input variables
        UniversalDataWriter* valueWriter = Slate::NewUniversalWriter( UniversalURI::SEA_WATER_TEMPERATURE, &testComponent, Units::CELSIUS( nanf( "" ) ) );

        // Build up the behavior as if it were expressed in XML
        MissionNode valueDetectNode( "Trigger:ValueDetect" );
        valueDetectNode.appendChild( "Parallel" );
        MissionNode* detectSettingNode( valueDetectNode.appendChild( "Setting" ) );
        detectSettingNode->appendChild( "Trigger:ValueDetect.detect" );
        detectSettingNode->appendChild( "Universal:sea_water_temperature" );
        MissionNode* valueSettingNode( valueDetectNode.appendChild( "Setting" ) );
        valueSettingNode->appendChild( "Trigger:ValueDetect.value" );
        valueSettingNode->appendChild( "Units:celsius" );
        valueSettingNode->appendChild( "Value" )->appendChildText( "10" );
        MissionNode* deltaSettingNode( valueDetectNode.appendChild( "Setting" ) );
        deltaSettingNode->appendChild( "Trigger:ValueDetect.delta" );
        deltaSettingNode->appendChild( "Units:kelvin" );
        deltaSettingNode->appendChild( "Value" )->appendChildText( "0.1" );

        // Convert the virtual XML to a behavior
        MissionItem* valueDetectMissionItem( MissionItem::Instance( NULL, &valueDetectNode, 0, testComponent.getLogger() ) );
        ValueDetect* valueDetectPtr = ( ValueDetect* )( valueDetectMissionItem->getComponent() );
        ValueDetect& valueDetect( *valueDetectPtr );

        // Initialize the behavior
        valueDetect.initialize();

        bool satisfied = valueDetect.runIfUnsatisfied();
        TS_ASSERT( !satisfied );

        valueWriter->writeWithAccuracy( Units::CELSIUS, 11.0, 0.05 );
        satisfied = valueDetect.runIfUnsatisfied();
        TS_ASSERT( !satisfied );

        valueWriter->writeWithAccuracy( Units::CELSIUS, 10.05, 0.05 );
        satisfied = valueDetect.runIfUnsatisfied();
        TS_ASSERT( satisfied );

        valueWriter->writeWithAccuracy( Units::CELSIUS, 10.0, 0.05 );
        satisfied = valueDetect.runIfUnsatisfied();
        TS_ASSERT( satisfied );

        valueWriter->writeWithAccuracy( Units::CELSIUS, 9.0, 0.05 );
        satisfied = valueDetect.runIfUnsatisfied();
        TS_ASSERT( !satisfied );

        // cleanup
        valueDetect.uninitialize();
        delete valueDetectMissionItem;
        BehaviorRegistry::Uninitialize();
    }

    // run test with no delta
    void testRunNoDelta( void )
    {
        BehaviorRegistry::Initialize();
        BehaviorRegistry::Insert( ValueDetectIF::NAME, &ValueDetect::CreateBehavior, NULL );
        TestAsyncComponent testComponent( "ValueDetect_TestComponent" );

        // Slate input variables
        UniversalDataWriter* valueWriter = Slate::NewUniversalWriter( UniversalURI::SEA_WATER_TEMPERATURE, &testComponent, Units::CELSIUS( nanf( "" ) ) );

        // Build up the behavior as if it were expressed in XML
        MissionNode valueDetectNode( "Trigger:ValueDetect" );
        valueDetectNode.appendChild( "Parallel" );
        MissionNode* detectSettingNode( valueDetectNode.appendChild( "Setting" ) );
        detectSettingNode->appendChild( "Trigger:ValueDetect.detect" );
        detectSettingNode->appendChild( "Universal:sea_water_temperature" );
        MissionNode* valueSettingNode( valueDetectNode.appendChild( "Setting" ) );
        valueSettingNode->appendChild( "Trigger:ValueDetect.value" );
        valueSettingNode->appendChild( "Units:celsius" );
        valueSettingNode->appendChild( "Value" )->appendChildText( "10" );

        // Convert the virtual XML to a behavior
        MissionItem* valueDetectMissionItem( MissionItem::Instance( NULL, &valueDetectNode, 0, testComponent.getLogger() ) );
        ValueDetect* valueDetectPtr = ( ValueDetect* )( valueDetectMissionItem->getComponent() );
        ValueDetect& valueDetect( *valueDetectPtr );

        // Initialize the behavior
        valueDetect.initialize();

        bool satisfied = valueDetect.runIfUnsatisfied();
        TS_ASSERT( !satisfied );

        valueWriter->writeWithAccuracy( Units::CELSIUS, 11.0, 0.05 );
        satisfied = valueDetect.runIfUnsatisfied();
        TS_ASSERT( !satisfied );

        valueWriter->writeWithAccuracy( Units::CELSIUS, 10.05, 0.05 );
        satisfied = valueDetect.runIfUnsatisfied();
        TS_ASSERT( !satisfied );

        valueWriter->writeWithAccuracy( Units::CELSIUS, 10.0, 0.05 );
        satisfied = valueDetect.runIfUnsatisfied();
        TS_ASSERT( satisfied );

        valueWriter->writeWithAccuracy( Units::CELSIUS, 9.0, 0.05 );
        satisfied = valueDetect.runIfUnsatisfied();
        TS_ASSERT( satisfied );

        valueWriter->writeWithAccuracy( Units::CELSIUS, 8.0, 0.05 );
        satisfied = valueDetect.runIfUnsatisfied();
        TS_ASSERT( !satisfied );

        valueWriter->writeWithAccuracy( Units::CELSIUS, 11.0, 0.05 );
        satisfied = valueDetect.runIfUnsatisfied();
        TS_ASSERT( satisfied );

        // cleanup
        valueDetect.uninitialize();
        delete valueDetectMissionItem;
        BehaviorRegistry::Uninitialize();
    }

};

#endif // _VALUEDETECT_TEST_H
