module.exports = TapConsumer

// pipe a stream into this that's emitting tap-formatted data,
// and it'll emit "data" events with test objects or comment strings
// and an "end" event with the final results.

var yamlish = require("yamlish")
  , Results = require("./tap-results")
  , inherits = require("inherits")

TapConsumer.decode = TapConsumer.parse = function (str) {
  var tc = new TapConsumer
    , list = []
  tc.on("data", function (res) {
    list.push(res)
  })
  tc.end(str)
  tc.results.list = list
  return tc.results
}

inherits(TapConsumer, require("stream").Stream)
function TapConsumer () {
  if (!(this instanceof TapConsumer)) {
    return new TapConsumer
  }

  TapConsumer.super.call(this)
  this.results = new Results
  this.readable = this.writable = true

  this.on("data", function (res) {
    if (typeof res === "object") this.results.add(res)
  })

  this._plan = null
  this._buffer = ""
  this._indent = []
  this._current = null
  this._actualCount = 0
  this._passed = []
  this._failed = []
  //console.error("TapConsumer ctor done")
}

TapConsumer.prototype.bailedOut = false

TapConsumer.prototype.write = function (chunk) {
  if (!this.writable) this.emit("error", new Error("not writable"))
  if (this.bailedOut) return true

  this._buffer = this._buffer + chunk
  // split it up into lines.
  var lines = this._buffer.split(/\r?\n/)
  // ignore the last line, since it might be incomplete.
  this._buffer = lines.pop()

  for (var i = 0, l = lines.length; i < l; i ++) {
    //console.error([i, lines[i]])
    // see if it's indented.
    var line = lines[i]
      , spaces = (this._indent.length && !line.trim())
               || line.match(/^\s/)
    // at this level, only interested in fully undented stuff.
    if (spaces) {
      var c = i
      while (c < l && (!lines[c].trim() || lines[c].match(/^\s/))) {
        this._indent.push(lines[c++])
      }
      //console.error(c-i, "indented", this._indent, this._current)
      i = c - 1
      continue
    }
    // some kind of line.  summary, ok, notok, comment, or garbage.
    // this also finishes parsing any of the indented lines from before
    this._parseLine(line)
  }
  return true
}

TapConsumer.prototype.end = function () {
  // finish up any hanging indented sections or final buffer
  if (this._buffer.match(/^\s/)) this._indent.push(this.buffer)
  else this._parseLine(this._buffer)

  if (!this.bailedOut &&
      this._plan !== null &&
      this.results.testsTotal !== this._plan) {
    while (this._actualCount < this._plan) {
      this.emit("data", {ok: false, name:"MISSING TEST",
                         id:this._actualCount ++ })
    }
  }

  this._parseLine("")
  this._buffer = ""
  this.writable = false
  this.emit("end", null, this._actualCount, this._passed)
}

TapConsumer.prototype._parseLine = function (line) {
  if (this.bailedOut) return
  //console.error("_parseLine", [line])
  // if there are any indented lines, and there is a
  // current object already, then they belong to it.
  // if there is not a current object, then they'r