/** \file
*
*  Contains the various /ref logging Rule class implementations that
*  are used by LogEngine to determine which LogWriter(s) to use for each
*  LogEntry as they are popped off the LogQueue.
*
*  Copyright (c) 2007,2008,2009 MBARI
*  MBARI Proprietary Information.  All Rights Reserved
*
*/

#include "LoggerRules.h"

#include "data/Slate.h"
#include "logger/DataEntry.h"
#include "logger/EventEntry.h"
#include "logger/SyslogEntry.h"

Rule::Rule( void )
    : active_( true )
{}

void Rule::activate()
{
    active_ = true;
}

void Rule::deactivate()
{
    active_ = false;
}

bool Rule::isActive()
{
    return active_;
}

AndRule::AndRule( Rule *ruleOneIn,
                  Rule *ruleTwoIn,
                  Rule *ruleThreeIn,
                  Rule *ruleFourIn,
                  Rule *ruleFiveIn,
                  Rule *ruleSizIn,
                  Rule *ruleSevenIn )
    : ruleOne_( ruleOneIn ),
      ruleTwo_( ruleTwoIn ),
      ruleThree_( ruleThreeIn ),
      ruleFour_( ruleFourIn ),
      ruleFive_( ruleFiveIn ),
      ruleSix_( ruleSizIn ),
      ruleSeven_( ruleSevenIn )
{}

AndRule::~AndRule( void )
{
    delete ruleOne_;
    delete ruleTwo_;
    if( NULL != ruleThree_ )
    {
        delete ruleThree_;
    }
    if( NULL != ruleFour_ )
    {
        delete ruleFour_;
    }
    if( NULL != ruleFive_ )
    {
        delete ruleFive_;
    }
    if( NULL != ruleSix_ )
    {
        delete ruleSix_;
    }
    if( NULL != ruleSeven_ )
    {
        delete ruleSeven_;
    }
}

bool AndRule::check( const LogEntry *entry )
{
    return ruleOne_->check( entry )
           && ruleTwo_->check( entry )
           && ( NULL == ruleThree_ || ruleThree_->check( entry ) )
           && ( NULL == ruleFour_ || ruleFour_->check( entry ) )
           && ( NULL == ruleFive_ || ruleFive_->check( entry ) )
           && ( NULL == ruleSix_ || ruleSix_->check( entry ) )
           && ( NULL == ruleSeven_ || ruleSeven_->check( entry ) );
}

Str AndRule::toString( void )
{
    return "(" + ruleOne_->toString()
           + ") AND (" + ruleTwo_->toString()
           + ( NULL != ruleThree_ ? ") AND (" + ruleThree_->toString() : "" )
           + ( NULL != ruleFour_ ? ") AND (" + ruleFour_->toString() : "" )
           + ( NULL != ruleFive_ ? ") AND (" + ruleFive_->toString() : "" )
           + ( NULL != ruleSix_ ? ") AND (" + ruleSix_->toString() : "" )
           + ( NULL != ruleSeven_ ? ") AND (" + ruleSeven_->toString() : "" )
           + ")";
}

OrRule::OrRule( Rule *ruleOneIn,
                Rule *ruleTwoIn,
                Rule *ruleThreeIn,
                Rule *ruleFourIn,
                Rule *ruleFiveIn )
    : ruleOne_( ruleOneIn ),
      ruleTwo_( ruleTwoIn ),
      ruleThree_( ruleThreeIn ),
      ruleFour_( ruleFourIn ),
      ruleFive_( ruleFiveIn )
{}

OrRule::~OrRule( void )
{
    delete ruleOne_;
    delete ruleTwo_;
    if( NULL != ruleThree_ )
    {
        delete ruleThree_;
    }
    if( NULL != ruleFour_ )
    {
        delete ruleFour_;
    }
    if( NULL != ruleFive_ )
    {
        delete ruleFive_;
    }
}

bool OrRule::check( const LogEntry *entry )
{
    return ruleOne_->check( entry )
           || ruleTwo_->check( entry )
           || ( NULL != ruleThree_ && ruleThree_->check( entry ) )
           || ( NULL != ruleFour_ && ruleFour_->check( entry ) )
           || ( NULL != ruleFive_ && ruleFive_->check( entry ) );
}

Str OrRule::toString( void )
{
    return Str( "(" ) + ruleOne_->toString()
           + ") OR (" + ruleTwo_->toString()
           + ( NULL != ruleThree_ ? ") OR (" + ruleThree_->toString() : "" )
           + ( NULL != ruleFour_ ? ") OR (" + ruleFour_->toString() : "" )
           + ( NULL != ruleFive_ ? ") OR (" + ruleFive_->toString() : "" )
           + ")";
}

NotRule::NotRule( Rule *ruleIn )
    : rule_( ruleIn )
{}


NotRule::~NotRule( void )
{
    delete rule_;
}

bool NotRule::check( const LogEntry *entry )
{
    return ! rule_->check( entry );
}

Str NotRule::toString( void )
{
    return Str( "NOT(" ) + rule_->toString() + ")";
}

TypeRule::TypeRule( LogEntry::Type typeIn )
    : type_( typeIn )
{}

