/**
 * Ported from Gutenberg code
 * @see README.md
 */

/**
 * Internal dependencies
 */
import * as children from './children';

/**
 * Browser dependencies
 */
const { TEXT_NODE, ELEMENT_NODE } = window.Node;

/**
 * A representation of a single node within a block's rich text value. If
 * representing a text node, the value is simply a string of the node value.
 * As representing an element node, it is an object of:
 *
 * 1. `type` (string): Tag name.
 * 2. `props` (object): Attributes and children array of WPBlockNode.
 *
 * @typedef {string|Object} WPBlockNode
 */

/**
 * Given an object implementing the NamedNodeMap interface, returns a plain
 * object equivalent value of name, value key-value pairs.
 * @see https://dom.spec.whatwg.org/#interface-namednodemap
 * @param {NamedNodeMap} nodeMap - NamedNodeMap to convert to object.
 * @returns {Object} Object equivalent value of NamedNodeMap.
 */
export function getNamedNodeMapAsObject(nodeMap) {
  const result = {};
  for (let i = 0; i < nodeMap.length; i++) {
    const { name, value } = nodeMap[ i ];
    result[ name ] = value;
  }

  return result;
}

/**
 * Given a DOM Element or Text node, returns an equivalent block node. Throws
 * if passed any node type other than element or text.
 * @param {Node} domNode - DOM node to convert.
 * @returns {WPBlockNode} Block node equivalent to DOM node.
 * @throws {TypeError} If non-element/text node is passed.
 */
export function fromDOM(domNode) {
  if (domNode.nodeType === TEXT_NODE) {
    return domNode.nodeValue;
  }

  if (domNode.nodeType !== ELEMENT_NODE) {
    throw new TypeError(
      'A block node can only be created from a node of type text or element.'
    );
  }

  return {
    type: domNode.nodeName.toLowerCase(),
    props: {
      ...getNamedNodeMapAsObject(domNode.attributes),
      children: children.fromDOM(domNode.childNodes),
    },
  };
}

/**
 * Object of utility functions used in managing block attribute values of
 * source `node`.
 * @see https://github.com/WordPress/gutenberg/pull/10439
 *
 * @deprecated since 4.0. The `node` source should not be used, and can be
 *             replaced by the `html` source.
 *
 * @private
 */
export default { fromDOM };
