#include "TCPSession.h"
#include "Exception.h"
#include "Log.h"
#include "TCPServer.h"
#include "uuid/uuid.h"

namespace core {

   TCPSession::TCPSession(EPoll &ePoll, TCPServer &server, std::string text) : TCPSocket(ePoll, text), server(server) {
      uuid_t uuid;
      uuid_generate(uuid);
      alias = coreutils::MString((char *)uuid, 26);
   }

   TCPSession::~TCPSession() {
      server.removeFromSessionList(this);
      server.subscriptions.removeSessionSubscriptions(*this);
   }

   void TCPSession::output(std::stringstream &data) {
      data << "|" << ipAddress.getClientAddressAndPort();
   }

   void TCPSession::protocol(coreutils::ZString &data) {
      if (data.getLength() != 0) 
	if (!server.commands.processRequest(data, *this)) 
	  coreutils::Log(coreutils::LOG_DEBUG_1) << "Received data could not be parsed: " << data.str();      
   }

//   bool TCPSession::compareAlias(coreutils::MString alias) {
//      return this->alias == alias;
//   }

   void TCPSession::onRegistered() {
      onConnected();
      send();
      if (term)
	shutdown("termination requested");
   }

   void TCPSession::onConnected() {}

   void TCPSession::onDataReceived(coreutils::ZString &data) {
      if (data.getLength() > 0) {
         lineBuffer = (char *)realloc(lineBuffer, lineBufferSize + data.getLength());
         memcpy(lineBuffer + lineBufferSize, data.getData(), data.getLength());
         lineBufferSize += data.getLength();
         while (lineBufferSize > 0) {
            if (blockSize == 0) {
               lineLength = strcspn(lineBuffer, "\r\n");
               if (lineLength == lineBufferSize)
                  break;
               coreutils::ZString zLine(lineBuffer, lineLength);
               onLineReceived(zLine);
               if (lineBuffer[lineLength] == '\r')
                  ++lineLength;
               if (lineBuffer[lineLength] == '\n')
                  ++lineLength;
               lineBufferSize -= lineLength;
               if (lineBufferSize > 0)
                  memmove(lineBuffer, lineBuffer + lineLength, lineBufferSize);
               lineBuffer = (char *)realloc(lineBuffer, lineBufferSize);
            }
            else if (lineBufferSize >= blockLength) {
               coreutils::ZString zBlock(lineBuffer, blockLength);
               onBlockReceived(zBlock);
               lineBufferSize -= blockLength;
               if (lineBufferSize > 0)
                  memmove(lineBuffer, lineBuffer + blockLength, lineBufferSize);
               lineBuffer = (char *)realloc(lineBuffer, lineBufferSize);
            }
         }
      }
   }

   void TCPSession::setBlockSize(int blockSize) {
      this->blockSize = blockSize;
   }

   void TCPSession::onLineReceived(coreutils::ZString &line) {
      protocol(line);
      send();
      if (term)
         shutdown("termination requested");
   }

   void TCPSession::onBlockReceived(coreutils::ZString &block) {
      coreutils::Log(coreutils::LOG_DEBUG_3) << "[" << block.getLength() << "]";
      if (term)
         shutdown("termination requested");
   }

   void TCPSession::send() {
      if (out.tellp() > 0)
         write(out.str());
      out.str("");
   }

   void TCPSession::terminate() {
      term = true;
   }

}
