import debug from 'debug'
import { EventEmitter } from 'events'
import { Observable } from 'rx'
import { has } from 'lodash'

const log = debug('observable-socket')

export default function observableSocket (_ws) {
    let ws // init

    // Normalize events between browser and node. Assumes node libs follow the
    // same pattern that "ws" does, i.e. socket.io *does not* work.
    if (has(global, 'WebSocket')) {
        ws = new EventEmitter()

        _ws.onopen    = () => ws.emit('open')
        _ws.onclose   = () => ws.emit('close')
        _ws.onerror   = () => ws.emit('error')
        _ws.onmessage = e => ws.emit('message', e.data)
    } else {
        ws = _ws
    }

    const ready = () => _ws.readyState === 1
    const send = message => _ws.send(message)

    const readyToSend = new Promise(function (resolve) {

        // If we make an Observable from an already connected socket, we'll
        // never hear anything about 'open'.
        if (ready()) {
            log('already opened')

            resolve(send)
        } else {
            ws.once('open', function () {
                log('opened')

                resolve(send)
            })
        }
    })

    // Compose socket event streams, so that external subscribers have
    // a single interface that forwards socket events to onNext, onError and
    // onCompleted.
    const socketStream = Observable.create(function (observer) {
        const messageDisposable = Observable.fromEvent(ws, 'message')
            .subscribe(function onNext (e) {
                debug('observable-socket:onNext')('message')

                observer.onNext(e)
            })

        const errorDisposable = Observable.fromEvent(ws, 'error')
            .subscribe(function onNext (e) {
                log('error', e)

                observer.onError(e)
            })

        const closeDisposable = Observable.fromEvent(ws,'close')
            .subscribe(function onNext (e) {
                log('closed')

                observer.onCompleted(e)
            })

        return function disposeAndEmit () {
            closeDisposable.dispose()
            errorDisposable.dispose()
            messageDisposable.dispose()
        }
    })

    return {
        send: message => readyToSend.then(send => send(message)),
        observable: socketStream,
    }
}

@@ -460,19 +460,32 @@
 _ws.
-onopen    =
+addEventListener('open',
  () 
@@ -502,16 +502,17 @@
 ('open')
+)
 %0A       
@@ -520,19 +520,33 @@
 _ws.
-on
+addEventListener('
 close
-   =
+',
  () 
@@ -556,32 +556,33 @@
 ws.emit('close')
+)
 %0A        _ws.one
@@ -582,19 +582,33 @@
 _ws.
-on
+addEventListener('
 error
-   =
+',
  () 
@@ -618,32 +618,33 @@
 ws.emit('error')
+)
 %0A        _ws.onm
@@ -644,19 +644,35 @@
 _ws.
-on
+addEventListener('
 message
- =
+',
  e =
@@ -699,16 +699,17 @@
  e.data)
+)
 %0A    %7D e

Use addEventListener() to attach handlers for browser.