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

#include "ControlThread.h"

//===================================================================
/// Constructor.
ControlThread::ControlThread()
    : AsyncComponent( "controlThread", NULL, Timespan( DEFAULT_CONTROL_THREAD_PERIOD ) ),
      syncHandler_( *this, logger_ ),
      componentsToAdd_( false ),
      componentsToRemove_( false ),
      addComponentsMutex_(),
      removeComponentsMutex_()
{
    // Enable duration of last run logging for main loop
    enableMetering( true );
}

/// Destructor.
ControlThread::~ControlThread()
{}

/// Initialize
void ControlThread::initialize( void )
{
    logger_.syslog( "Initializing ControlThread" );

    // Check for new components to be added
    addComponentsFromQueue();

    // (ok, so technically this won't happen very often, but good to do
    // for completeness
    removeComponentsFromQueue();

    syncHandler_.syslogComponentOrder( logger_ );

}

/// Run
void ControlThread::run( void )
{
    // Check for any factors which might affect the order in which components
    // are run
    //printf( "Running ControlThread\n" );

    syncHandler_.run();

    // Check for new components to be added
    if( addComponentsFromQueue() > 0 )
    {
        syncHandler_.syslogComponentOrder( logger_ );
    }
    if( removeComponentsFromQueue() > 0 )
    {
        syncHandler_.syslogComponentOrder( logger_ );
    }

}

/// Uninitialize
void ControlThread::uninitialize( void )
{
    logger_.syslog( "Uninitializing ControlThread" );

    syncHandler_.shutdown();
}

//== Functions for dealing with the list of components ==
/// Put a component in the control thread's control.
void ControlThread::addComponent( SyncComponent* component )
{
    MutexLocker locker( addComponentsMutex_ );
    componentsToAdd_.push( component );
}

/// Remove a component from the control thread's control.
void ControlThread::removeComponent( SyncComponent* component )
{
    MutexLocker locker( removeComponentsMutex_ );
    componentsToRemove_.push( component );
}

int ControlThread::addComponentsFromQueue( void )
{
    MutexLocker locker( addComponentsMutex_ );
    int totalAdded = 0;
    while( !componentsToAdd_.isEmpty() )
    {
        SyncComponent* component = componentsToAdd_.pop( 0 );

        if( component->getName() == "ExternalSim" )
        {
            totalAdded = totalAdded + 0;
        }
        if( true == syncHandler_.addComponent( component ) )
        {
            totalAdded++;
        }
    }
    return totalAdded;
}

int ControlThread::removeComponentsFromQueue( void )
{
    MutexLocker locker( removeComponentsMutex_ );
    int totalRemoved = 0;

    // Check for components to be removed
    while( !componentsToRemove_.isEmpty() )
    {
        SyncComponent* component = componentsToRemove_.pop( 0 );

        if( true == syncHandler_.removeComponent( component ) )
        {
            totalRemoved++;
        }
    }
    return totalRemoved;
}
