/*!
 * @techmely/utils
 * Copyright(c) 2021-2024 Techmely <techmely.creation@gmail.com>
 * MIT Licensed
 */


// src/orderMap.ts
var OrderedMap = class _OrderedMap {
  constructor(content) {
    this.content = content;
  }
  // Return a map with the given content. If null, create an empty
  // map. If given an ordered map, return that map itself. If given an
  // object, create a map from the object's properties.
  static from(value) {
    if (value instanceof _OrderedMap)
      return value;
    const content = [];
    if (value)
      for (const prop in value)
        content.push(prop, value[prop]);
    return new _OrderedMap(content);
  }
  /**
   * the amount of keys in this map.
   */
  get size() {
    return this.content.length >> 1;
  }
  #find(key) {
    for (let i = 0; i < this.content.length; i += 2)
      if (this.content[i] === key)
        return i;
    return -1;
  }
  /**
   * Retrieve the value stored under `key`, or return undefined when no such key exists.
   */
  get(key) {
    const found = this.#find(key);
    return found === -1 ? void 0 : this.content[found + 1];
  }
  /**
   * Create a new map by replacing the value of `key` with a new value,
   * or adding a binding to the end of the map. If `newKey` is given, the key of the binding will be replaced with that key.
   */
  update(key, value, newKey) {
    const self = newKey && newKey !== key ? this.remove(newKey) : this;
    const found = self.#find(key);
    const content = self.content.slice();
    if (found === -1) {
      content.push(newKey || key, value);
    } else {
      content[found + 1] = value;
      if (newKey)
        content[found] = newKey;
    }
    return new _OrderedMap(content);
  }
  /**
   * Return a map with the given key removed, if it existed.
   */
  remove(key) {
    const found = this.#find(key);
    if (found === -1)
      return this;
    const content = this.content.slice();
    content.splice(found, 2);
    return new _OrderedMap(content);
  }
  /**
   * Add a new key to the start of the map.
   */
  addToStart(key, value) {
    return new _OrderedMap([key, value].concat(this.remove(key).content));
  }
  /**
   * Add a new key to the end of the map.
   */
  addToEnd(key, value) {
    const content = this.remove(key).content.slice();
    content.push(key, value);
    return new _OrderedMap(content);
  }
  /**
   * Add the given key/value before `place`. If `place` is not found, the new key is added to the end.
   */
  addBefore(place, key, value) {
    const without = this.remove(key);
    const content = without.content.slice();
    const found = without.#find(place);
    content.splice(found === -1 ? content.length : found, 0, key, value);
    return new _OrderedMap(content);
  }
  /**
   * Call the given function for each key/value pair in the map, in order
   */
  forEach(fn) {
    for (let i = 0; i < this.content.length; i += 2) {
      fn(this.content[i], this.content[i + 1]);
    }
  }
  /**
   * Create a new map by prepending the keys in this map that don't appear in `map` before the keys in `map`
   */
  prepend(map) {
    map = _OrderedMap.from(map);
    if (!map.size)
      return this;
    return new _OrderedMap(map.content.concat(this.subtract(map).content));
  }
  /**
   * Create a new map by appending the keys in this map that don't appear in `map` after the keys in `map`.
   */
  append(map) {
    map = _OrderedMap.from(map);
    if (!map.size)
      return this;
    return new _OrderedMap(this.subtract(map).content.concat(map.content));
  }
  /**
   * Create a map containing all the keys in this map that don't appear in `map`
   */
  subtract(map) {
    let instance = this;
    map = _OrderedMap.from(map);
    for (let i = 0; i < map.content.length; i += 2) {
      instance = instance.remove(map.content[i]);
    }
    return instance;
  }
  /**
   * Turn ordered map into a plain object.
   */
  toObject() {
    const result = {};
    this.forEach((key, value) => {
      result[key] = value;
    });
    return result;
  }
};

export { OrderedMap };
