bool HuffmanStringProcessor::writeHuffBuffer(BitStream* pStream, const char* out_pBuffer, U32 maxLen)
{
   if (out_pBuffer == NULL) {
      pStream->writeFlag(false);
      pStream->writeInt(0, 8);
      return true;
   }

   if (mTablesBuilt == false)
      buildTables();

   size_t llen = out_pBuffer ? strlen(out_pBuffer) : 0;
   TNLAssertV(llen <= 255, ("String \"%s\" TOO long for writeString", out_pBuffer));
	U32 len = static_cast<U32>(llen);
   if (len > maxLen)
      len = maxLen;

   U32 numBits = 0;
   U32 i;
   for (i = 0; i < len; i++)
      numBits += mHuffLeaves[(unsigned char)out_pBuffer[i]].numBits;

   if (numBits >= (len * 8)) {
      pStream->writeFlag(false);
      pStream->writeInt(len, 8);
      pStream->write(len, out_pBuffer);
   } else {
      pStream->writeFlag(true);
      pStream->writeInt(len, 8);
      for (i = 0; i < len; i++) {
         HuffLeaf& rLeaf = mHuffLeaves[((unsigned char)out_pBuffer[i])];
         pStream->writeBits(rLeaf.numBits, &rLeaf.code);
      }
   }

   return true;
}
bool EventConnection::postNetEvent(NetEvent *theEvent)
{
   // Check if the direction this event moves is a valid direction.
   TNLAssertV(   (theEvent->getEventDirection() != NetEvent::DirUnset)
      && (theEvent->getEventDirection() != NetEvent::DirServerToClient || !isConnectionToServer())
      && (theEvent->getEventDirection() != NetEvent::DirClientToServer || !isConnectionToClient()),
      ("Trying to send wrong event direction in %s", theEvent->getClassName()));

   S32 classId = theEvent->getClassId(getNetClassGroup());
   if(U32(classId) >= mEventClassCount && getConnectionState() == Connected)
   {
      theEvent->incRef();
      theEvent->decRef(); // Avoids some type of memory leak by deleting here if nothing reference it.
      return false;
   }

   theEvent->notifyPosted(this);

   EventNote *event = mEventNoteChunker.alloc();
   event->mEvent = theEvent;
   event->mNextEvent = NULL;

   if(event->mEvent->mGuaranteeType == NetEvent::GuaranteedOrdered)
   {
      event->mSeqCount = mNextSendEventSeq++;
      if(!mSendEventQueueHead)
         mSendEventQueueHead = event;
      else
         mSendEventQueueTail->mNextEvent = event;
      mSendEventQueueTail = event;
   }
   else if(event->mEvent->mGuaranteeType == NetEvent::GuaranteedOrderedBigData)
   {
      BitStream bstream;
      const U32 start = 0;
      const U32 partsSize = 512;

      if(mConnectionParameters.mDebugObjectSizes)
         bstream.advanceBitPosition(BitStreamPosBitSize);
      
      S32 classId = event->mEvent->getClassId(getNetClassGroup());
      bstream.writeInt(classId, mEventClassBitSize);

      event->mEvent->pack(this, &bstream);
      logprintf(LogConsumer::LogEventConnection, "EventConnection %s: WroteEvent %s - %d bits", getNetAddressString(), event->mEvent->getDebugName(), bstream.getBitPosition() - start);

      if(mConnectionParameters.mDebugObjectSizes)
         bstream.writeIntAt(bstream.getBitPosition(), BitStreamPosBitSize, start);

      U32 size = bstream.getBytePosition();

      for(U32 i=0; i<size; i+=partsSize)
      {
         if(i+partsSize < size)
         {
            ByteBuffer *bytebuffer = new ByteBuffer(&bstream.getBuffer()[i], partsSize);
            bytebuffer->takeOwnership();  // may have to use this to prevent errors.
            s2rTNLSendDataParts(0, ByteBufferPtr(bytebuffer));
         }
         else
         {
            ByteBuffer *bytebuffer = new ByteBuffer(&bstream.getBuffer()[i], size-i);
            bytebuffer->takeOwnership();
            s2rTNLSendDataParts(1, ByteBufferPtr(bytebuffer));
         }
      }
      mEventNoteChunker.free(event);
   }
   else
   {
      event->mSeqCount = InvalidSendEventSeq;
      if(!mUnorderedSendEventQueueHead)
         mUnorderedSendEventQueueHead = event;
      else
         mUnorderedSendEventQueueTail->mNextEvent = event;
      mUnorderedSendEventQueueTail = event;
   }
   return true;
}
void EventConnection::writePacket(BitStream *bstream, PacketNotify *pnotify)
{
   Parent::writePacket(bstream, pnotify);
   EventPacketNotify *notify = static_cast<EventPacketNotify *>(pnotify);
   
   bool have_something_to_send = bstream->getBitPosition() >= 128;

   if(mConnectionParameters.mDebugObjectSizes)
      bstream->writeInt(DebugChecksum, 32);

   EventNote *packQueueHead = NULL, *packQueueTail = NULL;

   while(mUnorderedSendEventQueueHead)
   {
      if(bstream->isFull())
         break;
      // get the first event
      EventNote *ev = mUnorderedSendEventQueueHead;
      ConnectionStringTable::PacketEntry *strEntry = getCurrentWritePacketNotify()->stringList.stringTail;

      bstream->writeFlag(true);
      S32 start = bstream->getBitPosition();

      if(mConnectionParameters.mDebugObjectSizes)
         bstream->advanceBitPosition(BitStreamPosBitSize);
      
      S32 classId = ev->mEvent->getClassId(getNetClassGroup());
      bstream->writeInt(classId, mEventClassBitSize);

      ev->mEvent->pack(this, bstream);
      logprintf(LogConsumer::LogEventConnection, "EventConnection %s: WroteEvent %s - %d bits", getNetAddressString(), ev->mEvent->getDebugName(), bstream->getBitPosition() - start);

      if(mConnectionParameters.mDebugObjectSizes)
         bstream->writeIntAt(bstream->getBitPosition(), BitStreamPosBitSize, start);

      // check for packet overrun, and rewind this update if there
      // was one:
      if(!bstream->isValid() || bstream->getBitPosition() >= mWriteMaxBitSize)
      {
         mStringTable->packetRewind(&getCurrentWritePacketNotify()->stringList, strEntry);  // we never sent those stuff (TableStringEntry), so let it drop
         TNLAssert(have_something_to_send || bstream->getBitPosition() < mWriteMaxBitSize, "Packet too big to send");
         if(have_something_to_send)
         {
            bstream->setBitPosition(start - 1);
            bstream->clearError();
            break;
         }
         else //if(bstream->getBitPosition() < MaxPacketDataSize*8 - MinimumPaddingBits)
         {
            TNLAssertV(false, ("%s Packet too big to send, one or more events may be unable to send", ev->mEvent->getDebugName()));
            // dequeue the event:
            mUnorderedSendEventQueueHead = ev->mNextEvent;
            ev->mNextEvent = NULL;
            ev->mEvent->notifyDelivered(this, false);
            mEventNoteChunker.free(ev);
            bstream->setBitPosition(start - 1);
            bstream->clearError();
            break;
         }
      }
      have_something_to_send = true;

      // dequeue the event and add this event onto the packet queue
      mUnorderedSendEventQueueHead = ev->mNextEvent;
      ev->mNextEvent = NULL;

      if(!packQueueHead)
         packQueueHead = ev;
      else
         packQueueTail->mNextEvent = ev;
      packQueueTail = ev;
   }
   
   bstream->writeFlag(false);   
   S32 prevSeq = -2;
   
   while(mSendEventQueueHead)
   {
      if(bstream->isFull())
         break;
      
      // if the event window is full, stop processing
      if(mSendEventQueueHead->mSeqCount > mLastAckedEventSeq + 126)
         break;

      // get the first event
      EventNote *ev = mSendEventQueueHead;
      S32 eventStart = bstream->getBitPosition();
      ConnectionStringTable::PacketEntry *strEntry = getCurrentWritePacketNotify()->stringList.stringTail;

      bstream->writeFlag(true);

      if(!bstream->writeFlag(ev->mSeqCount == prevSeq + 1))
         bstream->writeInt(ev->mSeqCount, 7);
      prevSeq = ev->mSeqCount;

      if(mConnectionParameters.mDebugObjectSizes)
         bstream->advanceBitPosition(BitStreamPosBitSize);

      S32 start = bstream->getBitPosition();

      S32 classId = ev->mEvent->getClassId(getNetClassGroup());
      bstream->writeInt(classId, mEventClassBitSize);
      ev->mEvent->pack(this, bstream);

      ev->mEvent->getClassRep()->addInitialUpdate(bstream->getBitPosition() - start);
      logprintf(LogConsumer::LogEventConnection, "EventConnection %s: WroteEvent %s - %d bits", getNetAddressString(), ev->mEvent->getDebugName(), bstream->getBitPosition() - start);

      if(mConnectionParameters.mDebugObjectSizes)
         bstream->writeIntAt(bstream->getBitPosition(), BitStreamPosBitSize, start - BitStreamPosBitSize);

      // check for packet overrun, and rewind this update if there
      // was one:
      if(!bstream->isValid() || bstream->getBitPosition() >= mWriteMaxBitSize)
      {
         mStringTable->packetRewind(&getCurrentWritePacketNotify()->stringList, strEntry);  // we never sent those stuff (TableStringEntry), so let it drop
         if(have_something_to_send)
         {
            bstream->setBitPosition(eventStart);
            bstream->clearError();
            break;
         }
         else
         {
            TNLAssertV(false, ("%s Packet too big to send, one or more events may be unable to send", ev->mEvent->getDebugName()));
            for(EventNote *walk = ev->mNextEvent; walk; walk = walk->mNextEvent)
               walk->mSeqCount--;    // removing a GuaranteedOrdered needs to re-order mSeqCount
            mNextSendEventSeq--;

            // dequeue the event:
            mSendEventQueueHead = ev->mNextEvent;
            ev->mNextEvent = NULL;
            ev->mEvent->notifyDelivered(this, false);
            mEventNoteChunker.free(ev);
            bstream->setBitPosition(eventStart);
            bstream->clearError();
            break;
         }
      }
      have_something_to_send = true;

      // dequeue the event:
      mSendEventQueueHead = ev->mNextEvent;      
      ev->mNextEvent = NULL;
      if(!packQueueHead)
         packQueueHead = ev;
      else
         packQueueTail->mNextEvent = ev;
      packQueueTail = ev;
   }
   for(EventNote *ev = packQueueHead; ev; ev = ev->mNextEvent)
      ev->mEvent->notifySent(this);
      
   notify->eventList = packQueueHead;
   bstream->writeFlag(0);
}