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

#include "LogEntry.h"

#include "logger/DataEntry.h"
#include "logger/DirectoryEntry.h"
#include "logger/EventEntry.h"
#include "logger/Logger.h"
#include "logger/SyslogEntry.h"

const Str LogEntry::UNKNOWN( "Unknown" );

/// Constructor
LogEntry::LogEntry( Type myType, const Timestamp& timestamp, Service::ServiceType serviceType )
    : type_( myType ),
      serviceType_( serviceType )
{
    if( timestamp == Timestamp::NOT_SET_TIME )
    {
        timestamp_ = Timestamp::Now();
    }
    else
    {
        timestamp_ = timestamp;
    }
}

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

/// Convert a Type to a Str
const char* LogEntry::TypeToString( Type theType )
{
    switch( theType )
    {
    case NOT_LOG_ENTRY:
        return "NOT_LOG_ENTRY";
    case EVENT_LOG_ENTRY:
        return "EVENT";
    case DIRECTORY_LOG_ENTRY:
        return "DIRECTORY";
    case DATA_LOG_ENTRY:
        return "DATA";
    case SYSLOG_LOG_ENTRY:
        return "SYSLOG";
    }
    return "(undefined)";
}

LogEntry* LogEntry::Read( Timestamp& timeBase, Timespan& timeAdjust, InStream &inStream, Logger& logger, bool& error )
{
    unsigned short firstWord;
    bool ok = !inStream.readUShortCompact( firstWord ).eof();

    if( !ok )
    {
        return NULL;
    }

    unsigned short logEntryType = firstWord & LogEntry::TYPE_MASK;
    switch( logEntryType )
    {
    case LogEntry::EVENT_LOG_ENTRY:
        return EventEntry::Read( timeBase, timeAdjust, inStream, firstWord, logger, error );
    case LogEntry::DIRECTORY_LOG_ENTRY:
        return DirectoryEntry::Read( timeBase, inStream, firstWord, logger, error );
    case LogEntry::DATA_LOG_ENTRY:
        return DataEntry::Read( timeBase, inStream, firstWord, logger, error );
    case LogEntry::SYSLOG_LOG_ENTRY:
        return SyslogEntry::Read( timeBase, timeAdjust, inStream, firstWord, logger, error );
    }
    return NULL;
}

bool LogEntry::ReadTimestamp( Timestamp& timestamp, bool& changed, InStream& inStream, Logger& logger, Logger::TimePrecisionType timePrecision )
{
    bool ok( true );
    long long timeCode;
    if( inStream.readLongLongCompact( timeCode ).eof() )
    {
        logger.syslog( "End of Binary File Reached while reading LogEntry Timestamp", Syslog::ERROR );
        ok = false;
        changed = false;
    }
    else if( DirectoryEntry::GetCurrentLogVersion() < 0x0004 )
    {
        changed = true;
        timestamp.addFromMicros( timeCode );
    }
    else
    {
        changed = timeCode & 0x01;
        timeCode >>= 1;
        switch( timePrecision )
        {
        case Logger::TIME_PRECISION_MILLIS:
            timestamp.addFromMillis( timeCode );
            break;
        case Logger::TIME_PRECISION_MICROS:
            timestamp.addFromMicros( timeCode );
            break;
        }
    }
    return ok;
}

unsigned int LogEntry::writeTimestamp( const Timestamp & timeBase, bool changed, OutStream & logStream, Logger::TimePrecisionType timePrecision ) const
{
    long long timeCode;
    switch( timePrecision )
    {
    case Logger::TIME_PRECISION_MICROS:
        timeCode = ( timestamp_ - timeBase ).asCompactMicros() * 2;
        break;
    case Logger::TIME_PRECISION_MILLIS:
        timeCode = ( timestamp_ - timeBase ).asCompactMillis() * 2;
        break;
    }
    if( changed )
    {
        ++timeCode;
    }
    return logStream.writeLongLongCompact( timeCode ).bytesWritten();
}
