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

#include "LogEngine.h"

//#include "supervisor/CycleStarter.h"

// Constructor
LogEngine::LogEngine( )
    : queue_( LogQueue::Instance() ),
      associations_( )
{
}

LogEngine::LogEngine( LogQueue& queue )
    : queue_( queue ),
      associations_( )
{
}

// Destructor
LogEngine::~LogEngine()
{
    uninitialize();
}

/// Reset cached input settings
void LogEngine::resetInputs()
{
    /// Work through associations
    for( int i = associations_.getMinIndex(); i <= associations_.getMaxIndex(); ++i )
    {
        associations_[i]->resetInputs();
    }
}

// Initialize
void LogEngine::initialize( void )
{
}

void LogEngine::processEntry( LogEntry* thisEntry )
{
    MutexLocker locker( mutex_ );
    /// Split this out so it can be called without queue overhead by unserializers
    /// Work through associations
    for( int i = associations_.getMinIndex(); i <= associations_.getMaxIndex(); ++i )
    {
        associations_[i]->matchAndProcess( thisEntry );
    }
}

void LogEngine::processQueue( const Timespan& timeout )
{
    /// Split this out so it can be called from run() and from uninit()

    Timestamp startTime( Timestamp::Now() );
    while( !queue_.isEmpty()
            && ( timeout == Timespan::ZERO_TIMESPAN || startTime.elapsed() < timeout ) )
    {
        //printf("Logger read/write queue(%08X) size is %d/%d\n", (unsigned int)&queue_.getLoggerWaitMutex(), queue_.readQueueSize(), queue_.writeQueueSize());
        //queue_.swap();
        //while ( !queue_.isEmpty() )
        //{
        /// Pass queued items to appropriate writers
        LogEntry* thisEntry = queue_.pop();

        processEntry( thisEntry );

        /// done with the LogEntry.
        /// don't delete the special start cycle event entry
        //if( thisEntry != CycleStarter::GetCycleStartEntry() )
        //{
        delete thisEntry;
        //}

        //}
    }

    for( int i = associations_.getMinIndex(); i <= associations_.getMaxIndex(); ++i )
    {
        associations_[i]->endCycle();
    }
}

// Deinitialize
void LogEngine::uninitialize( void )
{
    //printf("Logger::uninitialize with queue(%08X)\n", (unsigned int)&queue_.getLoggerWaitMutex());

    // Hm.  Lifespan issue.  This function might be called several
    // times -- once when the component ends or is cancelled, then again
    // in the destructor (this is probably a bad idea).
    /// Should try to flush the queue one last time
    /// could skip this step if something's wrong...
    //printf("Calling Logger::processQueue\n");
    processQueue( Timespan::ZERO_TIMESPAN );


    for( int i = associations_.getMinIndex(); i <= associations_.getMaxIndex(); ++i )
    {
        associations_[i]->writeFooter();
    }
    // Who cleans up the queue?  Or we could mark it as "unusued"
    //printf("Calling Logger::cleanupAll\n");
    cleanupAll();
    //printf("Logger::uninitialize done.\n");
}

void LogEngine::cleanupAll( void )
{

    // Now really clean up
    //printf("Logger::cleanupAll with queue(%08X)\n", (unsigned int)&queue_.getLoggerWaitMutex());
    associations_.clear();
}

/// Add an entry to the LoggerAssociations table
LogAssociation* LogEngine::addAssociation( LogWriter* logWriter, Rule* rule )
{
    return associations_.add( logWriter, rule );
}

/// Remove an entry from the LoggerAssociations table
void LogEngine::removeAssociation( LogWriter* logWriter )
{
    associations_.remove( logWriter );
}

/// Configure logWriters
void LogEngine::configAssociatedLogWriters( Logger& sysLogger )
{
    for( int i = associations_.getMinIndex(); i <= associations_.getMaxIndex(); ++i )
    {
        associations_[i]->configLogWriter( sysLogger );
    }
}

