#ifndef INCLUDED_OPTIONS_
#define INCLUDED_OPTIONS_

#include <memory>
#include <iosfwd>
#include <ctime>
#include <string>
#include <unordered_set>

#include <bobcat/argconfig>
#include <bobcat/syslogstream>      // for the enums

#include "../iptypes/iptypes.h"

extern std::ostream g_debug;

struct Options: public IP_Types
{
    enum Time
    {
        RAW,
        UTC,
        LT
    };

    enum ExitStatus
    {
        OK,
        FAILED,
        TERM_SIGNAL,
    };
    
    enum Mode               // working mode: conntrack, pcap, or tcpdump
    {
        CONNTRACK,          // when modified: update producer/data.cc
        DEVICE,
        TCPDUMP,
    };

    enum 
    {
        TTL = 60,           // default TTL in seconds
        TTL_TCP = 3000      // TTL for TCP
    };

    private:
        FBB::ArgConfig &d_arg;
  
        bool d_byteCounts;  
        bool d_daemon;
        bool d_debug;
        bool d_rotate;
        bool d_rotateData;
        bool d_showDst;
        bool d_showVia;
        bool d_stdout;
        bool d_terminate;
        
        Mode d_mode;

        size_t d_IPheaderSize = 0;
        size_t d_verbose;
        size_t d_conntrackRestart = 10;

        size_t d_rotateFreq = 0;        // rotate non-syslog logs
        size_t d_rotateFactor = 1;      // after spec * factor minutes
        std::string d_rotateTimeSpec;   // e.g., ' minutes'

        size_t d_nRotations = 0;        // rotate #files
        size_t d_rotationInterval;      // minimum interval in secs. between 
                                        // log-file rotations

        time_t d_ttl = TTL;
        time_t d_ttlTCP = TTL_TCP;
        
        std::unordered_map<std::string, Time>::const_iterator d_time;
    
        std::string d_conntrackCommand;
        std::string d_conntrackDevice;
        std::string d_configPath;
        std::string d_syslogTag;
        std::string d_PIDfile;
        std::string d_timeSpecError;
        std::string d_syslogPriorityError;
        std::string d_syslogFacilityError;
        std::string d_log;
        std::string d_logData;

        std::unordered_set<Protocol> d_protocols;
    
        std::unordered_map<std::string, FBB::Facility>::const_iterator 
                                                            d_syslogFacility;
        std::unordered_map<std::string, FBB::Priority>::const_iterator 
                                                            d_syslogPriority;
            // default values:

        static char const s_defaultConfigPath[];
        static char const s_defaultConntrackCommand[];
        static char const s_defaultConntrackDevice[];
        static char const s_defaultConntrackArgs[];
        static char const s_defaultSyslogIdent[];
        static char const s_defaultSyslogFacility[];
        static char const s_defaultSyslogPriority[];
        static char const s_defaultPIDfile[];
    
        static std::unordered_map<std:: string, Time> const s_time;
        static std::unordered_map<std::string, FBB::Facility> const 
                                                           s_syslogFacilities;
        static std::unordered_map<std::string, FBB::Priority> const 
                                                           s_syslogPriorities;
        static std::unordered_map<std::string, Protocol> const 
                                                           s_name2protocol;
        static std::unordered_map<Protocol, std::string> const 
                                                           s_protocol2name;

        static std::unique_ptr<Options> s_options;

    public:
        static Options &instance();

        Options(Options const &other) = delete;

        bool daemon() const;
        void foreground();              // undo a default daemon request

        bool realTime() const;          // true if the packets are received
                                        // real-time; when recorded: false.
        bool byteCounts() const;
        bool debug() const;
        bool forwardOption() const;     // requested terminate, rotate(Data) 
        bool showDst() const;
        bool showVia() const;
        bool stdout() const;

        size_t IPheaderSize() const;
        size_t verbose() const;

        size_t rotateFreq() const;          // 0: no log rotation requested
        size_t rotateFactor() const;
        size_t rotationInterval() const;    // seconds, smallest aceptable
                                            // rotation interval
        size_t nRotations() const;
        std::string const &rotateTimeSpec() const;

        time_t ttl() const;
        time_t ttlTCP() const;

        Time time() const;
        std::string const &timeTxt() const;
        Mode mode() const;

        std::string const &configPath() const;
        std::string const &timeSpecError() const;
        std::string const &pidFile() const;
        std::unordered_set<Protocol> const &protocolSet() const;
        bool hasProtocol(std::string const &protoName) const;
        bool hasProtocol(size_t protocol) const;    // arg: a protocol value:
                                                    // IPTypes: ICMP, TCP, UDP
        std::string const &conntrackCommand() const;
        char const *conntrackDevice() const;
        std::string const &syslogTag() const;
        std::string const &log() const;
        std::string const &logData() const;

        FBB::Priority syslogPriority() const;
        FBB::Facility syslogFacility() const;

        std::string const &priority() const;
        std::string const &facility() const;

        std::string syslogPriorityError() const;
        std::string syslogFacilityError() const;

        char const *operator[](size_t idx) const;   // forwards ArgConfig's
        size_t nArgs() const;                       // values.
        std::string const &basename() const;

        size_t  conntrackRestart() const;

        std::string protocolNames() const;

        static std::string const &protocolName(Protocol protocol);
        static char const *defaultConfigPath();
        static char const *defaultConntrackCommand();
        static char const *defaultConntrackArgs();
        static char const *defaultConntrackDevice();
        static char const *defaultSyslogIdent();
        static char const *defaultSyslogFacility();
        static char const *defaultSyslogPriority();
        static char const *defaultPIDfile();

    private:
        Options();

        bool kill() const;
        void openConfig();
        size_t readPid() const;
        bool rotate() const;            // sends SIGHUP
        bool rotateData() const;        // sends SIGSTOP
        void setBoolMembers();
        void setConntrack();
        void setMode();
        void setLogParams();
        void setSyslogFacility();
        void setSyslogPriority();
        void setTimeType(std::string const &time);
        void setTimeSpec();
        void setProtocol();
};

#include "options.f"

#endif
