#ifndef __Session_h__
#define __Session_h__

#include "TCPLineBufferParser.h"
#include "MString.h"
#include "SessionFilter.h"
#include "TCPSocket.h"

namespace core {

  class Command;
  class TCPServer;

  ///
  /// TCPSession
  ///
  /// 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.
  ///
  ///
  ///

  class TCPSession : public TCPLineBufferParser {

  public:
    ///
    ///
    ///

    TCPSession(EPoll &ePoll, TCPServer &server, std::string text = "");

    ///
    ///
    ///

    virtual ~TCPSession();

    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();

    ///
    ///
    ///

    TCPServer &server;

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

    std::stringstream out;

    ///
    /// uuid is generated automatically when the session object is instantiated. This
    /// value can be used to uniquely identify a session and is the default value
    /// pointed to by the alias pointer.
    ///

    char uuid[37];

    ///
    /// alias is a MString that can be set to any string of characters that identifies
    /// this session uniquely. Alias's should be unique between sessions.
    ///

    coreutils::MString alias;
    ///
    ///
    ///

    ///
    ///
    ///

//    bool compareAlias(coreutils::MString alias);

  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.
    ///

     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 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
