// snfCFGmgr.hpp
// Copyright (C) 2006 - 2009 Arm Research Labs, LLC
// See www.armresearch.com for the copyright terms.
//
// SNF Configuration manager.

//// Begin include only once

#ifndef included_snfCFGmgr_hpp
#define included_snfCFGmgr_hpp

#include "GBUdb.hpp"
#include "snf_HeaderFinder.hpp"

#include "configuration.hpp"
#include "threading.hpp"
#include <string>
#include <set>

using namespace std;

const unsigned long int HeaderDirectiveBypass = 0x00000001;                     // Bypass hd rule flag.
const unsigned long int HeaderDirectiveWhite = 0x00000002;                      // White hd rule flag.
const unsigned long int HeaderDirectiveDrillDown = 0x00000004;                  // DrillDown rule flag.
const unsigned long int HeaderDirectiveSource = 0x00000008;                     // Source rule flag.
const unsigned long int HeaderDirectiveContext = 0x80000000;                    // Context activation flag.

class HeaderDirectiveHandler : public Configurator {                            // Handle inputs to header directives.
  public:

    HeaderDirectiveSet HeaderDirectives;                                        // Managed set of Header Directives.

    void operator()(ConfigurationElement& E, ConfigurationData& D) {            // The configurator call adds the Input.

        if(HeaderDirectiveContext == ContextInput.Directive) {                  // If a context has been established
            ContextInput.Context = HeaderDirectives.size() + 1;                 // then setup the context ID and
            DirectiveInput.Context = ContextInput.Context;                      // share it with the input.
            HeaderDirectives.insert(ContextInput);                              // Insert the context tester and
            ContextInput.clear();                                               // then clear it for future use.
        }

        HeaderDirectives.insert(DirectiveInput);                                // Insert the directive and then
        DirectiveInput.clear();                                                 // clear the input for future use.
    }

    HeaderFinderPattern ContextInput;                                           // The context can be set externally.
    HeaderFinderPattern DirectiveInput;                                         // The Input can be set externally.

    void reset() {                                                              // Reset the handler like this:
        HeaderDirectives.clear();                                               // Clear the header directives.
        ContextInput.clear();                                                   // Clear the Context Input.
        DirectiveInput.clear();                                                 // Clear the Directive Input.
    }

};

class HeaderDirectiveInitializer : public Configurator {                        // Initializes Header Directives.
  private:

    HeaderDirectiveHandler* MyTarget;                                           // Needs to know it's target.

  public:

    HeaderDirectiveInitializer() : MyTarget(NULL) {}                            // Constructor doesn't know it's target yet.

    void setTarget(HeaderDirectiveHandler& H) { MyTarget = &H; }                // We have a way to set the target though ;-)

    void operator()(ConfigurationElement& E, ConfigurationData& D) {            // The configurator() function goes to the
        if(NULL!=MyTarget) {                                                    // target (if it's set) and pushes the
            MyTarget->reset();                                                  // reset button (empties the set).
        }
    }
};

class HeaderDirectiveWhiteHeaderInitializer : public Configurator {             // Initializes White Header Directives.
  private:

    HeaderDirectiveHandler* MyTarget;                                           // Needs to know it's target.

  public:

    HeaderDirectiveWhiteHeaderInitializer() : MyTarget(NULL) {}                 // Constructor doesn't know it's target yet.

    void setTarget(HeaderDirectiveHandler& H) { MyTarget = &H; }                // We have a way to set the target though ;-)

    void operator()(ConfigurationElement& E, ConfigurationData& D) {            // The configurator() function goes to the
        if(NULL!=MyTarget) {                                                    // target (if it's set) and sets it up
            MyTarget->ContextInput.clear();                                     // for a white header directive.
            MyTarget->DirectiveInput.clear();
            MyTarget->DirectiveInput.Directive = HeaderDirectiveWhite;
        }
    }
};

class HeaderDirectiveBypassHeaderInitializer : public Configurator {            // Initializes Bypass Header Directives.
  private:

    HeaderDirectiveHandler* MyTarget;                                           // Needs to know it's target.

  public:

    HeaderDirectiveBypassHeaderInitializer() : MyTarget(NULL) {}                // Constructor doesn't know it's target yet.

    void setTarget(HeaderDirectiveHandler& H) { MyTarget = &H; }                // We have a way to set the target though ;-)

