text: 'use strict';
  
  const {Transform} = require('stream');
  const Assembler = require('../Assembler');
  
  class Counter {
    constructor(initialDepth) {
      this.depth = initialDepth;
    }
    startObject() {
      ++this.depth;
    }
    endObject() {
      --this.depth;
    }
    startArray() {
      ++this.depth;
    }
    endArray() {
      --this.depth;
    }
  }
  
  class StreamBase extends Transform {
    constructor(options) {
      super(Object.assign({}, options, {writableObjectMode: true, readableObjectMode: true}));
      this.objectFilter = options && options.objectFilter;
      this.includeUndecided = options && options.includeUndecided;
      if (typeof this.objectFilter != 'function') {
        this._filter = this._transform;
      }
      this._assembler = new Assembler();
      this._transform = this._wait || this._filter;
    }
  
    _transform(chunk, encoding, callback) {
      if (this._assembler[chunk.name]) {
        this._assembler[chunk.name](chunk.value);
        if (this._assembler.depth === this._level) {
          this._push();
        }
      }
      callback(null);
    }
  
    _filter(chunk, encoding, callback) {
      if (this._assembler[chunk.name]) {
        this._assembler[chunk.name](chunk.value);
        const result = this.objectFilter(this._assembler);
        if (result) {
          if (this._assembler.depth === this._level) {
            this._push();
            this._transform = this._filter;
          }
          this._transform = this._accept;
          return callback(null);
        }
        if (result === false) {
          this._saved_assembler = this._assembler;
          this._assembler = new Counter(this._saved_assembler.depth);
          this._saved_assembler.dropToLevel(this._level);
          if (this._assembler.depth === this._level) {
            this._assembler = this._saved_assembler;
            this._transform = this._filter;
          }
          this._transform = this._reject;
          return callback(null);
        }
        if (this._assembler.depth === this._level) {
          this._push(!this.includeUndecided);
        }
      }
      callback(null);
    }
  
    _accept(chunk, encoding, callback) {
      if (this._assembler[chunk.name]) {
        this._assembler[chunk.name](chunk.value);
        if (this._assembler.depth === this._level) {
          this._push();
          this._transform = this._filter;
        }
      }
      callback(null);
    }
  
    _reject(chunk, encoding, callback) {
      if (this._assembler[chunk.name]) {
        this._assembler[chunk.name](chunk.value);
        if (this._assembler.depth === this._level) {
          this._assembler = this._saved_assembler;
          this._transform = this._filter;
        }
      }
      callback(null);
    }
  }
  
  module.exports = StreamBase;
  