// @flow

// Copyright 2016 Attic Labs, Inc. All rights reserved.
// Licensed under the Apache License, version 2.0:
// http://www.apache.org/licenses/LICENSE-2.0

import BuzHash from './buzhash.js';
import {invariant} from './assert.js';

type getDataFn<T> = (item: T) => (Uint8Array | number);

export default class BuzHashBoundaryChecker<T> {
  windowSize: number;
  valueSize: number;
  pattern: number;
  _hash: BuzHash;
  _getData: getDataFn<T>;

  constructor(windowSize: number, valueSize: number, pattern: number, getData: getDataFn) {
    this._hash = new BuzHash(windowSize * valueSize);
    this.windowSize = windowSize;
    this.valueSize = valueSize;
    this.pattern = pattern;
    this._getData = getData;
  }

  write(item: T): boolean {
    const data = this._getData(item);
    return typeof data === 'number' ? this._writeByte(data) : this._writeBytes(data);
  }

  _writeBytes(bytes: Uint8Array): boolean {
    invariant(this.valueSize === bytes.length);
    this._hash.write(bytes);
    return this._checkPattern();
  }

  _writeByte(b: number): boolean {
    this._hash.hashByte(b);
    return this._checkPattern();
  }

  _checkPattern(): boolean {
    const sum = this._hash.sum32;
    const result = (sum & this.pattern) | 0;
    return result === this.pattern;
  }
}
