// event stream -.-
window.Buffer = require("buffer").Buffer

var shoe = require("mux-demux-shoe")
    , through = require("through")
    , PauseStream = require("pause-stream")
    , es = require("event-stream")
    , Backoff = require("backoff").fibonnaci
    , BACKOFF_OPTIONS = {
        initialDelay: 500,
        maxDelay: 10000
    }

module.exports = reconnecter

function reconnecter(uri) {
    var proxyWrite = through()
        , proxyRead = through()
        , proxy = es.duplex(proxyWrite, proxyRead)
        , metaStreams = []
        , stream
        , backoff = Backoff(BACKOFF_OPTIONS)

    proxy.createStream = createStream
    proxy.createWriteStream = createWriteStream
    proxy.createReadStream = createReadStream

    createShoeStream()

    return proxy

    function createShoeStream() {
        stream = shoe(uri)

        metaStreams.forEach(proxyMdmStream)

        stream.once("connect", onconnect)

        proxyWrite.pipe(stream).pipe(proxyRead)

        stream.once("end", onend)
    }

    function onconnect() {
        backoff.reset()
        proxy.emit("connect")
    }

    function onend() {
        proxy.emit("disconnect")

        // wait a second otherwise it spin locks
        var delay = backoff.backoffStrategy_.next()
        setTimeout(createShoeStream, delay)
    }

    function proxyMdmStream(details) {
        var proxyWrite = details.proxyWrite
            , proxyRead = details.proxyRead

        var mdm = stream.createStream(details.meta, details.opts)

        proxyWrite.pipe(mdm).pipe(proxyRead)

        stream.once("end", mdm.end.bind(mdm))
    }

    function createStream(meta, opts) {
        var proxyWrite = through()
            , proxyRead = through()
            , proxy = es.duplex(proxyWrite, proxyRead)

        var mdm = stream.createStream(meta, opts)

        proxyWrite.pipe(mdm).pipe(proxyRead)

        metaStreams.push({
            proxy: proxy
            , proxyRead: proxyRead
            , proxyWrite: proxyWrite
            , meta: meta
            , opts: opts
        })

        stream.once("end", mdm.end.bind(mdm))

        return proxy
    }

    function createWriteStream(meta) {
        return createStream(meta, {
            writable: true
            , readable: false
        })
    }

    function createReadStream(meta) {
        return createStream(meta, {
            writable: false
            , readable: true
        })
    }
}
@@ -131,52 +131,8 @@
 h%22)%0A
-    , PauseStream = require(%22pause-stream%22)%0A
     
@@ -916,32 +916,68 @@
 ).pipe(proxyRead
+, %7B%0A            end: false%0A        %7D
 )%0A%0A        strea
@@ -1357,21 +1357,23 @@
 ar proxy
-Write
+MdmRead
  = detai
@@ -1376,29 +1376,31 @@
 etails.proxy
-Write
+MdmRead
 %0A           
@@ -1407,20 +1407,24 @@
  , proxy
-Read
+MdmWrite
  = detai
@@ -1431,20 +1431,92 @@
 ls.proxy
-Read
+MdmWrite%0A            , meta = details.meta%0A            , opts = details.opts
 %0A%0A      
@@ -1551,30 +1551,14 @@
 eam(
-details.meta, details.
+meta, 
 opts
@@ -1565,32 +1565,35 @@
 )%0A%0A        proxy
+Mdm
 Write.pipe(mdm).
@@ -1594,36 +1594,75 @@
 (mdm).pipe(proxy
+Mdm
 Read
+, %7B%0A            end: false%0A        %7D
 )%0A%0A        strea
@@ -1750,37 +1750,39 @@
        var proxy
-Write
+MdmRead
  = through()%0A   
@@ -1789,36 +1789,40 @@
          , proxy
-Read
+MdmWrite
  = through()%0A   
@@ -1847,32 +1847,35 @@
  es.duplex(proxy
+Mdm
 Write, proxyRead
@@ -1866,24 +1866,27 @@
 Write, proxy
+Mdm
 Read)%0A%0A     
@@ -1936,32 +1936,35 @@
 )%0A%0A        proxy
+Mdm
 Write.pipe(mdm).
@@ -1973,20 +1973,59 @@
 pe(proxy
+Mdm
 Read
+, %7B%0A            end: false%0A        %7D
 )%0A%0A     
@@ -2086,24 +2086,27 @@
      , proxy
+Mdm
 Read: proxyR
@@ -2100,24 +2100,27 @@
 mRead: proxy
+Mdm
 Read%0A       
@@ -2127,24 +2127,27 @@
      , proxy
+Mdm
 Write: proxy
@@ -2142,24 +2142,27 @@
 Write: proxy
+Mdm
 Write%0A      

make sure streams don't get ended behind our back