text: /*
   *  Licensed to the Apache Software Foundation (ASF) under one
   *  or more contributor license agreements.  See the NOTICE file
   *  distributed with this work for additional information
   *  regarding copyright ownership.  The ASF licenses this file
   *  to you 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.
   */
  
  /**
   * @author Jorge Bay Gondra
   */
  'use strict';
  
  const defineSupportCode = require('cucumber').defineSupportCode;
  const helper = require('../helper');
  const graphModule = require('../../lib/structure/graph');
  const graphTraversalModule = require('../../lib/process/graph-traversal');
  const Graph = graphModule.Graph;
  const __ = graphTraversalModule.statics;
  
  defineSupportCode(function (methods) {
    const cache = {};
  
    function TinkerPopWorld(){
      this.scenario = null;
      this.g = null;
      this.traversal = null;
      this.result = null;
      this.cache = null;
      this.graphName = null;
      this.parameters = {};
    }
  
    TinkerPopWorld.prototype.getData = function () {
      if (!this.graphName) {
        throw new Error("Graph name is not set");
      }
      return this.cache[this.graphName];
    };
  
    TinkerPopWorld.prototype.cleanEmptyGraph = function () {
      const connection = this.cache['empty'].connection;
      const g = new Graph().traversal().withRemote(connection);
      return g.V().drop().toList();
    };
  
    TinkerPopWorld.prototype.loadEmptyGraphData = function () {
      const cacheData = this.cache['empty'];
      const c = cacheData.connection;
      return Promise.all([ getVertices(c), getEdges(c) ]).then(values => {
        cacheData.vertices = values[0];
        cacheData.edges = values[1];
      });
    };
  
    methods.setWorldConstructor(TinkerPopWorld);
  
    methods.BeforeAll(function () {
      // load all traversals
      const promises = ['modern', 'classic', 'crew', 'grateful', 'sink', 'empty'].map(graphName => {
        let connection = null;
        if (graphName === 'empty') {
          connection = helper.getConnection('ggraph');
          return connection.open().then(() => cache['empty'] = { connection: connection });
        }
        connection = helper.getConnection('g' + graphName);
        return connection.open()
          .then(() => Promise.all([getVertices(connection), getEdges(connection)]))
          .then(values => {
            cache[graphName] = {
              connection: connection,
              vertices: values[0],
              edges: values[1]
            };
          });
      });
      return Promise.all(promises);
    });
  
    methods.AfterAll(function () {
      return Promise.all(Object.keys(cache).map(graphName => cache[graphName].connection.close()));
    });
  
    methods.Before(function (info) {
      this.scenario = info.pickle.name;
      this.cache = cache;
    });
  });
  
  function getVertices(connection) {
    const g = new Graph().traversal().withRemote(connection);
    return g.V().group().by('name').by(__.tail()).next().then(it => it.value);
  }
  
  function getEdges(connection) {
    const g = new Graph().traversal().withRemote(connection);
    return g.E().group()
      .by(__.project("o", "l", "i").by(__.outV().values("name")).by(__.label()).by(__.inV().values("name")))
      .by(__.tail())
      .next()
      .then(it => {
        const edges = {};
        Object.keys(it.value).map(key => {
          edges[getEdgeKey(key)] = it.value[key];
        });
        return edges;
      });
  }
  
  function getEdgeKey(key) {
    const o = /o=(.+?)[,}]/.exec(key)[1];
    const l = /l=(.+?)[,}]/.exec(key)[1];
    const i = /i=(.+?)[,}]/.exec(key)[1];
    return o + "-" + l + "->" + i;
  }