#ifndef __TCPSession2_h__
# define __TCPSession2_h__

#include "TCPSocket.h"
#include "Timer.h"
#include "SessionFilter.h"

namespace core {

   class Command;
   class TCPServer;

   ///
   /// TCPSession2
   ///
   /// TCPSession defines the nature of the interaction with the client
   /// and stores persistent data for a defined session. TCPSession objects
   /// are not sockets but instead provide a communications control
   /// mechanism. Protocol conversations are provided through extensions
   /// from this object.
   ///
   /// TCPSession2 is designed to be 'connected' instead of being served
   /// by a server.
   ///

   class TCPSession2 : public TCPSocket {

    public:

      ///
      ///
      ///

      TCPSession2(EPoll &ePoll, std::string text = "");

      ///
      ///
      ///

      virtual ~TCPSession2();

      Command *grab = NULL;

      virtual void output(std::stringstream &data);

      ///
      /// The send method is used to output the contents of the out stream
      /// to the session containing the stream.
      ///

      void send();

      ///
      /// Use this method to terminate this TCPSession.
      ///

      void terminate();

      ///
      /// Use out to send data to the session socket or other session sockets.
      ///

      std::stringstream out;

    protected:

      ///
      ///
      ///

      virtual void onRegistered() override;

      ///
      /// Override this method to receive data directly from the socket as data is
      /// received. If you need data split by line termination characters then
      /// override the onLineReceived method instead.
      ///
      virtual void onDataReceived(coreutils::ZString &data) override;

      ///
      /// Override the onLineReceived method to receive a string of characters that
      /// represents a single line of data terminated by a LF or CRLF. If onDataReceived
      /// was overriden this method will not be called unless the onDataReceived calls
      /// this method explicitly using the class and member name.
      ///

      virtual void onLineReceived(coreutils::ZString &line);

      ///
      /// Override the onBlockReceived method to receive a string of characters that
      /// represents a single block of data of length determined by the block length value. If
      /// onDataReceived was overriden this method will not be called unless the onDataReceived
      /// calls this method explicitly using the class and member name.
      ///

      virtual void onBlockReceived(coreutils::ZString &block);

      ///
      /// This method is called from within the protocol method when protocol is called
      /// on the initial connection where the data is an empty string. Use this method
      /// to deliver a message to the connection upon connection.
      ///

      virtual void onConnected();

      ///
      /// Override the protocol method to manage and control the session communications
      /// in your inherited session. If you do not override this method then the Session
      /// default will process the 'commands' added to the server object using the
      /// processRequest method on the session input.
      ///
      /// When data is received within the session two modes are available to pass the
      /// data through the protocol method: LINE or BLOCK.
      ///

      virtual void protocol(coreutils::ZString &data);

      ///
      /// Use setBlockSize to set the amount of data that should be read at once from the
      /// session data buffer.
      /// If this value is set to 0 then the data will be retrieved
      ///

      void setBlockSize(int size = 0);

    private:
      char *lineBuffer = NULL;
      int lineBufferSize = 0;
      int lineLength = 0;
      int blockLength = 0;
      std::mutex mtx;
      bool term = false;
      int blockSize = 0;

   };

}

#endif