    void operator()(ConfigurationElement& E, ConfigurationData& D) {            // The configurator() function goes to the
        if(NULL!=MyTarget) {                                                    // target (if it's set) and sets it up
            MyTarget->ContextInput.clear();                                     // for a bypass header directive.
            MyTarget->DirectiveInput.clear();
            MyTarget->DirectiveInput.Directive = HeaderDirectiveBypass;
        }
    }
};

class HeaderDirectiveDrilldownInitializer : public Configurator {               // Initializes Drilldown Header Directives.
  private:

    HeaderDirectiveHandler* MyTarget;                                           // Needs to know it's target.

  public:

    HeaderDirectiveDrilldownInitializer() : MyTarget(NULL) {}                   // Constructor doesn't know it's target yet.

    void setTarget(HeaderDirectiveHandler& H) { MyTarget = &H; }                // We have a way to set the target though ;-)

    void operator()(ConfigurationElement& E, ConfigurationData& D) {            // The configurator() function goes to the
        if(NULL!=MyTarget) {                                                    // target (if it's set) and sets it up for
            MyTarget->ContextInput.clear();                                     // a drilldown header directive.
            MyTarget->DirectiveInput.clear();
            MyTarget->DirectiveInput.Directive = HeaderDirectiveDrillDown;
            MyTarget->DirectiveInput.Header = "Received:";
        }
    }
};

class HeaderDirectiveSourceHeaderInitializer : public Configurator {            // Initializes Source Header Directives.
  private:

    HeaderDirectiveHandler* MyTarget;                                           // Needs to know it's target.

  public:

    HeaderDirectiveSourceHeaderInitializer() : MyTarget(NULL) {}                // Constructor doesn't know it's target yet.

    void setTarget(HeaderDirectiveHandler& H) { MyTarget = &H; }                // We have a way to set the target though ;-)

    void operator()(ConfigurationElement& E, ConfigurationData& D) {            // The configurator() function goes to the
        if(NULL!=MyTarget) {                                                    // target (if it's set) and sets it up
            MyTarget->ContextInput.clear();                                     // for a context sensitive source header
            MyTarget->DirectiveInput.clear();                                   // directive. Activation context as well
            MyTarget->ContextInput.Directive = HeaderDirectiveContext;          // as source header data.
            MyTarget->ContextInput.Header = "Received:";
            MyTarget->DirectiveInput.Directive = HeaderDirectiveSource;
        }
    }
};

class RangePoint {                                                              // Range point x:Probability, y:Confidence
  public:

    RangePoint() :                                                              // The simple constructor sets all to zero.
      Confidence(0.0),
      Probability(0.0) {}

    RangePoint(double C, double P) :                                            // This constructor sets the values.
      Confidence(C),
      Probability(P) {}

    double Probability;                                                         // Probability and Confidence are
    double Confidence;                                                          // freely accessible.

    bool operator<(const RangePoint& right) const {                             // Comparison of RangePoint objects depends
        return (Confidence < right.Confidence);                                 // on the Confidence value. This is because
    }                                                                           // Confidence is used as a "key" in the set.
    bool operator>(const RangePoint& right) const {
        return (Confidence > right.Confidence);
    }
    bool operator==(const RangePoint& right) const {
        return (Confidence == right.Confidence);
    }
    bool operator<=(const RangePoint& right) const {
        return (Confidence <= right.Confidence);
    }
    bool operator>=(const RangePoint& right) const {
        return (Confidence >= right.Confidence);
    }
};

class RangeHandler : public Configurator {                                      // The handler adds edgepoints and holds and
  public:                                                                       // tests the set that defines the region.

    void operator()(ConfigurationElement& E, ConfigurationData& D) {            // The () operator adds EdgeInput to the list.
        EdgeMap.insert(EdgeInput);
    }

    bool On_Off;                                                                // Ranges can be turned on and off.
    int Symbol;                                                                 // They have a symbol assigned to them.
    int Priority;                                                               // They have an evaluation priority.

    RangePoint EdgeInput;                                                       // This EdgePoint is set, and added using ().
    set<RangePoint> EdgeMap;                                                    // This contains the set of EdgePoints.

