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

#include "MultiHandler.h"
#include "process/PCaller.h"
#include "supervisor/CycleStarter.h"

//===================================================================
// == MultiHandler ==
MultiHandler::MultiHandler( Component& owner, const Str& name )
    : Handler( owner, name ),
      components_( true ),
      runNextIndex_( 0 ),
      runnable_( true ),
      running_( false ),
      runningComponent_( NULL ),
      mutex_()
{}

/// Destructor
MultiHandler::~MultiHandler()
{}

void MultiHandler::shutdown()
{
    MutexLocker lock( mutex_ );
    stopRuns();
    // Wait up to 5 seconds
    for( int i = 0; isRunning() && i < 15; ++i )
    {
        printf( "Waiting for component %s to stop running.\n", component_.getName().cStr() );
        Timespan::Seconds( 0.20 ).sleepFor();
    }

    /// Uninitialize any components I may have
    for( unsigned int i = 0; i < components_.size(); ++i )
    {
        //Entry* entry = ( *itr );
        Component* component = components_.getIndexed( i );
        //entry->component_->uninitialize();
        //pCaller_.pUninitialize( *( entry->component_ ) );
        pCaller_->pUninitialize( *component );
    }

    clearComponentList();

}

bool MultiHandler::addComponent( SyncComponent* component )
{

    // Look for duplicates
    //ListOfComponents::iterator itr;
    unsigned int i;
    for( i = 0; i < components_.size(); ++i )
    {
        if( components_.getIndexed( i ) == component )
        {
            break;
        }
    }

    // Check and see if you made it to the end
    if( i >= components_.size() )
    {
        // No duplicate found, add new one.
        SyncComponent::CycleOrder order = component->getCycleOrder();
        components_.put( order, component );
        if( component->isRepeater() )
        {
            SyncComponent::CycleOrder repeatOrder( ( int )order + SyncComponent::CYCLE_REPEAT_OFFSET );
            components_.put( repeatOrder, component );
        }

        pCaller_->pInitialize( *component );
        return true;
    }

    // Return false if duplicate found
    return false;
}

//bool MultiHandler::addComponent( Component* component )
//{
//    Entry *newEntry = new Entry( component );
//    return addComponent( newEntry );
//}

bool MultiHandler::removeComponent( SyncComponent* component )
{
    bool success = false;
    for( unsigned int i = 0; i < components_.size(); ++i )
    {
        if( components_.getIndexed( i ) == component )
        {
            if( !success )
            {
                component->uninitialize();
                success = true;
            }
            components_.popIndexed( i );
        }
    }
    return success;
}

/// Run all items in the list of components
void MultiHandler::runAll()
{
    runNextIndex_ = 0;
    while( runNextIndex_ < components_.size() )
    {
        runNext();
    }
}

/// Run next item in the list of components
void MultiHandler::runNext()
{
    if( isRunnable() && components_.size() > 0 )
    {
        running_ = true;
        if( components_.size() <= runNextIndex_ )
        {
            runNextIndex_ = 0;
        }
        //runningComponent_ = ( *runNext_ )->component_;
        MapEntry<SyncComponent::CycleOrder, SyncComponent*>* entry =  components_.getIndexedEntry( runNextIndex_ );
        int order = ( int )entry->getKey();
        runningComponent_ = entry->getItem();
        if( runningComponent_->getDivisor() == 1
                || CycleStarter::GetCycle() % runningComponent_->getDivisor()
                == runningComponent_->getModulo() )
        {
            runningComponent_->setRepeating( ( order % SyncComponent::CYCLE_INCREMENT ) == SyncComponent::CYCLE_REPEAT_OFFSET );
            //printf("Executing %s\n", runningComponent_->getName().c_str() );
            //runningComponent_->execute();
            pCaller_->pExecute( *runningComponent_ );
        }
        runningComponent_ = NULL;
        ++runNextIndex_;
        running_ = false;
    }
}

void MultiHandler::clearComponentList( void )
{
    while( components_.size() > 0 )
    {
        components_.popIndexed( components_.size() - 1 );
    }
}

void MultiHandler::syslogComponentOrder( Logger &logger )
{
    Str message( "Component order: " );
    for( unsigned int i = 0; i < components_.size(); ++i )
    {
        //message += ( *itr )->component_->getName() + ",";
        message += components_.getIndexed( i )->getName() + ",";
    }
    logger.syslog( message );
}
