#include "Thread.h"
#include "EPoll.h"
#include "Command.h"
#include "Exception.h"
#include <signal.h>

namespace core {

   EPoll::EPoll() : Command() {

      coreutils::Log(coreutils::LOG_DEBUG_2) << "EPoll starting.";

      maxSockets = 1000;
      epfd = epoll_create1(0);
      terminateThreads = false;
   }

   EPoll::~EPoll() {}

   bool EPoll::start(int numberOfThreads, int maxSockets) {

      coreutils::Log(coreutils::LOG_DEBUG_2) << "Starting epoll event processing.";

      this->numberOfThreads = numberOfThreads;

      coreutils::Log(coreutils::LOG_DEBUG_3) << "Number of threads starting is " << numberOfThreads << ".";
      coreutils::Log(coreutils::LOG_DEBUG_3) << "Maximum connections is " << maxSockets << ".";

      // TODO: Set the number of maximum open files to the maxSockets value.
      //
      //----------------------------------------------------------------------
      // Create thread objects into vector for number of threads requested.
      // Hand all the threads a pointer to the EPoll object so they can run
      // the socket handlers.
      //----------------------------------------------------------------------

      for(int ix = 0; ix < numberOfThreads; ++ix)
        threads.emplace_back(*this);

      for(int ix = 0; ix < numberOfThreads; ++ix)
        threads[ix].start();

      return true;
   }

   bool EPoll::stop() {

      terminateThreads = true;

      //--------------------------------------------------------
      // Kill and join all the threads that have been started.
      //--------------------------------------------------------

      for(int ix = 0; ix < numberOfThreads; ++ix)
        threads[ix].join();

      //--------------------------
      // Close the epoll socket.
      //--------------------------

      close(epfd);

      return true;
   }

   bool EPoll::isStopping() {
      return terminateThreads;
   }

   int EPoll::getDescriptor() {
      return epfd;
   }

   int EPoll::processCommand(coreutils::ZString &request, TCPSession &session) {
      int sequence = 0;
      for(auto threadx : threads) {
         session.out << "|" << ++sequence;
         threadx.output(session.out);
         session.out << "|" << std::endl;
      }
      return 1;
   }

}