    bool isInWhite(RangePoint& x);                                              // True if x is inside the -P of the EdgeMap.
    bool isInBlack(RangePoint& x);                                              // True if x is inside the +P of the EdgeMap.

    void reset() { EdgeMap.clear(); }                                           // When we reset - we empty the EdgeMap.

};

class RangeInitializer : public Configurator {                                  // The RangeInitializer Configurator.
  private:

    RangeHandler* MyTarget;                                                     // Needs to know it's target.

  public:

    RangeInitializer() : MyTarget(NULL) {}                                      // Constructor doesn't know it's target yet.

    void setTarget(RangeHandler& H) { MyTarget = &H; }                          // We have a way to set the target though ;-)

    void operator()(ConfigurationElement& E, ConfigurationData& D) {            // The configurator() function goes to the
        if(NULL!=MyTarget) {                                                    // target (if it's set) and pushes the
            MyTarget->reset();                                                  // reset button.
        }
    }
};

class IntegerSetHandler : public Configurator {                                 // Integer set handler for rule panics.
  public:
    void operator()(ConfigurationElement& E, ConfigurationData& D) {            // The operator() inserts IntegerInput
        IntegerSet.insert(IntegerInput);                                        // if it's not already a member.
    }

    int IntegerInput;                                                           // The input port.
    set<int> IntegerSet;                                                        // The set itself.

    bool isListed(int x);                                                       // How to check if an int is listed.

    void reset() { IntegerSet.clear(); }                                        // How to reset (clear) the list.
};

class IntegerSetInitializer : public Configurator {                             // The initializer resets the set.
  private:

    IntegerSetHandler* MyTarget;                                                // It needs to know which set to init.

  public:

    IntegerSetInitializer() : MyTarget(NULL) {}                                 // Start off not knowing where to go.

    void setTarget(IntegerSetHandler& H) { MyTarget = &H; }                     // Set a pointer to the handler.

    void operator()(ConfigurationElement& E, ConfigurationData& D) {            // The operator() does the trick.
        if(NULL!=MyTarget) {
            MyTarget->reset();
        }
    }
};

class XHDRSymbol {                                                              // XHeader associated with a Symbol
  public:
    int Symbol;                                                                 // The integer symbol.
    string Header;                                                              // The header to associate.
    XHDRSymbol(int FreshSymbol, string FreshHeader) :                           // Creating the object requires both.
      Symbol(FreshSymbol),
      Header(FreshHeader) {}

    bool operator<(const XHDRSymbol& right) const {                             // To live in a set we must have a <
        return (Symbol < right.Symbol);                                         // operator. Only the symbol matters
    }                                                                           // in this case.
};

class XHDRSymbolsHandler : public Configurator {                                // XHDRSymbol hander.
  public:
    set<XHDRSymbol> SymbolHeaders;                                              // Carries a set of Symbol Headers.

    void reset() { SymbolHeaders.clear(); }                                     // Is reset by clearing the set.

    string HeaderForSymbol(int S) {                                             // Can return a Header for symbol.
        string MatchingHeader = "";                                             // Starting with an empty string,
        set<XHDRSymbol>::iterator iS = SymbolHeaders.find(XHDRSymbol(S,""));    // we look up the symbol and
        if(SymbolHeaders.end() != iS) {                                         // if we find it then we will
            MatchingHeader = (*iS).Header;                                      // return the matching header
        }                                                                       // string. If not then we return
        return MatchingHeader;                                                  // the empty string.
    }                                                                           // Coded in-line on purpose.

    bool OnOff;                                                                 // Input OnOff value.
    int Symbol;                                                                 // Input Symbol value.
    string Header;                                                              // Input Header value.

    void operator()(ConfigurationElement& E, ConfigurationData& D) {            // The operator() inserts an XHDRSymbol
        if(OnOff) {                                                             // if the header entry is turned on and
          SymbolHeaders.insert(XHDRSymbol(Symbol, Header));                     // if it's not already a member.
        }
    }
};

class XHDRSymbolsInitializer : public Configurator {                            // The XHDRSymbols initializer.
  private:

    XHDRSymbolsHandler* MyTarget;                                               // It needs to know which set to init.

  public:

    XHDRSymbolsInitializer() : MyTarget(NULL) {}                                // Start off not knowing where to go.

    void setTarget(XHDRSymbolsHandler& H) { MyTarget = &H; }                    // Set a pointer to the handler.

