// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// JavaScript functions used by the Chrome debugging protocol DOM domain:
// https://developer.chrome.com/devtools/docs/protocol/1.1/dom

devtoolsBackend.dom = {};

// Creates and returns a new Node object corresponding to the document node,
// including its children up to a default depth.
// https://developer.chrome.com/devtools/docs/protocol/1.1/dom#command-getDocument
devtoolsBackend.dom.getDocument = function(params) {
  var result = {};
  result.root = this.getNodeWithChildren(document, 2);
  result.root.documentURL = document.URL;
  return JSON.stringify(result);
}

// Creates an array of Node objects corresponding to the children of the
// specified node, and returns them via an event. A depth may be specified,
// where a negative depth means to return all descendants. If no depth is
// specified, the default is 1, a single level.
// https://developer.chrome.com/devtools/docs/protocol/1.1/dom#command-requestChildNodes
devtoolsBackend.dom.requestChildNodes = function(params) {
  var node = this.findNode(params);
  var depth = params.depth || 1;
  var result = {};
  result.parentId = params.nodeId;
  result.nodes = this.getChildNodes(node, depth);

  // Send the result via an event, and an empty response.
  devtoolsBackend.sendEvent('DOM.setChildNodes', JSON.stringify(result));
  return '{}';
}

// Finds the node corresponding to a remote objectId. Also sends all nodes on
// the path from the requested one to the root as a series of setChildNodes
// events.
// https://developer.chrome.com/devtools/docs/protocol/1.1/dom#command-requestNode
devtoolsBackend.dom.requestNode = function(params) {
  var node = this.findNode(params);
  var nodeInfo = new this.Node(node);
  var result = {};
  result.nodeId = nodeInfo.nodeId;

  var parent = node.parentNode;
  while (parent) {
    var parentInfo = new this.Node(parent);
    var params = {};
    params.parentId = parentInfo.nodeId;
    params.nodes = [];
    params.nodes.push(nodeInfo);
    devtoolsBackend.sendEvent('DOM.setChildNodes', JSON.stringify(params));
    node = parent;
    nodeInfo = parentInfo;
    parent = parent.parentNode;
  }

  return JSON.stringify(result);
}

// Returns a Runtime.RemoteObject corresponding to a node.
// https://developer.chrome.com/devtools/docs/protocol/1.1/dom#command-resolveNode
devtoolsBackend.dom.resolveNode = function(params) {
  var node = this.findNode(params);
  var returnByValue = true;
  var result = {};
  result.object = new devtoolsBackend.runtime.RemoteObject(
        node, params.objectGroup, returnByValue);

  return JSON.stringify(result);
}

// Returns the bounding box of a node. Used for node highlighting.
devtoolsBackend.dom.getBoundingClientRect = function(params) {
  var node = this.findNode(params);
  return JSON.stringify(node.getBoundingClientRect());
}

// Creates and returns a Node object that represents the specified node.
// Adds the node's children up to the specified depth. A negative depth will
// cause all descendants to be added.
devtoolsBackend.dom.getNodeWithChildren = function(node, depth) {
  var result = new this.Node(node);
  if (depth != 0) {
    result.children = this.getChildNodes(node, depth);
  }
  return result;
}

// Creates and returns an array of Node objects corresponding to the children
// of the specified node, recursing on each on up to the specified depth.
devtoolsBackend.dom.getChildNodes = function(node, depth) {
  if (!node.childNodes) {
    return [];
  }

  var children = [];
  for (var i = 0; i < node.childNodes.length; i++) {
    var child = node.childNodes[i];
    if (!this.nodeIsIgnorable(child)) {
      children.push(this.getNodeWithChildren(child, depth - 1));
    }
  }
  return children;
}

// Finds a node specified by either nodeId or objectId (to get a node
// from its corresponding remote object).
devtoolsBackend.dom.findNode = function(params) {
  if (params.nodeId != null) {
    return this.nodeStore[params.nodeId];
  }

  if (params.objectId != null) {
    return devtoolsBackend.runtime.getObject(params.objectId);
  }

  // Either nodeId or objectId must be specified.
  return null;
}

// Adds a node to the internal node store and returns a unique id that can
// be used to access it again.
devtoolsBackend.dom.addNode = function(node) {
  // If we've already added this node, then use the same nodeId.
  for (var i = 0; i < this.nodeStore.length; i++) {
    if (this.nodeStore[i] === node) {
      return i;
    }
  }

  var nodeId = this.nextNodeId++;
  this.nodeStore[nodeId] = node;
  return nodeId;
}

// Whether a node is ignorable. We ignore text nodes with white-space only
// content, as they just clutter up the DOM tree.
devtoolsBackend.dom.nodeIsIgnorable = function(node) {
  return node.nodeType == Node.TEXT_NODE &&
      !(/[^\t\n\r ]/.test(node.textContent));
}

// Creates a new Node object, which is the type used to return information
// about nodes to devtools. All Node objects are added to |nodeStore|,
// so they can be retrieved later via |nodeId|.
devtoolsBackend.dom.Node = function(node) {
  this.nodeId = devtoolsBackend.dom.addNode(node);
  this.localName = node.nodeName;
  this.nodeName = node.nodeName;
  this.nodeType = node.nodeType;
  this.nodeValue = node.nodeValue || "";
  this.childNodeCount = node.childNodes.length;

  if (node.attributes) {
    this.attributes = [];
    for (var i = 0; i < node.attributes.length; i++) {
      this.attributes.push(node.attributes[i].name);
      this.attributes.push(node.attributes[i].value);
    }
  }
}

devtoolsBackend.dom.nodeStore = [];
devtoolsBackend.dom.nextNodeId = 0;