#ifndef __EPoll_h__
#define __EPoll_h__

#include "Log.h"
#include "Socket.h"
#include "Thread.h"
#include "Session.h"
#include "Command.h"

namespace core {
   
   ///
   /// EPoll
   ///
   /// Manage socket events from the epoll system call.
   /// 
   /// Use this object to establish a socket server using the epoll network structure of Linux.
   ///
   /// Use this object to establish the basis of working with multiple sockets of all sorts
   /// using the epoll capabilities of the Linux platform.
   /// Socket objects can register with BMAEPoll which will establish a communication mechanism
   /// with that socket. 
   /// 
   /// The maximum number of sockets to communicate with is specified on the
   /// start method. 
   ///
   /// Threads are used to establish a read queue for epoll. The desired number of threads (or
   /// queues) is established by a parameter on the start method.
   ///
   
   class EPoll : public Command {
      
    public: 
      
      ///
      /// The constructor for the BMAEPoll object.
      ///
      
      EPoll();
      
      ///
      /// The destructor for the BMAEPoll object.
      ///
      
      ~EPoll();
      
      ///
      /// Use the start() method to initiate the threads and begin epoll queue processing.
      ///
      /// @param numberOfThreads the number of threads to start for processing epoll entries.
      /// @param maxSockets the maximum number of open sockets that epoll will manage.
      ///
      
      bool start(int numberOfThreads, int maxSockets); ///< Start the BMAEPoll processing.
      
      ///
      /// Use the stop() method to initiate the shutdown process for the epoll socket management.
      /// 
      /// A complete shutdown of all managed sockets will be initiated by this method call. 
      ///
      
      bool stop(); ///< Stop and shut down the BMAEPoll processing.
      
      ///
      /// This method returns a true if the stop() method has been called and the epoll system 
      /// is shutting.
      ///
      
      bool isStopping(); ///< Returns a true if the stop command has been requested.
      
      ///
      /// Use registerSocket to add a new socket to the ePoll event watch list. This enables
      /// a new BMASocket object to receive events when data is received as well as to write
      /// data output to the socket. 
      ///
      /// @param socket a pointer to a BMASocket object. 
      /// @return a booelean that indicates the socket was registered or not.
      ///
      
      bool registerSocket(Socket *socket); ///< Register a BMASocket for monitoring by BMAEPoll.
      
      ///
      /// Use this method to remove a socket from receiving events from the epoll system. 
      ///
      
      bool unregisterSocket(Socket *socket); ///< Unregister a BMASocket from monitoring by BMAEPoll. 
      
      ///
      /// Use this method to obtain the current descriptor socket number for the epoll function call.
      ///
      
      int getDescriptor(); ///< Return the descriptor for the ePoll socket.
      
      ///
      /// The maximum number of sockets that can be managed by the epoll system.
      ///
      
      int maxSockets; ///< The maximum number of socket allowed.
      
      ///
      /// Receive the epoll events and dispatch the event to the socket making the request.
      ///
      
      void eventReceived(struct epoll_event event); ///< Dispatch event to appropriate socket.
      
      ///
      /// The processCommand() method displays the thread array to the requesting console via the 
      /// session passed as parameter.
      ///
      /// @param session the session to write the requested data to. 
      ///
      
      int processCommand(std::string command, Session *session) override; ///<Output the threads array to the console.
      
    private:
      
      int epfd;
      int numberOfThreads; 
      std::map<int, Socket *> sockets; 
      std::vector<Thread> threads; 
      volatile bool terminateThreads; 
      std::mutex lock;
      
   };
   
}

#endif