    void operator()(ConfigurationElement& E, ConfigurationData& D) {            // The operator() does the trick.
        if(NULL!=MyTarget) {
            MyTarget->reset();
        }
    }
};

enum snfIPRange {                                                               // IP action ranges
    Unknown,                                                                    // Unknown - not defined.
    White,                                                                      // This is a good guy.
    Normal,                                                                     // Benefit of the doubt.
    New,                                                                        // It is new to us.
    Caution,                                                                    // This is suspicious.
    Black,                                                                      // This is bad.
    Truncate                                                                    // Don't even bother looking.
};

const int ScanLogMatches_All = 2;                                               // Include all matches.
const int ScanLogMatches_Unique = 1;                                            // Include 1 match of each rule.
const int ScanLogMatches_None = 0;                                              // Include only the final result.

const int LogOutputMode_None = 0;                                               // No output (don't process).
const int LogOutputMode_API = 1;                                                // Make available to API.
const int LogOutputMode_File = 2;                                               // Output to msgfile.xhdr.
const int LogOutputMode_Inject = 3;                                             // Inject into msgfile.

class snfCFGData {                                                              // Object that stores our config data.
  private:

    ConfigurationElement MyCFGReader;                                           // This is how we read our cfg data.

  public:

    snfCFGData();                                                               // Constructor handled in .cpp

    void initializeFromFile(const char* FileName);                              // Initialize from the provided file.

    int Generation;                                                             // Generation tag.

    // Here are the derived data elements...

    string ConfigFilePath;                                                      // Configuration file path
    string RuleFilePath;                                                        // Rulebase file path
    string SecurityKey;                                                         // Security key for rulebase

    // Here are the basic data elements...

    string node_identity;
    string node_licenseid;
    string node_authentication;

    //// paths

    string paths_workspace_path;
    string paths_rulebase_path;
    string paths_log_path;

    //// logging

    bool Logs_Rotation_LocalTime_OnOff;

    bool Status_SecondReport_Log_OnOff;
    bool Status_SecondReport_Append_OnOff;
    bool Status_MinuteReport_Log_OnOff;
    bool Status_MinuteReport_Append_OnOff;
    bool Status_HourReport_Log_OnOff;
    bool Status_HourReport_Append_OnOff;

    bool Scan_Identifier_Force_Message_Id;

    int Scan_Classic_Mode;
    bool Scan_Classic_Rotate;
    int Scan_Classic_Matches;

    int Scan_XML_Mode;
    bool Scan_XML_Rotate;
    int Scan_XML_Matches;
    bool Scan_XML_Performance;
    bool Scan_XML_GBUdb;

    //// xheaders

    int XHDROutput_Mode;

    bool XHDRVersion_OnOff;
    string XHDRVersion_Header;

    bool XHDRLicense_OnOff;
    string XHDRLicense_Header;

    bool XHDRRulebase_OnOff;
    string XHDRRulebase_Header;

    bool XHDRIdentifier_OnOff;
    string XHDRIdentifier_Header;

    bool XHDRGBUdb_OnOff;
    string XHDRGBUdb_Header;

    bool XHDRResult_OnOff;
    string XHDRResult_Header;

    bool XHDRMatches_OnOff;
    string XHDRMatches_Header;

    bool XHDRBlack_OnOff;
    string XHDRBlack_Header;

    bool XHDRWhite_OnOff;
    string XHDRWhite_Header;

    bool XHDRClean_OnOff;
    string XHDRClean_Header;

    XHDRSymbolsHandler XHDRSymbolHeaders;
    XHDRSymbolsInitializer XHDRSymbolHeadersInitializer;

    //// platform

    string PlatformElementContents;

    //// network

    int network_sync_secs;
    string network_sync_host;
    int network_sync_port;

    bool update_script_on_off;
    string update_script_call;
    int update_script_guard_time;

    //// gbudb

    int gbudb_database_condense_minimum_seconds_between;
    bool gbudb_database_condense_time_trigger_on_off;
    int gbudb_database_condense_time_trigger_seconds;
    bool gbudb_database_condense_posts_trigger_on_off;
    int gbudb_database_condense_posts_trigger_posts;
    bool gbudb_database_condense_records_trigger_on_off;
    int gbudb_database_condense_records_trigger_records;
    bool gbudb_database_condense_size_trigger_on_off;
    int gbudb_database_condense_size_trigger_megabytes;

