'use strict';

// --------------------------------------------------------------------
// Imports
// --------------------------------------------------------------------

var assert = require('assert');
var jsdom = require('jsdom');
var test = require('tape');

var ohm = require('..');
var parseTree = require('../visualizer/parseTree');

// --------------------------------------------------------------------
// Helpers
// --------------------------------------------------------------------

var ArrayProto = Array.prototype;

function label(node) {
  var labelNode = node.firstChild;
  assert(labelNode.classList.contains('label'),
         "Expected node with class 'label', found '" + labelNode.className + "'");
  return labelNode.textContent;
}

function flattenParseNodes(nodeOrArray) {
  if (Array.isArray(nodeOrArray)) {
    var result = [];
    for (var i = 0; i < nodeOrArray.length; ++i) {
      result = result.concat(flattenParseNodes(nodeOrArray[i]));
    }
    return result;
  } else if (nodeOrArray.classList.contains('hidden')) {
    return visualChildren(nodeOrArray);
  } else {
    assert(nodeOrArray.classList.contains('pexpr'), 'expected pexpr');
    return nodeOrArray;
  }
}

// Return the DOM elements which *visually* the children of the given node in the parse tree.
// Because the labels of some nodes are omitted from the tree, the parse tree does not have a
// 1-to-1 correspondence to the DOM tree.
function visualChildren(node) {
  if (node.children.length === 1) {
    return [];
  }
  var childrenDiv = node.lastChild;
  assert(childrenDiv.classList.contains('children'),
         "Expected node with class 'children', found '" + childrenDiv.className + "'");
  return flattenParseNodes(ArrayProto.slice.call(childrenDiv.children));
}

// Recursively compares the DOM tree rooted at `traceNode` with an expected value.
// `expected` is an Array of the form ['someLabel', children...].
function compareTree(t, traceNode, expected) {
  // The first element in `expected` is the expected label.
  t.equal(label(traceNode), expected[0]);

  // The remaining elements are the expected children.
  var childNodes = visualChildren(traceNode);
  assert.equal(childNodes.length, expected.length - 1, 'wrong number of children');

  expected.slice(1).forEach(function(obj, i) {
    compareTree(t, childNodes[i], obj);
  });
}

function compareTrace(t, resultNode, expected) {
  assert.equal(resultNode.children.length, 1, 'single node at root');
  compareTree(t, resultNode.firstChild, expected);
}

// --------------------------------------------------------------------
// Tests
// --------------------------------------------------------------------

// Stripped down DOM containing only the markup that is required to show the parse tree.
var HTML = '<div id="expandedInput"></div><div id="parseResults"></div>' +
           '<div id="measuringDiv"><div class="pexpr"></div></div>';

test('simple parse tree', function(t) {
  var doc = jsdom.jsdom(HTML);
  var refreshParseTree = parseTree(ohm, doc, null, null);
  var g = ohm.grammar('G { start = letter digit+  -- x\n| digit }');

  refreshParseTree(null, g, g.trace('a99'), false);
  t.equal(doc.querySelector('#expandedInput').textContent, 'a99');

  compareTrace(t, doc.querySelector('#parseResults'), [
    'start', [
      'start_x',
        ['letter', ['lower']],
        ['digit+', ['digit', ['"0".."9"']],
        ['digit', ['"0".."9"']]]]
  ]);

  t.end();
});

@@ -1783,22 +1783,24 @@
 rsively 
-compar
+serializ
 es the D
@@ -1832,48 +1832,34 @@
 ode%60
- with an expected value.%0A// %60expected%60 i
+.%0A// For each node, return
 s an
@@ -1879,19 +1879,18 @@
  form %5B'
-som
+th
 eLabel',
@@ -1908,212 +1908,199 @@
 .%5D.%0A
-function compareTree(t, traceNode, expected) %7B%0A  // The first element in %60expected%60 is the expected label.%0A  t.equal(label(traceNode), expected%5B0%5D);%0A%0A  // The remaining elements are the expected children.
+// NOTE: The serialized form represents the visual structure of the tree, rather than the%0A// action structure of the DOM -- see %60visualChildren%60.%0Afunction serializeTree(traceNode, expected) %7B
 %0A  v
@@ -2107,21 +2107,19 @@
 ar child
-Nodes
+ren
  = visua
@@ -2146,181 +2146,68 @@
 ;%0A  
-assert.equal(childNodes.length, expected.length - 1, 'wrong number of children');%0A%0A  expected.slice(1).forEach(function(obj, i) %7B%0A    compareTree(t, childNodes%5Bi%5D, obj);%0A  %7D
+return %5Blabel(traceNode)%5D.concat(children.map(serializeTree)
 );%0A%7D
@@ -2217,32 +2217,31 @@
 unction 
-compar
+serializ
 eTrace(
-t, 
 resultNo
@@ -2238,34 +2238,24 @@
 e(resultNode
-, expected
 ) %7B%0A  assert
@@ -2322,23 +2322,29 @@
 ;%0A  
-compar
+return serializ
 eTree(
-t, 
 resu
@@ -2360,26 +2360,16 @@
 rstChild
-, expected
 );%0A%7D%0A%0A//
@@ -3079,24 +3079,35 @@
 %0A%0A  
-compar
+t.deepEqual(serializ
 eTrace(
-t, 
 doc.
@@ -3136,16 +3136,17 @@
 esults')
+)
 , %5B%0A    

Modify test to just use deepEqual for comparison.