/** \file
 *
 *  Contains the various /ref logging Rule class definitions 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
 *
 */

#ifndef LOGGERRULES_H_
#define LOGGERRULES_H_

#include "DataEntry.h"
#include "EventEntry.h"
#include "LogWriter.h"
#include "SyslogEntry.h"

/**
 *  Abstract base class for classes that are used by LogEngine to determine
 *  which LogWriter(s) to use for each LogEntry as they are popped off the
 *  LogQueue.
 *
 *  \ingroup logging
 */
class Rule
{
public:
    /// Destructor
    virtual ~Rule( void )
    {}
    ;

    /// Does this rule match this LogEntry
    virtual bool check( const LogEntry *entry ) = 0;

    /// Serialize this Rule to a Str
    virtual Str toString( void ) = 0;

    virtual void activate();

    virtual void deactivate();

    virtual bool isActive();

protected:

    /// Protected constructor for pure virtual class.
    Rule( void );

private:
    // Note that the copy constructor below is private and not given a body.
    // Any attempt to call it will return a compiler error.
    Rule( const Rule& old ); // disallow copy constructor

    bool active_;

};

/**
 *  A logging Rule implementing a logical AND() between two other rules.
 *
 *  \ingroup logging
 */
class AndRule : public Rule
{
public:
    AndRule( Rule *ruleOneIn,
             Rule *ruleTwoIn,
             Rule *ruleThreeIn = NULL,
             Rule *ruleFourIn = NULL,
             Rule *ruleFiveIn = NULL,
             Rule *ruleSizIn = NULL,
             Rule *ruleSevenIn = NULL );

    virtual ~AndRule( void );

    virtual bool check( const LogEntry *entry );

    virtual Str toString( void );

private:
    // Note that the copy constructor below is private and not given a body.
    // Any attempt to call it will return a compiler error.
    AndRule( const AndRule& old ); // disallow copy constructor

    Rule *ruleOne_, *ruleTwo_, *ruleThree_, *ruleFour_, *ruleFive_, *ruleSix_, *ruleSeven_;
};

/**
 *  A logging Rule implementing a logical OR() between two other rules.
 *
 *  \ingroup logging
 */
class OrRule : public Rule
{
public:
    OrRule( Rule *ruleOneIn,
            Rule *ruleTwoIn,
            Rule *ruleThreeIn = NULL,
            Rule *ruleFourIn = NULL,
            Rule *ruleFiveIn = NULL );

    virtual ~OrRule( void );

    virtual bool check( const LogEntry *entry );

    virtual Str toString( void );

private:
    // Note that the copy constructor below is private and not given a body.
    // Any attempt to call it will return a compiler error.
    OrRule( const OrRule& old ); // disallow copy constructor

    Rule *ruleOne_, *ruleTwo_, *ruleThree_, *ruleFour_, *ruleFive_ ;
};

/**
 *  A logging Rule implementing a logical NOT() of another rules.
 *
 *  \ingroup logging
 */
class NotRule : public Rule
{
public:
    NotRule( Rule *ruleIn );

    virtual ~NotRule( void );

    virtual bool check( const LogEntry *entry );

    virtual Str toString( void );

private:
    // Note that the copy constructor below is private and not given a body.
    // Any attempt to call it will return a compiler error.
    NotRule( const NotRule& old ); // disallow copy constructor

    Rule *rule_;
};

/**
 *  A logging Rule which matches against a given LogEntry::Type.
 *
 *  \ingroup logging
 */
class TypeRule : public Rule
{
public:
    TypeRule( LogEntry::Type typeIn );

    virtual ~TypeRule( void );

    virtual bool check( const LogEntry *entry );

    virtual Str toString( void );

private:

    /// The LogEntry type we're looking for
    LogEntry::Type type_;
};

/**
 *  A Logger Rule which matches against a given LogEvent::EventEntry.
 *  Multiple EventEntry::Action values may be mathematically added together
 *
 *  It is not necessary to use a TypeRule with this rule, as this rule
 *  only accepts EventEntry items.
 *
 *  \ingroup logging
 */