    bool gbudb_database_checkpoint_on_off;
    int gbudb_database_checkpoint_secs;

    RangeHandler WhiteRangeHandler;
    RangeInitializer WhiteRangeInitializer;

    bool gbudb_regions_white_panic_on_off;
    int gbudb_regions_white_panic_rule_range;

    RangeHandler BlackRangeHandler;
    RangeInitializer BlackRangeInitializer;

    bool gbudb_regions_black_sample_on_off;
    double gbudb_regions_black_sample_probability;
    int gbudb_regions_black_sample_grab_one_in;
    bool gbudb_regions_black_sample_passthrough;
    int gbudb_regions_black_sample_passthrough_symbol;
    int gbudb_regions_black_truncate_symbol;

    bool gbudb_regions_black_truncate_on_off;
    double gbudb_regions_black_truncate_probability;
    int gbudb_regions_black_truncate_peek_one_in;

    RangeHandler CautionRangeHandler;
    RangeInitializer CautionRangeInitializer;

    snfIPRange RangeEvaluation(GBUdbRecord& R);                                 // Returns the range for a GBUdbRecord.
    snfIPRange RangeEvaluation(RangePoint& p);                                  // Returns the range for a RangePoint.

    HeaderDirectiveHandler HeaderDirectivesHandler;                             //** Handles header directives.
    HeaderDirectiveInitializer HeaderDirectivesInitializer;                     //** Initializes header directives set.
    HeaderDirectiveSourceHeaderInitializer HDSourceHeaderInitializer;           //**** For source header directives.
    HeaderDirectiveDrilldownInitializer HDDrilldownInitializer;                 //**** For drilldown header directives.
    HeaderDirectiveBypassHeaderInitializer HDBypassHeaderInitializer;           //**** For bypass header directives.
    HeaderDirectiveWhiteHeaderInitializer HDWhiteHeaderInitializer;             //**** For white header directives.

    IntegerSetHandler TrainingBypassRuleHandler;                                // Rules to NOT train GBUdb with source.
    IntegerSetInitializer TrainingBypassRuleInitializer;

    IntegerSetHandler TrainingWhiteRuleHandler;                                 // Rules to train GBUdb as white source.
    IntegerSetInitializer TrainingWhiteRuleInitializer;

    bool GBUdbTrainingOn_Off;                                                   // True when GBUdb training is allowed.

    IntegerSetHandler RulePanicHandler;
    IntegerSetInitializer RulePanicInitializer;

    bool XCI_OnOff;                                                             // XML Command Interface ON or OFF.
    int XCI_Port;                                                               // XML Command Interface Port number.

    bool MessageFileTypeCGP_on_off;                                             // True for scanning communigate msgs.

};

class snfCFGmgr {                                                               // Object that manages our config data.

  private:

    Mutex myMutex;                                                              // Serialize control during updates.

    snfCFGData A;                                                               // This is where we store one copy.
    snfCFGData B;                                                               // This is where we store the other.

    volatile bool AisActive;                                                    // This tells us which is active.

    void swapCFGData();                                                         // This swaps the active dataset.
    snfCFGData& ActiveData();                                                   // This returns the active dataset.
    snfCFGData& InactiveData();                                                 // This returns the inactive dataset.

    string InitFileName;                                                        // Initilization parameters are reused
    string InitLicenseId;                                                       // any time load() is called.
    string InitAuthentication;

    string ConfigurationPath;                                                   // Path to active configuration file.

  public:

    snfCFGmgr();                                                                // Constructor - to get things right

    void initialize(                                                            // In order to initialize we need to
      const char* FileName,                                                     // collect a path to our config or .snf
      const char* LicenseId,                                                    // our license id and our
      const char* Authentication                                                // authentication.
    );

    class LoadFailure {};                                                       // What we throw if load fails.

    void load();                                                                // Load the configuration data.

    //// Access methods for config data...

    string RuleFilePath();                                                      // Rulebase file path
    string SecurityKey();                                                       // Security key for rulebase

    snfCFGData* ActiveConfiguration();                                          // Pointer to active configuration

};

#include "snfCFGmgr.inline.hpp"

#endif
// End include only once
