'use strict';
const Buffer = require('safe-buffer').Buffer;
const Transform = require('stream').Transform;
/**
 * A transform stream that waits for a sequence of "ready" bytes before emitting a ready event and emitting data events
 * @extends Transform
 * @example
To use the `Ready` parser provide a byte start sequence. After the bytes have been received a ready event is fired and data events are passed through.
```js
const SerialPort = require('serialport');
const Ready = SerialPort.parsers.Ready;
const port = new SerialPort('/dev/tty-usbserial1');
const parser = port.pipe(new Ready({ delimiter: 'READY' }));
parser.on('ready', () => console.log('the ready byte sequence has been received'))
parser.on('data', console.log); // all data after READY is received
```
 */
class ReadyParser extends Transform {
  /**
   *
   * @param {object} options
   * @param {string|Buffer|array} options.delimiter
   */
  constructor(options) {
    options = options || {};
    if (options.delimiter === undefined) {
      throw new TypeError('"delimiter" is not a bufferable object');
    }

    if (options.delimiter.length === 0) {
      throw new TypeError('"delimiter" has a 0 or undefined length');
    }

    super(options);
    this.delimiter = Buffer.from(options.delimiter);
    this.readOffset = 0;
    this.ready = false;
  }

  _transform(chunk, encoding, cb) {
    if (this.ready) {
      this.push(chunk);
      return cb();
    }
    const delimiter = this.delimiter;
    let chunkOffset = 0;
    while (this.readOffset < delimiter.length && chunkOffset < chunk.length) {
      if (delimiter[this.readOffset] === chunk[chunkOffset]) {
        this.readOffset++;
      } else {
        this.readOffset = 0;
      }
      chunkOffset++;
    }
    if (this.readOffset === delimiter.length) {
      this.ready = true;
      this.emit('ready');
      const chunkRest = chunk.slice(chunkOffset);
      if (chunkRest.length > 0) {
        this.push(chunkRest);
      }
    }
    cb();
  }
};

module.exports = ReadyParser;
