class Faye::WebSocket::HybiParser

def close(code = nil, reason = nil, &callback)

def close(code = nil, reason = nil, &callback)
  return if @closed
  @closing_callback ||= callback
  @socket.send(reason || '', :close, code || ERRORS[:normal_closure])
  @closed = true
end

def create_handshake

def create_handshake
  Handshake.new(@socket.uri, @protocols)
end

def emit_frame

def emit_frame
  payload = @masked ? WebSocketMask.mask(@payload, @mask) : @payload
  case @opcode
    when OPCODES[:continuation] then
      return @socket.close(ERRORS[:protocol_error], nil, false) unless @mode
      @buffer.concat(payload)
      if @final
        message = @buffer
        message = WebSocket.encode(message, true) if @mode == :text
        reset
        if message
          @socket.receive(message)
        else
          @socket.close(ERRORS[:encoding_error], nil, false)
        end
      end
    when OPCODES[:text] then
      if @final
        message = WebSocket.encode(payload, true)
        if message
          @socket.receive(message)
        else
          @socket.close(ERRORS[:encoding_error], nil, false)
        end
      else
        @mode = :text
        @buffer.concat(payload)
      end
    when OPCODES[:binary] then
      if @final
        @socket.receive(payload)
      else
        @mode = :binary
        @buffer.concat(payload)
      end
    when OPCODES[:close] then
      code = (payload.size >= 2) ? 256 * payload[0] + payload[1] : nil
      unless (payload.size == 0) or
             (code && code >= 3000 && code < 5000) or
             ERROR_CODES.include?(code)
        code = ERRORS[:protocol_error]
      end
      if payload.size > 125 or not WebSocket.valid_utf8?(payload[2..-1] || [])
        code = ERRORS[:protocol_error]
      end
      reason = (payload.size > 2) ? WebSocket.encode(payload[2..-1], true) : nil
      @socket.close(code, reason, false)
      @closing_callback.call if @closing_callback
    when OPCODES[:ping] then
      return @socket.close(ERRORS[:protocol_error], nil, false) if payload.size > 125
      @socket.send(payload, :pong)
    when OPCODES[:pong] then
      message = WebSocket.encode(payload, true)
      callback = @ping_callbacks[message]
      @ping_callbacks.delete(message)
      callback.call if callback
  end
end

def frame(data, type = nil, code = nil)

def frame(data, type = nil, code = nil)
  return nil if @closed
  is_text = (String === data)
  opcode  = OPCODES[type || (is_text ? :text : :binary)]
  buffer  = data.respond_to?(:bytes) ? data.bytes.to_a : data
  insert  = code ? 2 : 0
  length  = buffer.size + insert
  header  = (length <= 125) ? 2 : (length <= 65535 ? 4 : 10)
  offset  = header + (@masking ? 4 : 0)
  masked  = @masking ? MASK : 0
  frame   = Array.new(offset)
  frame[0] = FIN | opcode
  if length <= 125
    frame[1] = masked | length
  elsif length <= 65535
    frame[1] = masked | 126
    frame[2] = (length >> 8) & BYTE
    frame[3] = length & BYTE
  else
    frame[1] = masked | 127
    frame[2] = (length >> 56) & BYTE
    frame[3] = (length >> 48) & BYTE
    frame[4] = (length >> 40) & BYTE
    frame[5] = (length >> 32) & BYTE
    frame[6] = (length >> 24) & BYTE
    frame[7] = (length >> 16) & BYTE
    frame[8] = (length >> 8)  & BYTE
    frame[9] = length & BYTE
  end
  if code
    buffer = [(code >> 8) & BYTE, code & BYTE] + buffer
  end
  if @masking
    mask = [rand(256), rand(256), rand(256), rand(256)]
    frame[header...offset] = mask
    buffer = WebSocketMask.mask(buffer, mask)
  end
  frame.concat(buffer)
  WebSocket.encode(frame)
end

def handshake_response

def handshake_response
  sec_key = @socket.env['HTTP_SEC_WEBSOCKET_KEY']
  return '' unless String === sec_key
  accept    = Base64.encode64(Digest::SHA1.digest(sec_key + Handshake::GUID)).strip
  protos    = @socket.env['HTTP_SEC_WEBSOCKET_PROTOCOL']
  supported = @protocols
  proto     = nil
  headers = [
    "HTTP/1.1 101 Switching Protocols",
    "Upgrade: websocket",
    "Connection: Upgrade",
    "Sec-WebSocket-Accept: #{accept}"
  ]
  if protos and supported
    protos = protos.split(/\s*,\s*/) if String === protos
    proto = protos.find { |p| supported.include?(p) }
    if proto
      @protocol = proto
      headers << "Sec-WebSocket-Protocol: #{proto}"
    end
  end
  (headers + ['','']).join("\r\n")
end

def initialize(web_socket, options = {})

def initialize(web_socket, options = {})
  reset
  @socket    = web_socket
  @reader    = StreamReader.new
  @stage     = 0
  @masking   = options[:masking]
  @protocols = options[:protocols]
  @protocols = @protocols.split(/\s*,\s*/) if String === @protocols
  
  @ping_callbacks = {}
end

def integer(bytes)

def integer(bytes)
  number = 0
  bytes.each_with_index do |data, i|
    number += data << (8 * (bytes.size - 1 - i))
  end
  number
end

def open?

def open?
  true
end

def parse(data)

def parse(data)
  @reader.put(data.bytes.to_a)
  buffer = true
  while buffer
    case @stage
      when 0 then
        buffer = @reader.read(1)
        parse_opcode(buffer[0]) if buffer
      when 1 then
        buffer = @reader.read(1)
        parse_length(buffer[0]) if buffer
      when 2 then
        buffer = @reader.read(@length_size)
        parse_extended_length(buffer) if buffer
      when 3 then
        buffer = @reader.read(4)
        if buffer
          @mask  = buffer
          @stage = 4
        end
      when 4 then
        buffer = @reader.read(@length)
        if buffer
          @payload = buffer
          emit_frame
          @stage = 0
        end
    end
  end
  nil
end

def parse_extended_length(buffer)

def parse_extended_length(buffer)
  @length = integer(buffer)
  @stage  = @masked ? 3 : 4
end

def parse_length(data)

def parse_length(data)
  @masked = (data & MASK) == MASK
  @length = (data & LENGTH)
  if @length <= 125
    @stage = @masked ? 3 : 4
  else
    @length_size = (@length == 126) ? 2 : 8
    @stage       = 2
  end
end

def parse_opcode(data)

def parse_opcode(data)
  if [RSV1, RSV2, RSV3].any? { |rsv| (data & rsv) == rsv }
    return @socket.close(ERRORS[:protocol_error], nil, false)
  end
  @final   = (data & FIN) == FIN
  @opcode  = (data & OPCODE)
  @mask    = []
  @payload = []
  unless OPCODES.values.include?(@opcode)
    return @socket.close(ERRORS[:protocol_error], nil, false)
  end
  unless FRAGMENTED_OPCODES.include?(@opcode) or @final
    return @socket.close(ERRORS[:protocol_error], nil, false)
  end
  if @mode and OPENING_OPCODES.include?(@opcode)
    return @socket.close(ERRORS[:protocol_error], nil, false)
  end
  @stage = 1
end

def ping(message = '', &callback)

def ping(message = '', &callback)
  @ping_callbacks[message] = callback if callback
  @socket.send(message, :ping)
end

def reset

def reset
  @buffer = []
  @mode   = nil
end

def version

def version
  "hybi-#{@socket.env['HTTP_SEC_WEBSOCKET_VERSION']}"
end