   # can be constructed with more flexibility, as file buffers or
   # message queues can be used as additional packet relay mechanisms.
   send: (data) ->
-    @connect() unless @connected
     data = @dataDelegate() if data is undefined and typeof @dataDelegate is 'function'
-    @emitEvent 'data', data
+    @handleSocketEvent 'data', data
 
   # ## Sending information packets without open bracket
   #

#     (c) 2011-2012 Henri Bergius, Nemein
#     NoFlo may be freely distributed under the MIT license
{EventEmitter} = require 'events'

# ## Internal Sockets
#

    return "DATA -> #{toStr(@to)}" unless @from
    "#{fromStr(@from)} -> #{toStr(@to)}"

  legacyToIp: (event, payload) ->
    # No need to wrap modern IP Objects
    return payload if payload and typeof payload is 'object' and payload.isIP

    # Wrap legacy events into appropriate IP objects
    switch event
      when 'connect'
        return new IP 'openBracket', null
      when 'connect', 'begingroup'
        return new IP 'openBracket', payload
      when 'disconnect', 'endgroup'
        return new IP 'closeBracket'
      else
        return new IP 'data', payload

  ipToLegacy: (ip) ->
    switch ip.type
      when 'openBracket'
        if ip.data is null
          return legacy =
            event: 'connect'
            payload: @
        return legacy =
          event: 'begingroup'
          payload: ip.data
      when 'data'
        return legacy =
          event: 'data'
          payload: ip.data
      when 'closeBracket'
        if ip.data is null
          return legacy =
            event: 'disconnect'
            payload: @
        return legacy =
          event: 'endgroup'
          payload: ip.data

  handleSocketEvent: (event, payload, autoConnect = true) ->
    ip = @legacyToIp event, payload

    # Handle state transitions
    if ip.type is 'data' and not @connected and autoConnect
      # Connect before sending data
      @handleSocketEvent 'connect', null

    if ip.type is 'openBracket' and ip.data
      if not @connected and autoConnect
        # Connect before sending bracket
        @handleSocketEvent 'connect', null
      # Append bracket to socket group list
      @groups.push ip.data

    if ip.type is 'openBracket' and ip.data is null
      # If we're already connected, no need to connect again
      return if @connected
      @connected = true

    if ip.type is 'closeBracket'
      if @groups.length
        # Add group name to bracket
        ip.data = @groups.pop()
      else
        # If we were already disconnected, no need to disconnect again
        return unless @connected
        # Last bracket was closed, we're disconnected
        @connected = false
        ip.data = null

    # Emit the IP Object
    @emitEvent 'ip', ip

    # Emit the legacy event
    legacyEvent = @ipToLegacy ip
    @emitEvent legacyEvent.event, legacyEvent.payload

exports.InternalSocket = InternalSocket

exports.createSocket = -> new InternalSocket
