/** \file
 *
 *  Contains the Behavior class implementation.
 *
 *  Copyright (c) 2007,2008,2009 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 *
 */

#include "Behavior.h"

#include "data/Slate.h"

Behavior::~Behavior()
{
    if( NULL != settingReaderMap_ )
    {
        delete settingReaderMap_;
    }
    if( NULL != argWriterMap_ )
    {
        delete argWriterMap_;
    }
}

/// Combined run and test with metrics generation
bool Behavior::executeIfUnsatisfied()
{
    bool satisfied = false;
    if( true == enabled_ )
    {
        // Now run it.
        Timestamp beforeRun, afterRun;
        Timespan runTime, dt;

        beforeRun = Timestamp::Now();
        setTimeOfRun( beforeRun );

        if( timeOfLastRun_ == Timestamp::NOT_SET_TIME )
        {
            dt = Timespan::INVALID_TIMESPAN;
        }
        else
        {
            dt = beforeRun - timeOfLastRun_;
        }
        setDt( dt );

        if( broadcastRequested() )
        {
            // init messaging
        }

        satisfied = runIfUnsatisfied();

        // Publish new data over the broadcast channel
        if( broadcastEnabled_ )
            publish();

        afterRun = Timestamp::Now();

        runTime = afterRun - beforeRun;

        setTimeOfLastRun( beforeRun );
        setDurationOfLastRun( runTime );
    }
    return satisfied;
}

/// Combined run and test
/// Called by mission element: behaviorDone_
bool Behavior::runIfUnsatisfied()
{
    if( isSatisfied() )
    {
        return true;
    }
    else
    {
        run();
        return false;
    }
}

SettingReader* Behavior::addValueClause( const Str& uriPart, ValueClause* valueClause )
{
    if( NULL == settingReaderMap_ )
    {
        settingReaderMap_ = new FastMap<const Str, SettingReader*>( false );
    }
    SettingReader* settingReader = settingReaderMap_->get( uriPart );

    if( NULL == settingReader )
    {
        SettingURI settingURI( uriPart.cStr(), Units::NONE );
        settingReader = new SettingReader( settingURI, valueClause );
        settingReaderMap_->put( uriPart, settingReader, true );
    }
    else
    {
        settingReader->setValueClause( valueClause );
    }
    return settingReader;
}

SettingReader* Behavior::newSettingReader( const Str& uriPart, const DataValue* defaultValue, bool deleteDefaultValue )
{
    if( NULL == settingReaderMap_ )
    {
        settingReaderMap_ = new FastMap<const Str, SettingReader*>( false );
    }
    SettingReader* settingReader = settingReaderMap_->get( uriPart );

    if( NULL == settingReader )
    {
        SettingURI settingURI( uriPart.cStr(), Units::NONE );
        settingReader = new SettingReader( settingURI, defaultValue, deleteDefaultValue );
        settingReaderMap_->put( uriPart, settingReader, true );
    }
    else
    {
        settingReader->setDefaultValue( defaultValue, deleteDefaultValue );
    }
    return settingReader;
}

SettingReader* Behavior::newSettingReader( const SettingURI& settingURI )
{
    if( NULL == settingReaderMap_ )
    {
        settingReaderMap_ = new FastMap<const Str, SettingReader*>( false );
    }
    SettingReader* settingReader = settingReaderMap_->get( settingURI );

    if( NULL == settingReader )
    {
        settingReader = new SettingReader( settingURI, settingURI.getUnit().dataValue( settingURI.getBinaryType() ), true );
        settingReaderMap_->put( settingURI, settingReader, true );
    }
    return settingReader;
}

SettingReader* Behavior::findSettingReader( const Str& settingURI )
{
    if( NULL == settingReaderMap_ )
    {
        return NULL;
    }
    return settingReaderMap_->get( settingURI );
}

void Behavior::addArgWriter( const Str& uriPart, DataWriter* argWriter )
{
    if( NULL == argWriterMap_ )
    {
        argWriterMap_ = new FastMap<const Str, DataWriter*>();
    }
    argWriterMap_->put( uriPart, argWriter );
}

DataWriter* Behavior::findArgWriter( const OutputURI& uriPart )
{
    if( NULL == argWriterMap_ )
    {
        return NULL;
    }
    return argWriterMap_->get( uriPart );
}

/// Protected constructor for abstract base class
Behavior::Behavior( const Str& name, const Module* module,
                    const bool runnable, const bool satisfiable )
    : LcmMessagingComponent( name, COMPONENT_BEHAVIOR, module ),
      runnable_( runnable ),
      satisfiable_( satisfiable ),
      behaviorState_( Behavior::BEHAVIOR_INACTIVE ),
      timeout_( Timespan::INVALID_TIMESPAN ),
      settingReaderMap_( NULL ),
      argWriterMap_( NULL )
{}

/// Protected constructor for abstract base class
Behavior::Behavior( const Str& name, const Module* module,
                    const bool runnable, const bool satisfiable,
                    const DataURI& enableBroadcast )
    : LcmMessagingComponent( name, COMPONENT_BEHAVIOR, module, enableBroadcast ),
      runnable_( runnable ),
      satisfiable_( satisfiable ),
      behaviorState_( Behavior::BEHAVIOR_INACTIVE ),
      timeout_( Timespan::INVALID_TIMESPAN ),
      settingReaderMap_( NULL ),
      argWriterMap_( NULL )
{}

