/**
 *  Bucket Interface
 *
 *  Copyright (C) 2010-2020 R-T Specialty, LLC.
 *
 *  This file is part of the Liza Data Collection Framework
 *
 *  liza is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * There's a hole in my bucket, dear Liza, dear Liza [...]
 */

type BucketValue = unknown;
type BucketFieldValue = BucketValue[];
type BucketData = Record<string, BucketFieldValue>;

/**
 * Represents an object that is able to store key-value data with multiple
 * indexes per value
 */
export interface Bucket {
  /**
   * Explicitly sets the contents of the bucket
   *
   * @param data - associative array of the data
   *
   * @return self
   */
  setValues(data: CommonObject): this;

  /**
   * Overwrites values in the original bucket
   *
   * @param data - associative array of the data
   *
   * @return self
   */
  overwriteValues(values: CommonObject): this;

  /**
   * Clears all data from the bucket
   *
   * @return self
   */
  clear(): this;

  /**
   * Calls a function for each of the values in the bucket
   *
   * Note: This format is intended to be consistent with Array.forEach()
   *
   * @param callback - function to call for each value in the bucket
   *
   * @return self
   */
  each(callback: (val: BucketData, key: string) => void): this;

  /**
   * Calls a function for each of the values in the bucket matching the given
   * predicate
   *
   * @param pred     - predicate
   * @param callback - function to call for each value in the bucket
   *
   * @return self
   */
  filter(
    pred: (key: string) => unknown,
    callback: (val: BucketData, key: string) => void
  ): this;

  /**
   * Returns the data for the requested field
   *
   * @param name - field name (with or without trailing brackets)
   *
   * @return data for the field, or empty array if none
   */
  getDataByName(name: string): Array<string>;

  /**
   * Return raw bucket data
   *
   * TODO: remove; breaks encapsulation
   *
   * @return raw bucket data
   */
  getData(): CommonObject;

  /**
   * Returns the data as a JSON string
   *
   * @return data represented as JSON
   */
  getDataJson(): string;
}
