// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

/// Tools for manipulating HTML during code generation of analyzer and analysis
/// server.
import 'package:html/dom.dart' as dom;

/// Make a deep copy of the given HTML nodes.
List<dom.Node> cloneHtmlNodes(List<dom.Node> nodes) =>
    nodes.map((dom.Node node) => node.clone(true)).toList();

/// Return true if the given iterable contains only whitespace text nodes.
bool containsOnlyWhitespace(Iterable<dom.Node> nodes) {
  for (var node in nodes) {
    if (!isWhitespaceNode(node)) {
      return false;
    }
  }
  return true;
}

/// Get the text contents of the element, ignoring all markup.
String innerText(dom.Element parent) {
  var buffer = StringBuffer();
  void recurse(dom.Element parent) {
    for (dom.Node child in parent.nodes) {
      if (child is dom.Text) {
        buffer.write(child.text);
      } else if (child is dom.Element) {
        recurse(child);
      }
    }
  }

  recurse(parent);
  return buffer.toString();
}

/// Return true if the given node is a text node containing only whitespace, or
/// a comment.
bool isWhitespaceNode(dom.Node node) {
  if (node is dom.Element) {
    return false;
  } else if (node is dom.Text) {
    return node.text.trim().isEmpty;
  }
  // Treat all other types of nodes (e.g. comments) as whitespace.
  return true;
}

/// Create an HTML element with the given name, attributes, and child nodes.
dom.Element makeElement(
    String name, Map<dynamic, String> attributes, List<dom.Node> children) {
  var result = dom.Element.tag(name);
  result.attributes.addAll(attributes);
  for (var child in children) {
    result.append(child);
  }
  return result;
}

/// Mixin class for generating HTML.
mixin HtmlGenerator {
  List<dom.Node> _html = [];

  /// Add the given [node] to the HTML output.
  void add(dom.Node node) {
    _html.add(node);
  }

  /// Add the given [nodes] to the HTML output.
  void addAll(Iterable<dom.Node> nodes) {
    for (var node in nodes) {
      add(node);
    }
  }

  /// Execute [callback], collecting any code that is output using [write],
  /// [writeln], [add], [addAll] or [element], and return the result as a list
  /// of HTML nodes.
  List<dom.Node> collectHtml(void Function()? callback) {
    var oldHtml = _html;
    try {
      _html = <dom.Node>[];
      if (callback != null) {
        callback();
      }
      return _html;
    } finally {
      _html = oldHtml;
    }
  }

  /// Execute [callback], wrapping its output in an element with the given
  /// [name] and [attributes].
  void element(String name, Map<dynamic, String> attributes,
      [void Function()? callback]) {
    add(makeElement(name, attributes, collectHtml(callback)));
  }

  /// Output text without ending the current line.
  void write(String text) {
    _html.add(dom.Text(text));
  }

  /// Output text, ending the current line.
  void writeln([Object obj = '']) {
    write('$obj\n');
  }
}
