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

#include "MessagingComponent.h"
#include "Component.h"
#include "data/Slate.h"
#include "data/MessagingDataWriter.h"


MessagingComponent::MessagingComponent( const Str& name, ComponentType componentType, const Module* module )
    : Component( name, componentType, module ),
      enableBroadcastWriter_( NULL ),
      broadcastEnabled_( false )
{
    if( componentType == COMPONENT_SYNC || componentType == COMPONENT_ASYNC )
    {
        // Create broadcast enable writer to sense message broacast requests
        const DataURI ENABLE_BROADCAST( getName(), "enableBroadcast", Units::BOOL );
        enableBroadcastWriter_ = newDataWriter( ENABLE_BROADCAST );
    }
}

MessagingComponent::MessagingComponent( const Str& name, ComponentType componentType, const Module* module, const DataURI& enableBroadcast )
    : Component( name, componentType, module ),
      enableBroadcastWriter_( NULL ),
      broadcastEnabled_( false )
{
    enableBroadcastWriter_ = newDataWriter( enableBroadcast );
}

MessagingComponent::~MessagingComponent()
{}

bool MessagingComponent::broadcastRequested()
{
    if( NULL != enableBroadcastWriter_ )
    {
        bool enable = enableBroadcastWriter_->isDataRequested();

        if( broadcastEnabled_ != enable )
        {
            // Update the class member
            broadcastEnabled_ = enable;

            if( broadcastEnabled_ )
            {
                // Publish state switch to the Slate and activate messaging
                enableBroadcastWriter_->write( Units::BOOL, enable );
                activateMessaging();
            }
            else
            {
                // Deactivate messaging and publish state switch to the Slate
                deactivateMessaging();
                enableBroadcastWriter_->write( Units::BOOL, enable );
            }
        }
    }

    return broadcastEnabled_;
}

void MessagingComponent::execute( void )
{
    if( true == enabled_ )
    {
        // Run the component
        setTimeOfRun( Timestamp::Now() );

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

        if( broadcastRequested() )
        {
            // initializes broadcasting.
        }

        // Execute the component's run state
        executeRunState();

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

        setDurationOfLastRun( Timestamp::Now() - getTimeOfRun() );
        setTimeOfLastRun( getTimeOfRun() );
    }
    else
    {
        if( getRunState() != STOPPED && getRunState() != STOPPING )
        {
            setRunState( stop() );
        }
        else if( getRunState() == STOPPING )
        {
            setRunState( stopping() );
        }
        else
        {
            setRunState( stopped() );
        }
    }
}

DataWriter* MessagingComponent::newDataWriter( const DataURI& dataURI, Logger::TimePrecisionType timePrecision )
{
    DataElement* newElement = Slate::GetElement( dataURI );
    if( NULL == newElement )
    {
        newElement = Slate::NewDataElement( dataURI, this, dataURI.getUnit(), dataURI.getBinaryType() );
    }
    DataWriter* writer = new MessagingDataWriter( this, *newElement, NULL, timePrecision );
    return writer;
}

DataWriter* MessagingComponent::newDataWriter( const Str& channel,
        const DataURI& dataURI,
        Logger::TimePrecisionType timePrecision )
{
    DataElement* newElement = Slate::GetElement( dataURI );
    if( NULL == newElement )
    {
        newElement = Slate::NewDataElement( dataURI, this, dataURI.getUnit(), dataURI.getBinaryType() );
    }
    DataWriter* writer = new MessagingDataWriter( this, *newElement, NULL, timePrecision, channel );
    return writer;
}
