/**
							 | 
						|
								 * Helper classes for LayoutEngine.
							 | 
						|
								 *
							 | 
						|
								 * Strategy pattern for usage of direction methods for hierarchical layouts.
							 | 
						|
								 */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Interface definition for direction strategy classes.
							 | 
						|
								 *
							 | 
						|
								 * This class describes the interface for the Strategy
							 | 
						|
								 * pattern classes used to differentiate horizontal and vertical
							 | 
						|
								 * direction of hierarchical results.
							 | 
						|
								 *
							 | 
						|
								 * For a given direction, one coordinate will be 'fixed', meaning that it is
							 | 
						|
								 * determined by level.
							 | 
						|
								 * The other coordinate is 'unfixed', meaning that the nodes on a given level
							 | 
						|
								 * can still move along that coordinate. So:
							 | 
						|
								 *
							 | 
						|
								 * - `vertical` layout: `x` unfixed, `y` fixed per level
							 | 
						|
								 * - `horizontal` layout: `x` fixed per level, `y` unfixed
							 | 
						|
								 *
							 | 
						|
								 * The local methods are stubs and should be regarded as abstract.
							 | 
						|
								 * Derived classes **must** implement all the methods themselves.
							 | 
						|
								 *
							 | 
						|
								 * @private
							 | 
						|
								 */
							 | 
						|
								class DirectionInterface {
							 | 
						|
								  /** @ignore **/
							 | 
						|
								  abstract() {
							 | 
						|
								    throw new Error("Can't instantiate abstract class!");
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * This is a dummy call which is used to suppress the jsdoc errors of type:
							 | 
						|
								   *
							 | 
						|
								   *   "'param' is assigned a value but never used"
							 | 
						|
								   *
							 | 
						|
								   * @ignore
							 | 
						|
								   **/
							 | 
						|
								  fake_use() {
							 | 
						|
								    // Do nothing special
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * Type to use to translate dynamic curves to, in the case of hierarchical layout.
							 | 
						|
								   * Dynamic curves do not work for these.
							 | 
						|
								   *
							 | 
						|
								   * The value should be perpendicular to the actual direction of the layout.
							 | 
						|
								   *
							 | 
						|
								   * @return {string} Direction, either 'vertical' or 'horizontal'
							 | 
						|
								   */
							 | 
						|
								  curveType() { return this.abstract(); }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * Return the value of the coordinate that is not fixed for this direction.
							 | 
						|
								   *
							 | 
						|
								   * @param {Node} node The node to read
							 | 
						|
								   * @return {number} Value of the unfixed coordinate
							 | 
						|
								   */
							 | 
						|
								  getPosition(node) { this.fake_use(node); return this.abstract(); }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * Set the value of the coordinate that is not fixed for this direction.
							 | 
						|
								   *
							 | 
						|
								   * @param {Node} node The node to adjust
							 | 
						|
								   * @param {number} position
							 | 
						|
								   * @param {number} [level] if specified, the hierarchy level that this node should be fixed to
							 | 
						|
								   */
							 | 
						|
								  setPosition(node, position, level = undefined) { this.fake_use(node, position, level); this.abstract(); }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * Get the width of a tree.
							 | 
						|
								   *
							 | 
						|
								   * A `tree` here is a subset of nodes within the network which are not connected to other nodes,
							 | 
						|
								   * only among themselves. In essence, it is a sub-network.
							 | 
						|
								   *
							 | 
						|
								   * @param {number} index The index number of a tree
							 | 
						|
								   * @return {number} the width of a tree in the view coordinates
							 | 
						|
								   */
							 | 
						|
								  getTreeSize(index) { this.fake_use(index); return this.abstract(); }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * Sort array of nodes on the unfixed coordinates.
							 | 
						|
								   *
							 | 
						|
								   * @param {Array.<Node>} nodeArray array of nodes to sort
							 | 
						|
								   */
							 | 
						|
								  sort(nodeArray) { this.fake_use(nodeArray); this.abstract(); }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * Assign the fixed coordinate of the node to the given level
							 | 
						|
								   *
							 | 
						|
								   * @param {Node} node The node to adjust
							 | 
						|
								   * @param {number} level The level to fix to
							 | 
						|
								   */
							 | 
						|
								  fix(node, level) { this.fake_use(node, level); this.abstract(); }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * Add an offset to the unfixed coordinate of the given node. 
							 | 
						|
								   *
							 | 
						|
								   * @param {NodeId} nodeId Id of the node to adjust
							 | 
						|
								   * @param {number} diff Offset to add to the unfixed coordinate
							 | 
						|
								   */
							 | 
						|
								  shift(nodeId, diff) { this.fake_use(nodeId, diff); this.abstract(); }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Vertical Strategy
							 | 
						|
								 *
							 | 
						|
								 * Coordinate `y` is fixed on levels, coordinate `x` is unfixed.
							 | 
						|
								 *
							 | 
						|
								 * @extends DirectionInterface
							 | 
						|
								 * @private
							 | 
						|
								 */
							 | 
						|
								class VerticalStrategy extends DirectionInterface {
							 | 
						|
								  /**
							 | 
						|
								   * Constructor
							 | 
						|
								   *
							 | 
						|
								   * @param {Object} layout reference to the parent LayoutEngine instance.
							 | 
						|
								   */
							 | 
						|
								  constructor(layout) {
							 | 
						|
								    super();
							 | 
						|
								    this.layout = layout;
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /** @inheritdoc */
							 | 
						|
								  curveType() {
							 | 
						|
								    return 'horizontal';
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /** @inheritdoc */
							 | 
						|
								  getPosition(node) {
							 | 
						|
								    return node.x;
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /** @inheritdoc */
							 | 
						|
								  setPosition(node, position, level = undefined) {
							 | 
						|
								    if (level !== undefined) {
							 | 
						|
								      this.layout.hierarchical.addToOrdering(node, level);
							 | 
						|
								    }
							 | 
						|
								    node.x = position;
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /** @inheritdoc */
							 | 
						|
								  getTreeSize(index) {
							 | 
						|
								    let res = this.layout.hierarchical.getTreeSize(this.layout.body.nodes, index);
							 | 
						|
								    return {min: res.min_x, max: res.max_x};
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /** @inheritdoc */
							 | 
						|
								  sort(nodeArray) {
							 | 
						|
								    nodeArray.sort(function(a, b) {
							 | 
						|
								      // Test on 'undefined' takes care of divergent behaviour in chrome
							 | 
						|
								      if (a.x === undefined || b.x === undefined) return 0;   // THIS HAPPENS
							 | 
						|
								      return a.x - b.x;
							 | 
						|
								    });
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /** @inheritdoc */
							 | 
						|
								  fix(node, level) {
							 | 
						|
								    node.y = this.layout.options.hierarchical.levelSeparation * level;
							 | 
						|
								    node.options.fixed.y = true;
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /** @inheritdoc */
							 | 
						|
								  shift(nodeId, diff) {
							 | 
						|
								    this.layout.body.nodes[nodeId].x += diff;
							 | 
						|
								  }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Horizontal Strategy
							 | 
						|
								 *
							 | 
						|
								 * Coordinate `x` is fixed on levels, coordinate `y` is unfixed.
							 | 
						|
								 *
							 | 
						|
								 * @extends DirectionInterface
							 | 
						|
								 * @private
							 | 
						|
								 */
							 | 
						|
								class HorizontalStrategy extends DirectionInterface {
							 | 
						|
								  /**
							 | 
						|
								   * Constructor
							 | 
						|
								   *
							 | 
						|
								   * @param {Object} layout reference to the parent LayoutEngine instance.
							 | 
						|
								   */
							 | 
						|
								  constructor(layout) {
							 | 
						|
								    super();
							 | 
						|
								    this.layout = layout;
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /** @inheritdoc */
							 | 
						|
								  curveType() {
							 | 
						|
								    return 'vertical';
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /** @inheritdoc */
							 | 
						|
								  getPosition(node) {
							 | 
						|
								    return node.y;
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /** @inheritdoc */
							 | 
						|
								  setPosition(node, position, level = undefined) {
							 | 
						|
								    if (level !== undefined) {
							 | 
						|
								      this.layout.hierarchical.addToOrdering(node, level);
							 | 
						|
								    }
							 | 
						|
								    node.y = position;
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /** @inheritdoc */
							 | 
						|
								  getTreeSize(index) {
							 | 
						|
								    let res = this.layout.hierarchical.getTreeSize(this.layout.body.nodes, index);
							 | 
						|
								    return {min: res.min_y, max: res.max_y};
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /** @inheritdoc */
							 | 
						|
								  sort(nodeArray) {
							 | 
						|
								    nodeArray.sort(function(a, b) {
							 | 
						|
								      // Test on 'undefined' takes care of divergent behaviour in chrome
							 | 
						|
								      if (a.y === undefined || b.y === undefined) return 0;   // THIS HAPPENS
							 | 
						|
								      return a.y - b.y;
							 | 
						|
								    });
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /** @inheritdoc */
							 | 
						|
								  fix(node, level) {
							 | 
						|
								    node.x = this.layout.options.hierarchical.levelSeparation * level;
							 | 
						|
								    node.options.fixed.x = true;
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /** @inheritdoc */
							 | 
						|
								  shift(nodeId, diff) {
							 | 
						|
								    this.layout.body.nodes[nodeId].y += diff;
							 | 
						|
								  }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								export {HorizontalStrategy, VerticalStrategy};
							 |