class EventTypeRule : public Rule
{
public:
    EventTypeRule( EventEntry::EventType eventIn );

    virtual ~EventTypeRule( void );

    virtual bool check( const LogEntry *entry );

    virtual Str toString( void );

private:

    /// The LogEntry type we're looking for
    EventEntry::EventType eventType_;
};

/**
 *  A Logger Rule which matches against a given ServiceType
 *  If the LogEntry's ServiceType equals the specified severity
 *  the the ServiceTypeRule return true.
 *
 *  \ingroup logging
 */
class ServiceTypeRule : public Rule
{
public:
    ServiceTypeRule( Service::ServiceType serviceType );

    virtual ~ServiceTypeRule( void );

    virtual bool check( const LogEntry *entry );

    virtual Str toString( void );

private:

    /// The ServiceType type we're looking for
    Service::ServiceType serviceType_;
};

/**
 *  A Logger Rule which matches against a given SyslogSeverity
 *  If the SyslogEntry's severity equals or exceeds the specified severity
 *  the the SyslogSeverityRule return true.
 *
 *  It is not necessary to use a TypeRule with this rule, as this rule
 *  only accepts SyslogEntry items.
 *
 *  \ingroup logging
 */
class SyslogSeverityRule : public Rule
{
public:
    SyslogSeverityRule( Syslog::Severity sev, bool orGreater = true );

    virtual ~SyslogSeverityRule( void );

    virtual bool check( const LogEntry *entry );

    virtual Str toString( void );

private:

    /// The LogEntry type we're looking for
    Syslog::Severity severity_;
    bool orGreater_;
};

/**
 *  A Logger Rule which matches against the starting text of a SyslogEntry
 *
 *  It is not necessary to use a TypeRule with this rule, as this rule
 *  only accepts SyslogEntry items.
 *
 *  \ingroup logging
 */
class SyslogStartRule : public Rule
{
public:
    SyslogStartRule( const Str& start );

    virtual ~SyslogStartRule( void );

    virtual bool check( const LogEntry *entry );

    virtual Str toString( void );

private:

    /// The SyslogEntry start text we are looking for
    Str start_;
};

/**
 *  A Logger Rule which specifies either data writes or data reads.
 *  If the DataEntry corresponds to a write event and the specified dataWrite
 *  entry was true, then DataWriteRule returns true.  Likewise, if the
 *  DataEntry corresponds to a read event and the specified dataWrite
 *  entry was false, then DataWriteRule returns true.  Otherwise, DataWriteRule
 *  returns false.
 *
 *  It is not necessary to use a TypeRule with this rule, as this rule
 *  only accepts DataEntry items.
 *
 *  \ingroup logging
 */
///
class DataWriteRule : public Rule
{
public:
    DataWriteRule( bool dataWrite );

    virtual ~DataWriteRule( void );

    virtual bool check( const LogEntry *entry );

    virtual Str toString( void );

private:

    /// The LogEntry type we're looking for
    bool dataWrite_;
};

/**
 *  A Logger Rule which specifies either data writes or data reads using
 *  an element with an ElementURI matching the supplied name
 *  If dataName should be deleted (by delete[]) by the destructor, then
 *  delteName should be true;
 *  If the DataEntry corresponds to a write event and the specified dataWrite
 *  entry was true, then DataWriteRule returns true.  Likewise, if the
 *  DataEntry corresponds to a read event and the specified dataWrite
 *  entry was false, then DataWriteRule returns true.  Otherwise, DataWriteRule
 *  returns false.
 *
 *  It is not necessary to use a TypeRule with this rule, as this rule
 *  only accepts DataEntry items.
 *
 *  \ingroup logging
 */
///
class DataNameRule : public DataWriteRule
{
public:
    DataNameRule( const Str& dataName, bool dataWrite = true );

    virtual ~DataNameRule( void );

    virtual bool check( const LogEntry *entry );

    virtual Str toString( void );

private:

    const Str dataName_;
    unsigned short code_;
    unsigned int slateElementURICount_;
};
#endif /*LOGGERRULES_H_*/
