import {Readable, Transform} from "stream"

const sortTypes = {
  number: (a, b) => a - b,
  object: Buffer.compare,
  string: undefined
}

export default tuple => {
  let sources = Object.keys(tuple).map(name => {
    let source = {name}

    let transform = Transform({
      objectMode: true,

      transform(kv, enc, cb) {
        source.kv = kv
        source.cb = cb

        push()
      },

      flush(cb) {
        let index = sources.filter(x => x.name === name)[0]
        sources.splice(index, 1)

        push()
        cb()
      }
    })

    tuple[name].pipe(transform)

    return source
  })

  let pushable = false
  let read = () => {
    pushable = true
    push()
  }

  let push = () => {
    if (!sources.length) return tuples.push(null)

    let kvs = sources.map(source => source.kv)
    let ready = kvs.every(Boolean)

    if (!ready) return

    let value = new tuple.constructor
    let sort = sortTypes[typeof kvs[0].key]
    let key = kvs.map(kv => kv.key).sort(sort)[0]

    let cbs = sources
      .filter(source => source.kv && source.kv.key === key)
      .map(source => {
        let cb = source.cb

        value[source.name] = source.kv.value

        delete source.kv
        delete source.cb

        return cb
      })

    pushable = tuples.push({key, value})

    cbs.forEach(cb => cb())
  }

  let tuples = new Readable({read, objectMode: true})

  return tuples
}

@@ -13,19 +13,8 @@
 able
-, Transform
 %7D fr
@@ -165,203 +165,191 @@
 rces
- = Object.keys(tuple).map(name =%3E %7B%0A    let source = %7Bname%7D
+%0A  let isPushable = false%0A  let ctor = tuple.constructor
 %0A%0A
-  
   let 
-transform = Transform(%7B%0A      objectMode: true,%0A%0A      transform(kv, enc, cb) %7B%0A        source.kv = kv%0A        source.cb = cb%0A
+setup = () =%3E %7B%0A    sources = Object.keys(tuple).map(name =%3E %7B%0A      let data = %5B%5D%0A%0A      tuple%5Bname%5D.on(%22end%22, () =%3E %7B
 %0A   
@@ -353,29 +353,38 @@
         
+data.
 push(
+null
 )%0A      
 %7D,%0A%0A    
@@ -379,137 +379,136 @@
     
-%7D,%0A%0A      flush(cb) %7B%0A        let index = sources.filter(x =%3E x.name === name)%5B0%5D%0A        sources.splice(index, 1)%0A%0A        
+  check()%0A      %7D)%0A%0A      tuple%5Bname%5D.on(%22readable%22, () =%3E %7B%0A        let kv%0A        while (kv = tuple%5Bname%5D.read()) data.
 push(
+kv
 )%0A  
@@ -514,17 +514,20 @@
        c
-b
+heck
 ()%0A     
@@ -532,96 +532,48 @@
    %7D
+)%0A
 %0A    
-%7D)%0A%0A    tuple%5Bname%5D.pipe(transform)%0A%0A    return source%0A
+  return %7Bname, data%7D%0A  
   %7D)%0A
-%0A
   
-let pushable = false
+%7D%0A
 %0A  l
@@ -590,25 +590,54 @@
 () =%3E %7B%0A    
-p
+if (!sources) setup()%0A%0A    isP
 ushable = tr
@@ -643,20 +643,21 @@
 rue%0A    
-push
+check
 ()%0A  %7D%0A%0A
@@ -662,20 +662,21 @@
 %0A%0A  let 
-push
+check
  = () =%3E
@@ -691,130 +691,76 @@
 f (!
-sources.length) return tuples.push(null)%0A%0A    let kvs = sources.map(source
+isPushable) return%0A%0A    let isReady
  =
-%3E
  source
-.kv)%0A    let ready = kvs.every(Boolean
+s.every(x =%3E 0 in x.data
 )%0A%0A 
@@ -767,17 +767,19 @@
    if (!
-r
+isR
 eady) re
@@ -796,81 +796,110 @@
 let 
-value = new tuple.constructor%0A    let sort = sortTypes%5Btypeof kvs%5B0%5D.key%5D
+actives = sources.filter(x =%3E x.data%5B0%5D !== null)%0A%0A    if (actives.length === 0) return rs.push(null)%0A
 %0A   
@@ -910,280 +910,230 @@
  key
+s
  = 
-kv
+active
 s.map(
-kv
+x
  =%3E 
-kv.key).sort(sort)%5B0%5D%0A%0A    let cbs = sources%0A      .filter(source =%3E source.kv && source.kv.key === key)%0A      .map(source =%3E %7B%0A        let cb = source.cb%0A%0A        value%5Bsource.name%5D = source.kv
+x.data%5B0%5D.key)%0A    let key = keys.sort(sortTypes%5Btypeof keys%5B0%5D%5D)%5B0%5D%0A    let value = actives.reduce((acc, x) =%3E %7B%0A      if (x.data%5B0%5D.key === key) %7B%0A        acc%5Bx.name%5D = x.data.shift()
 .value%0A
-%0A  
       
-delete source.kv%0A        delete source.cb%0A%0A  
+%7D%0A%0A
     
@@ -1145,89 +1145,54 @@
 urn 
+ac
 c
-b
 %0A    
-  %7D)%0A%0A    pushable = tuples.push(%7Bkey, value%7D)%0A%0A    cbs.forEach(cb =%3E cb()
+%7D, new ctor)%0A%0A    rs.push(%7Bkey, value%7D
 )%0A  
@@ -1200,21 +1200,17 @@
 %0A%0A  let 
-tuple
+r
 s = new 
@@ -1223,14 +1223,8 @@
 le(%7B
-read, 
 obje
@@ -1235,16 +1235,22 @@
 de: true
+, read
 %7D)%0A%0A  re
@@ -1254,17 +1254,13 @@
  return 
-tuple
+r
 s%0A%7D%0A

use readable instead of transform