/* Copyright (c) 2012-2016 LevelUP contributors
 * See list at <https://github.com/level/levelup#contributing>
 * MIT License <https://github.com/level/levelup/blob/master/LICENSE.md>
 */

var common  = require('./common')

  , assert  = require('referee').assert
  , refute  = require('referee').refute
  , buster  = require('bustermove')
  , delayed = require('delayed').delayed

buster.testCase('Key and Value Streams', {
    'setUp': function (done) {
      common.commonSetUp.call(this, function () {
        this.dataSpy    = this.spy()
        this.endSpy     = this.spy()
        this.sourceData = []

        for (var i = 0; i < 100; i++) {
          var k = (i < 10 ? '0' : '') + i
          this.sourceData.push({
              type  : 'put'
            , key   : k
            , value : Math.random()
          })
        }

        this.sourceKeys = Object.keys(this.sourceData)
          .map(function (k) { return this.sourceData[k].key }.bind(this))
        this.sourceValues = Object.keys(this.sourceData)
          .map(function (k) { return this.sourceData[k].value }.bind(this))

        this.verify = delayed(function (rs, data, done) {
          assert.equals(this.endSpy.callCount, 1, 'Stream emitted single "end" event')
          assert.equals(this.dataSpy.callCount, data.length, 'Stream emitted correct number of "data" events')
          data.forEach(function (d, i) {
            var call = this.dataSpy.getCall(i)
            if (call) {
              //console.log('call', i, ':', call.args[0].key, '=', call.args[0].value, '(expected', d.key, '=', d.value, ')')
              assert.equals(call.args.length, 1, 'Stream "data" event #' + i + ' fired with 1 argument')
              assert.equals(+call.args[0].toString(), +d, 'Stream correct "data" event #' + i + ': ' + d)
            }
          }.bind(this))
          done()
        }, 0.05, this)

        done()
      }.bind(this))
    }

  , 'tearDown': common.commonTearDown

  , 'test .keyStream()': function (done) {
      this.openTestDatabase(function (db) {
        // execute
        db.batch(this.sourceData.slice(), function (err) {
          refute(err)

          var rs = db.keyStream()
          rs.on('data', this.dataSpy)
          rs.on('end', this.endSpy)
          rs.on('close', this.verify.bind(this, rs, this.sourceKeys, done))
        }.bind(this))
      }.bind(this))
    }

  , 'test .readStream({keys:true,values:false})': function (done) {
      this.openTestDatabase(function (db) {
        // execute
        db.batch(this.sourceData.slice(), function (err) {
          refute(err)

          var rs = db.readStream({ keys: true, values: false })
          rs.on('data', this.dataSpy)
          rs.on('end', this.endSpy)
          rs.on('close', this.verify.bind(this, rs, this.sourceKeys, done))
        }.bind(this))
      }.bind(this))
    }

  , 'test .valueStream()': function (done) {
      this.openTestDatabase(function (db) {
        // execute
        db.batch(this.sourceData.slice(), function (err) {
          refute(err)

          var rs = db.valueStream()
          rs.on('data', this.dataSpy)
          rs.on('end', this.endSpy)
          rs.on('close', this.verify.bind(this, rs, this.sourceValues, done))
        }.bind(this))
      }.bind(this))
    }

  , 'test .readStream({keys:false,values:true})': function (done) {
      this.openTestDatabase(function (db) {
        // execute
        db.batch(this.sourceData.slice(), function (err) {
          refute(err)

          var rs = db.readStream({ keys: false, values: true })
          rs.on('data', this.dataSpy)
          rs.on('end', this.endSpy)
          rs.on('close', this.verify.bind(this, rs, this.sourceValues, done))
        }.bind(this))
      }.bind(this))
    }
})
