/// Support code for the tests in this directory.
library support;

import 'dart:collection';
import 'dart:io';

import 'package:path/path.dart' as p;
import 'package:html/src/treebuilder.dart';
import 'package:html/dom.dart';
import 'package:html/dom_parsing.dart';

typedef TreeBuilder TreeBuilderFactory(bool namespaceHTMLElements);

Map<String, TreeBuilderFactory> _treeTypes;
Map<String, TreeBuilderFactory> get treeTypes {
  if (_treeTypes == null) {
    // TODO(jmesserly): add DOM here once it's implemented
    _treeTypes = {"simpletree": (useNs) => new TreeBuilder(useNs)};
  }
  return _treeTypes;
}

final testDir = p.join(p.dirname(p.fromUri(Platform.packageConfig)), 'test');

final testDataDir = p.join(testDir, 'data');

Iterable<String> getDataFiles(String subdirectory) {
  var dir = new Directory(p.join(testDataDir, subdirectory));
  return dir.listSync().where((f) => f is File).map((f) => f.path);
}

// TODO(jmesserly): make this class simpler. We could probably split on
// "\n#" instead of newline and remove a lot of code.
class TestData extends IterableBase<Map> {
  final String _text;
  final String newTestHeading;

  TestData(String filename, [this.newTestHeading = "data"])
      // Note: can't use readAsLinesSync here because it splits on \r
      : _text = new File(filename).readAsStringSync();

  // Note: in Python this was a generator, but since we can't do that in Dart,
  // it's easier to convert it into an upfront computation.
  Iterator<Map> get iterator => _getData().iterator;

  List<Map> _getData() {
    var data = <String, String>{};
    String key;
    var result = <Map>[];
    var lines = _text.split('\n');
    // Remove trailing newline to match Python
    if (lines.last == '') {
      lines.removeLast();
    }
    for (var line in lines) {
      var heading = sectionHeading(line);
      if (heading != null) {
        if (data.isNotEmpty && heading == newTestHeading) {
          // Remove trailing newline
          data[key] = data[key].substring(0, data[key].length - 1);
          result.add(normaliseOutput(data));
          data = <String, String>{};
        }
        key = heading;
        data[key] = "";
      } else if (key != null) {
        data[key] = '${data[key]}$line\n';
      }
    }

    if (data.isNotEmpty) {
      result.add(normaliseOutput(data));
    }
    return result;
  }

  /// If the current heading is a test section heading return the heading,
  /// otherwise return null.
  static String sectionHeading(String line) {
    return line.startsWith("#") ? line.substring(1).trim() : null;
  }

  static Map normaliseOutput(Map data) {
    // Remove trailing newlines
    data.forEach((key, value) {
      if (value.endsWith("\n")) {
        data[key] = value.substring(0, value.length - 1);
      }
    });
    return data;
  }
}

/// Serialize the [document] into the html5 test data format.
testSerializer(document) {
  return (new TestSerializer()..visit(document)).toString();
}

/// Serializes the DOM into test format. See [testSerializer].
class TestSerializer extends TreeVisitor {
  final StringBuffer _str;
  int _indent = 0;
  String _spaces = '';

  TestSerializer() : _str = new StringBuffer();

  String toString() => _str.toString();

  int get indent => _indent;

  set indent(int value) {
    if (_indent == value) return;

    var arr = new List<int>(value);
    for (int i = 0; i < value; i++) {
      arr[i] = 32;
    }
    _spaces = new String.fromCharCodes(arr);
    _indent = value;
  }

  void _newline() {
    if (_str.length > 0) _str.write('\n');
    _str.write('|$_spaces');
  }

  visitNodeFallback(Node node) {
    _newline();
    _str.write(node);
    visitChildren(node);
  }

  visitChildren(Node node) {
    indent += 2;
    for (var child in node.nodes) visit(child);
    indent -= 2;
  }

  visitDocument(node) => _visitDocumentOrFragment(node);

  _visitDocumentOrFragment(node) {
    indent += 1;
    for (var child in node.nodes) visit(child);
    indent -= 1;
  }

  visitDocumentFragment(DocumentFragment node) =>
      _visitDocumentOrFragment(node);

  visitElement(Element node) {
    _newline();
    _str.write(node);
    if (node.attributes.isNotEmpty) {
      indent += 2;
      var keys = new List.from(node.attributes.keys);
      keys.sort((x, y) => x.compareTo(y));
      for (var key in keys) {
        var v = node.attributes[key];
        if (key is AttributeName) {
          AttributeName attr = key;
          key = "${attr.prefix} ${attr.name}";
        }
        _newline();
        _str.write('$key="$v"');
      }
      indent -= 2;
    }
    visitChildren(node);
  }
}
