-- httpserver-connection
-- Part of nodemcu-httpserver, provides a buffered connection object that can handle multiple
-- consecutive send() calls, and buffers small payloads to send once they get big.
-- For this to work, it must be used from a coroutine and owner is responsible for the final
-- flush() and for closing the connection.
-- Author: Philip Gladstone, Marcos Kirsch

BufferedConnection = {}

-- parameter is the nodemcu-firmware connection
function BufferedConnection:new(connection)
   local newInstance = {}
   newInstance.connection = connection
   newInstance.size = 0
   newInstance.data = {}

   function newInstance:flush()
      if self.size > 0 then
         self.connection:send(table.concat(self.data, ""))
         self.data = {}
         self.size = 0
         return true
      end
      return false
   end

   function newInstance:send(payload)
      local flushthreshold = 1400

      local newsize = self.size + payload:len()
      while newsize > flushthreshold do
          --STEP1: cut out piece from payload to complete threshold bytes in table
          local piecesize = flushthreshold - self.size
          local piece = payload:sub(1, piecesize)
          payload = payload:sub(piecesize + 1, -1)
          --STEP2: insert piece into table
          table.insert(self.data, piece)
          self.size = self.size + piecesize --size should be same as flushthreshold
          --STEP3: flush entire table
          if self:flush() then
              coroutine.yield()
          end
          --at this point, size should be 0, because the table was just flushed
          newsize = self.size + payload:len()
      end
            
      --at this point, whatever is left in payload should be <= flushthreshold
      local plen = payload:len()
      if plen == flushthreshold then
          --case 1: what is left in payload is exactly flushthreshold bytes (boundary case), so flush it
          table.insert(self.data, payload)
          self.size = self.size + plen
          if self:flush() then
              coroutine.yield()
          end
      elseif payload:len() then
          --case 2: what is left in payload is less than flushthreshold, so just leave it in the table
          table.insert(self.data, payload)
          self.size = self.size + plen
      --else, case 3: nothing left in payload, so do nothing
      end
   end

   return newInstance
end

return BufferedConnection
