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

#include "BinaryLogReader.h"
#include "data/Slate.h"
#include "io/InStream.h"
#include "logger/LogEngine.h"

/// Default Constructor
BinaryLogReader::BinaryLogReader( Logger& sysLogger,
                                  const Timestamp& startTime, const Timestamp& endTime,
                                  const Str& whileRunningName,
                                  LogEngine* writeEngine, LogEngine* syslogEngine, bool debug )
    : LogReader(),
      timeBase_( Timespan::NOT_SET_TIME ),
      timeAdjust_( Timespan::ZERO_TIMESPAN ),
      sysLogger_( sysLogger ),
      startTime_( startTime ),
      endTime_( endTime ),
      whileRunningName_( whileRunningName ),
      writeEngine_( writeEngine ),
      syslogEngine_( syslogEngine ),
      firstTime_( Timestamp::NOT_SET_TIME ),
      lastTime_( Timestamp::NOT_SET_TIME ),
      whileRunningCode_( CodedStr::NO_CODE ),
      running_( false ),
      debug_( debug )
{}

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

unsigned int BinaryLogReader::read()
{
    unsigned int entriesRead( 0 );

    bool doStartTime( startTime_ != Timestamp::NOT_SET_TIME );
    bool doEndTime( endTime_ != Timestamp::NOT_SET_TIME );
    bool doWhileRunning( whileRunningName_ != Str::EMPTY_STR );
    bool runEnding( false );
    setError( false );

    if( logStream_->eof() != true )
    {
        if( doWhileRunning && whileRunningCode_ == CodedStr::NO_CODE )
        {
            CodedStr* codedStr = Slate::FindCodedName( whileRunningName_ );
            if( NULL != codedStr )
            {
                whileRunningCode_ = codedStr->getCode();
            }
        }

        bool logHasError( false );
        if( debug_ && NULL != writeEngine_ )
        {
            writeEngine_->processEntry( new SyslogEntry( Str( "inStream at 0x" ) + logStream_->getTotalBytesRead(), Syslog::INFO, sysLogger_.getFacility() ) );
        }
        LogEntry* entry( LogEntry::Read( timeBase_, timeAdjust_, *logStream_, sysLogger_, logHasError ) );

        // Temporary workaround to prevent erroneous parsing of timestamps until we take the
        // time to reformat the LRAUV binary packet structure. Basically, ignore timestamps
        // set to \> 1 year before beginning of epoch (that's what NOT_SET_TIME is) and
        // timestamps that are further than a month in the future from time of read
        // (2628000 seconds).
        if( NULL != entry && ( entry->getTimestamp() < Timestamp::EPOCH_START_TIME
                               || entry->getTimestamp().asFloat() > ( Timestamp::Now().asFloat() + 2628000 ) ) )
        {
            sysLogger_.syslog( "LogEntry timebase value of " + Str( timeBase_.asFloat(), 2 ) + " is out of bounds.", Syslog::ERROR );
            sysLogger_.syslog( "inStream at 0x", logStream_->getTotalBytesRead(), Syslog::ERROR );
            timeBase_ = Timestamp::NOT_SET_TIME;
            logHasError = true;
        }

        if( logHasError )
        {
            delete entry;
            if( runEnding )
            {
                running_ = false;
            }
            entry = NULL;
            setError( logHasError );
        }

        if( NULL != entry )
        {
            if( doWhileRunning && entry->getType() == LogEntry::EVENT_LOG_ENTRY )
            {
                EventEntry* eventEntry = ( EventEntry* )entry;
                if( eventEntry->getEventType() == EventEntry::COMPONENT_ACTION )
                {
                    if( eventEntry->getComponentAction() == EventEntry::COMPONENT_MISSION_RUN )
                    {
                        if( eventEntry->getActorCode() == whileRunningCode_ )
                        {
                            if( eventEntry->getRunLoop() != 0 )
                            {
                                running_ = true;
                            }
                            else
                            {
                                runEnding = true;
                            }
                        }
                    }
                }
            }
            ++entriesRead;
            if( NULL != writeEngine_
                    && ( !doStartTime || entry->getTimestamp() >= startTime_ )
                    && ( !doEndTime || entry->getTimestamp() <= endTime_ )
                    && ( !doWhileRunning || running_ ) )
            {
                if( firstTime_ == Timestamp::NOT_SET_TIME
                        && timeBase_ != Timestamp::NOT_SET_TIME
                        && entry->getType() != LogEntry::DIRECTORY_LOG_ENTRY )
                {
                    firstTime_ = entry->getTimestamp();
                }
                lastTime_ = entry->getTimestamp();
                writeEngine_->processEntry( entry );
            }
            delete entry;
            if( runEnding )
            {
                running_ = false;
            }
            entry = NULL;
        }

        /// serialize the syslog.
        if( NULL != syslogEngine_ )
        {
            syslogEngine_->processQueue( Timespan::ZERO_TIMESPAN );
        }
    }

    return entriesRead;
}
