var through = require('through2')
var duplexify = require('duplexify')
var WS = require('ws')

module.exports = WebSocketStream

function WebSocketStream(target, protocols) {
  var stream, socket
  var socketWrite = process.title === 'browser' ? socketWriteBrowser : socketWriteNode
  var proxy = through.obj(socketWrite, socketEnd)

  // use existing WebSocket object that was passed in
  if (typeof target === 'object') {
    socket = target
  // otherwise make a new one
  } else {
    socket = new WS(target, protocols)
    socket.binaryType = 'arraybuffer'
  }

  // was already open when passed in
  if (socket.readyState === 1) {
    stream = proxy
  } else {
    stream = duplexify.obj()
    socket.addEventListener("open", onready)
  }

  stream.socket = socket

  socket.addEventListener("close", onclose)
  socket.addEventListener("error", onerror)
  socket.addEventListener("message", onmessage)

  proxy.on('close', destroy)

  function socketWriteNode(chunk, enc, next) {
    socket.send(chunk, next)
  }

  function socketWriteBrowser(chunk, enc, next) {
    try {
      socket.send(chunk)
    } catch(err) {
      return next(err)
    }

    next()
  }

  function socketEnd(done) {
    socket.close()
    done()
  }

  function onready() {
    stream.setReadable(proxy)
    stream.setWritable(proxy)
    stream.emit('connect')
  }

  function onclose() {
    stream.end();
    stream.destroy()
  }

  function onerror(err) {
    stream.destroy(err)
  }

  function onmessage(event) {
    var data = event.data
    if (data instanceof ArrayBuffer) data = new Buffer(new Uint8Array(data))
    else data = new Buffer(data)
    proxy.push(data)
  }

  function destroy() {
    socket.close()
  }

  return stream
}