TypeRule::~TypeRule( void )
{}

bool TypeRule::check( const LogEntry *entry )
{
    return entry->getType() == type_;
}

Str TypeRule::toString( void )
{
    return Str( "type=" ) + LogEntry::TypeToString( type_ );
}

EventTypeRule::EventTypeRule( EventEntry::EventType eventIn )
    : eventType_( eventIn )
{}

EventTypeRule::~EventTypeRule( void )
{}

bool EventTypeRule::check( const LogEntry *entry )
{
    if( entry->getType() == LogEntry::EVENT_LOG_ENTRY )
    {
        const EventEntry* eventEntry = static_cast<const EventEntry*>( entry );
        return eventType_ == eventEntry->getEventType();
    }
    return false;
}

Str EventTypeRule::toString( void )
{
    return Str( "eventType=" ) + EventEntry::EventTypeToString( eventType_ );
}

ServiceTypeRule::ServiceTypeRule( Service::ServiceType serviceType )
    : serviceType_( serviceType )
{}

ServiceTypeRule::~ServiceTypeRule( void )
{}

bool ServiceTypeRule::check( const LogEntry *entry )
{
    return entry->getServiceType() == serviceType_;
}

Str ServiceTypeRule::toString( void )
{
    return Str( "serviceType=" ) + Service::ServiceType2Str( serviceType_ );
}

SyslogSeverityRule::SyslogSeverityRule( Syslog::Severity sev, bool orGreater )
    : severity_( sev ),
      orGreater_( orGreater )
{}

SyslogSeverityRule::~SyslogSeverityRule( void )
{}

bool SyslogSeverityRule::check( const LogEntry *entry )
{
    if( entry->getType() == LogEntry::SYSLOG_LOG_ENTRY )
    {
        const SyslogEntry* syslogEntry = static_cast<const SyslogEntry*>( entry );
        switch( severity_ )
        {
        case Syslog::NONE:
            return false;
        case Syslog::DEBUG:
        case Syslog::INFO:
        case Syslog::ERROR:
        case Syslog::IMPORTANT:
            return  orGreater_ ? syslogEntry->getSeverity() >= severity_ : syslogEntry->getSeverity() == severity_;
        case Syslog::FAULT:
            return  orGreater_ ? syslogEntry->getSeverity() >= Syslog::CRITICAL : syslogEntry->getSeverity() == severity_;
        case Syslog::CRITICAL:
            return  syslogEntry->getSeverity() == Syslog::CRITICAL;
        }
    }
    return false;
}

Str SyslogSeverityRule::toString( void )
{
    return Str( "severity=" ) + Syslog::SeverityToString( severity_ );
}

SyslogStartRule::SyslogStartRule( const Str& start )
    : start_( start )
{}

SyslogStartRule::~SyslogStartRule( void )
{}

bool SyslogStartRule::check( const LogEntry *entry )
{
    if( entry->getType() == LogEntry::SYSLOG_LOG_ENTRY )
    {
        const SyslogEntry* syslogEntry = static_cast<const SyslogEntry*>( entry );
        return syslogEntry->getMessage().startsWith( start_ );
    }
    return false;
}

Str SyslogStartRule::toString( void )
{
    return Str( "start=" ) + start_;
}

DataWriteRule::DataWriteRule( bool dataWrite )
    : dataWrite_( dataWrite )
{}

DataWriteRule::~DataWriteRule( void )
{}

bool DataWriteRule::check( const LogEntry *entry )
{
    if( entry->getType() == LogEntry::DATA_LOG_ENTRY )
    {
        const DataEntry* dataEntry = static_cast<const DataEntry*>( entry );
        return dataEntry->isDataWrite() == dataWrite_;
    }
    return false;
}

Str DataWriteRule::toString( void )
{
    return Str( "dataWrite=" ) + ( dataWrite_ ? "true" : "false" );
}

DataNameRule::DataNameRule( const Str& dataName,  bool dataWrite )
    : DataWriteRule( dataWrite ),
      dataName_( dataName ),
      code_( ElementURI::NO_CODE ),
      slateElementURICount_( 0 )
{}

DataNameRule::~DataNameRule( void )
{}

bool DataNameRule::check( const LogEntry *entry )
{
    if( code_ == ElementURI::NO_CODE && slateElementURICount_ != Slate::GetElementURICount() )
    {
        slateElementURICount_ = Slate::GetElementURICount();
        ElementURI* uri = Slate::FindElementURI( dataName_ );
        if( NULL != uri )
        {
            code_ = uri->getCode();
        }
    }
    if( code_ == ElementURI::NO_CODE )
    {
        return false;
    }
    if( !DataWriteRule::check( entry ) )
    {
        return false;
    }
    const DataEntry* dataEntry = static_cast<const DataEntry*>( entry );
    DataAccess* dataAccess = dataEntry->getDataAccess();

    bool retVal = dataAccess->getElementCode() == code_ ||
                  ( dataEntry->isBest() && dataAccess->getUniversalCode() == code_ );
    return retVal;
}

Str DataNameRule::toString( void )
{
    return "dataName=" + dataName_ + ", " + DataWriteRule::toString();
}

