<commit_before>/*!
 * TAB 切换
 * tommyshao <jinhong.shao@frontpay.cn>
 * Reference bootstrap.tab.js
 * API:
 *      $(element).on('closed.ui.alert', function(e, obj){});
 */

+(function($) {
    'use strict';

    var tab = '[data-toggle="tab"],.tabs-btn';

    // 构造函数
    // ===============
    var Tab = function(element) {
        this.$el = $(element);
    };

    Tab.VERSION = '1.0.0';

    // 动画过渡时间
    Tab.TRANSITION_DURATION = 150;

    // 关闭
    // ===============
    Tab.prototype.show = function( ) {
        var $this = this.$el;
        var $ul = $this.closest('.tabs');
        var selector = $this.data('target');

        if (!selector) { // a标签
            selector = $this.attr('href')
            selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
        }

        if($this.hasClass('active')) return;

        var $previous = $ul.find('.active a');
        var hideEvent = $.Event('hide.ui.tab', {
            relatedTarget: $this[0]
        });
        var showEvent = $.Event('show.ui.tab', {
            relatedTarget: $previous[0]
        });

        $previous.trigger(hideEvent);
        $this.trigger(showEvent);

        if(showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return;

        var $target = $(selector);

        this.activate($this.closest('li'), $ul);
        this.activate($target, $target.parent(), function(){
            $previous.trigger({
                type: 'hidden.ui.tab',
                relatedTarget: $this[0]
            });
            $this.trigger({
                type: 'shown.ui.tab',
                relatedTarget: $previous[0]
            })
        })
    };

    Tab.prototype.activate = function (element, container, callback) {
        var $active = container.find('> .active');
        var transition = callback
                            && $.support.transition
                            && (($active.length && $active.hasClass('fade')) || !!container.find('> .fade').length)

        function next() {
            $active.removeClass('active').find(tab).attr('aria-expanded', false);

            element.addClass('active').find(tab).attr('aria-expanded', true);

            if(transition) {
                element[0].offsetWidth;
                element.addClass('in');
            } else {
                element.removeClass('fade');
            }

            callback && callback();
        }

        $active.length && transition ?
                $active.one('uiTransitionEnd', next).emulateTransitionEnd(Tab.TRANSITION_DURATION)
                :
                next();
        $active.removeClass('in');
    };

    // 插件定义
    //======================
    function Plugin(option) {
        return $(this).each(function () {
            var $this = $(this);
            var data = $this.data('ui.tab');

            if(!data) $this.data('ui.tab', (data = new Tab(this)));
            if(typeof option == 'string') data[option] && data[option]();
        })
    }

    // jQuery 插件扩展
    $.fn.tab = Plugin;
    $.fn.tab.Constructor = Tab;

    // 元素插件绑定
    // ====================
    var clickHandler = function(e) {
        if(!$(e.target).hasClass('tab-disabled')) e.preventDefault();
        Plugin.call($(this), 'show')
    };

    $(function(){
        $(document).on('click.ui.tab', tab, clickHandler)
    })

})( jQuery );
<commit_msg>修复tab链接跳转问题<commit_after>/*!
 * TAB 切换
 * tommyshao <jinhong.shao@frontpay.cn>
 * Reference bootstrap.tab.js
 * API:
 *      $(element).on('closed.ui.alert', function(e, obj){});
 */

+(function($) {
    'use strict';

    var tab = '[data-toggle="tab"],.tabs-btn';

    // 构造函数
    // ===============
    var Tab = function(element) {
        this.$el = $(element);
    };

    Tab.VERSION = '1.0.0';

    // 动画过渡时间
    Tab.TRANSITION_DURATION = 150;

    // 关闭
    // ===============
    Tab.prototype.show = function( ) {
        var $this = this.$el;
        var $ul = $this.closest('.tabs');
        var selector = $this.data('target');

        if (!selector) { // a标签
            selector = $this.attr('href')
            selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
        }

        if($this.hasClass('active')) return;

        var $previous = $ul.find('.active a');
        var hideEvent = $.Event('hide.ui.tab', {
            relatedTarget: $this[0]
        });
        var showEvent = $.Event('show.ui.tab', {
            relatedTarget: $previous[0]
        });

        $previous.trigger(hideEvent);
        $this.trigger(showEvent);

        if(showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return;

        var $target = $(selector);

        this.activate($this.closest('li'), $ul);
        this.activate($target, $target.parent(), function(){
            $previous.trigger({
                type: 'hidden.ui.tab',
                relatedTarget: $this[0]
            });
            $this.trigger({
                type: 'shown.ui.tab',
                relatedTarget: $previous[0]
            })
        })
    };

    Tab.prototype.activate = function (element, container, callback) {
        var $active = container.find('> .active');
        var transition = callback
                            && $.support.transition
                            && (($active.length && $active.hasClass('fade')) || !!container.find('> .fade').length)

        function next() {
            $active.removeClass('active').find(tab).attr('aria-expanded', false);

            element.addClass('active').find(tab).attr('aria-expanded', true);

            if(transition) {
                element[0].offsetWidth;
                element.addClass('in');
            } else {
                element.removeClass('fade');
            }

            callback && callback();
        }

        $active.length && transition ?
                $active.one('uiTransitionEnd', next).emulateTransitionEnd(Tab.TRANSITION_DURATION)
                :
                next();
        $active.removeClass('in');
    };

    // 插件定义
    //======================
    function Plugin(option) {
        return $(this).each(function () {
            var $this = $(this);
            var data = $this.data('ui.tab');

            if(!data) $this.data('ui.tab', (data = new Tab(this)));
            if(typeof option == 'string') data[option] && data[option]();
        })
    }

    // jQuery 插件扩展
    $.fn.tab = Plugin;
    $.fn.tab.Constructor = Tab;

    // 元素插件绑定
    // ====================
    var clickHandler = function(e) {
        if(!$(e.target).hasClass('tab-disabled')){
            e.preventDefault();
            Plugin.call($(this), 'show')
        }
    };

    $(function(){
        $(document).on('click.ui.tab', tab, clickHandler)
    })

})( jQuery );
<|endoftext|>


<commit_before>JS2 = (function (undefined) {
  var JS2   = function () {};
  JS2.Class = function () { this.initialize.apply(this, arguments) };

  function _super () {
    var s = arguments.callee.caller._super;
    if (s) return s.apply(this, arguments);
  };
  JS2.Class.prototype.initialize = function () {};

  JS2.Class.extend = function (klassDef, name) {
    // TODO make more efficient
    var ret   = function () { this.initialize.apply(this, arguments) };
    var proto = Object.create(this.prototype);
    ret.prototype = proto;

    for (var k in this) {
      if (this.hasOwnProperty(k)) ret[k] = this[k];
    }

    for (var k in klassDef) {
      if (klassDef.hasOwnProperty(k)) {
        if (proto[k]) klassDef[k]._super = proto[k];
        proto[k] = klassDef[k];
      }
    }

    if (! 'initialize' in ret.prototype) {
      proto.initialize = function () {};
    }

    proto.super = _super;
    return ret;
  };

  JS2.Class.addStaticMethod = function (name, method) {
    if (this.hasOwnProperty(name)) {
      method._super = this[name]._super;
    } else if (this[name]) {
      method._super = this[name];
    }

    this[name] = method;
  };

  JS2.Class.$addMethod = function (name, method) {
    // method exists, override
    if (this.prototype.hasOwnProperty(name)) {
      method._super = this.prototype[name]._super;
    }

    // inheritted method, use super
    else if (this.prototype[name]) {
      method._super = this.prototype[name];
    }

    this.prototype[name] = method;
  };

  JS2.Class.include = function (mixin) {
    var proto = ret.prototype;
    var mixinProto = mixin.prototype;

    for (var k in mixinProto) {
      if (mixinProto.hasOwnProperty(k)) {
        if (!proto.hasOwnProperty(k)) {
          ret.prototype[k] = mixinProto[k];
	      }
      }
    }

    if (! 'initialize' in ret.prototype) {
      ret.prototype.initialize = function () {};
    }

    ret.prototype.$super = _super;
    return ret;
  };

  return JS2;
})();
<commit_msg>better class inheritance<commit_after>JS2 = (function (undefined) {
  var JS2   = function () {};
  JS2.Class = function () { this.initialize.apply(this, arguments) };

  function _super () {
    var s = arguments.callee.caller._super;
    if (s) return s.apply(this, arguments);
  };
  JS2.Class.prototype.initialize = function () {};

  JS2.Class.extend = function (klassDef, name) {
    // TODO make more efficient
    var ret   = function () { this.initialize.apply(this, arguments) };
    var proto = Object.create(this.prototype);
    ret.prototype = proto;
    ret.__proto__ = this;

    for (var k in klassDef) {
      if (klassDef.hasOwnProperty(k)) {
        if (proto[k]) klassDef[k]._super = proto[k];
        proto[k] = klassDef[k];
      }
    }

    if (! 'initialize' in ret.prototype) {
      proto.initialize = function () {};
    }

    proto.super = _super;
    return ret;
  };

  JS2.Class.addStaticMethod = function (name, method) {
    if (this.hasOwnProperty(name)) {
      method._super = this[name]._super;
    } else if (this[name]) {
      method._super = this[name];
    }

    this[name] = method;
  };

  JS2.Class.addMethod = function (name, method) {
    // method exists, override
    if (this.prototype.hasOwnProperty(name)) {
      method._super = this.prototype[name]._super;
    }

    // inheritted method, use super
    else if (this.prototype[name]) {
      method._super = this.prototype[name];
    }

    this.prototype[name] = method;
  };

  JS2.Class.include = function (mixin) {
    var proto = ret.prototype;
    var mixinProto = mixin.prototype;

    for (var k in mixinProto) {
      if (mixinProto.hasOwnProperty(k)) {
        if (!proto.hasOwnProperty(k)) {
          ret.prototype[k] = mixinProto[k];
	      }
      }
    }

    if (! 'initialize' in ret.prototype) {
      ret.prototype.initialize = function () {};
    }

    ret.prototype.$super = _super;
    return ret;
  };

  return JS2;
})();
<|endoftext|>


<commit_before>// ==========================================================================
// Project:   MySystem
// Copyright: ©2010 Concord Consortium
// ==========================================================================
/*globals MySystem */

/** @namespace

  My cool new app.  Describe your application.

  @extends SC.Object
*/
MySystem = SC.Application.create(
  /** @scope MySystem.prototype */ {

  NAMESPACE: 'MySystem',
  VERSION: '0.1.0',

  // TODO: Add global constants or singleton objects needed by your app here.
  canvasView: null,
  NOVICE_STUDENT: 'novice',
  ADVANCED_STUDENT: 'advanced',
  DEVELOPMENT_HEAD: 'head',

  learnerDataVersion: 5,

  /**
    Callback provided so that external applications, like WISE4, can let MySystem know to read the student state from
    the DOM element used for inter-iframe communication with MySystem.
  */
  updateFromDOM: function () {
    SC.run( function () {
      var text = SC.$('#my_system_state').text();
      MySystem.loadLearnerJSON(text);
    });
  },

  loadLearnerJSON: function (text) {
    var data;
    if (text.trim().length === 0) {
      return; // there is no data in the DOM
    }
    data = MySystem.migrations.migrateLearnerData(JSON.parse(text));
    MySystem.loadLearnerData(data);
  },
  loadLearnerData: function (data) {
    console.log(data);
    MySystem.store.setStudentStateDataHash(data);
  },

  isLearnerDataVersionAReleaseVersion: function () {
    return MySystem.migrations.isValidReleaseVersion(MySystem.learnerDataVersion);
  }

});

// Binding transform that takes the first element of an array and returns it, iff the element is of the specified type
SC.Binding.firstIfType = function (type) {
  return this.transform(function (value, binding) {
    var first;

    if (value && (first = value.firstObject()) && first.kindOf(type)) {
      return first;
    }
    else {
      return null;
    }
  });
};

// All fields of records used in this application must be declared before use. This is especially useful after
// refactoring models, in order to catch accesses of now-obsolete record types
SC.Record.reopen({
  unknownProperty: function (key, value) {
    if (key.length > 0) throw new ReferenceError("Attempt to access undeclared field '%@' of record: %@".fmt(key, this.toString()));
  }
});
<commit_msg>remove stray console.log statement.<commit_after>// ==========================================================================
// Project:   MySystem
// Copyright: ©2010 Concord Consortium
// ==========================================================================
/*globals MySystem */

/** @namespace

  My cool new app.  Describe your application.

  @extends SC.Object
*/
MySystem = SC.Application.create(
  /** @scope MySystem.prototype */ {

  NAMESPACE: 'MySystem',
  VERSION: '0.1.0',

  // TODO: Add global constants or singleton objects needed by your app here.
  canvasView: null,
  NOVICE_STUDENT: 'novice',
  ADVANCED_STUDENT: 'advanced',
  DEVELOPMENT_HEAD: 'head',

  learnerDataVersion: 5,

  /**
    Callback provided so that external applications, like WISE4, can let MySystem know to read the student state from
    the DOM element used for inter-iframe communication with MySystem.
  */
  updateFromDOM: function () {
    SC.run( function () {
      var text = SC.$('#my_system_state').text();
      MySystem.loadLearnerJSON(text);
    });
  },

  loadLearnerJSON: function (text) {
    var data;
    if (text.trim().length === 0) {
      return; // there is no data in the DOM
    }
    data = MySystem.migrations.migrateLearnerData(JSON.parse(text));
    MySystem.loadLearnerData(data);
  },
  loadLearnerData: function (data) {
    MySystem.store.setStudentStateDataHash(data);
  },

  isLearnerDataVersionAReleaseVersion: function () {
    return MySystem.migrations.isValidReleaseVersion(MySystem.learnerDataVersion);
  }

});

// Binding transform that takes the first element of an array and returns it, iff the element is of the specified type
SC.Binding.firstIfType = function (type) {
  return this.transform(function (value, binding) {
    var first;

    if (value && (first = value.firstObject()) && first.kindOf(type)) {
      return first;
    }
    else {
      return null;
    }
  });
};

// All fields of records used in this application must be declared before use. This is especially useful after
// refactoring models, in order to catch accesses of now-obsolete record types
SC.Record.reopen({
  unknownProperty: function (key, value) {
    if (key.length > 0) throw new ReferenceError("Attempt to access undeclared field '%@' of record: %@".fmt(key, this.toString()));
  }
});
<|endoftext|>


<commit_before>const React = require('react');
const h = require('react-hyperscript');
//const queryString = require('query-string');
const _ = require('lodash');
//const Loader = require('react-loader');

// const hideTooltips = require('../../common/cy/events/click').hideTooltips;
// const removeStyle= require('../../common/cy/manage-style').removeStyle;
const make_cytoscape = require('../../common/cy/');
// const interactionsStylesheet= require('../../common/cy/interactions-stylesheet');
const { BaseNetworkView } = require('../../common/components');
//const { getLayoutConfig } = require('../../common/cy/layout');
//const downloadTypes = require('../../common/config').downloadTypes;

const enrichmentConfig={
  //extablish toolbar and declare features to not include
  toolbarButtons: _.differenceBy(BaseNetworkView.config.toolbarButtons,[{'id': 'expandCollapse'}, {'id': 'showInfo'}],'id'),
  menus: BaseNetworkView.config.menus,
  //allow for searching of nodes
  useSearchBar: true
};

function validateInput(query, array, object)
{
  //recognized input
  if(_.isEmpty(object) && array.length == 0 )
  {
    alert("Thank you for your input. ***Service will continue to analysis");
    ServerAPI.enrichmentAPI(query, 'analysis');
    console.log(ServerAPI.enrichmentAPI(query, 'analysis'));
  }
    //unrec gene
  else if(array.length != 0 && _.isEmpty(object) == true)
  {
    let errorMes = "";
    for (let i = 0; i < array.length; i++)
    {
      errorMes += "\n" + array[i] + " is not a recognized";
    }
    errorMes += "\nPlease fix your input and submit again";
    alert(errorMes);
  }
  //duplicate
  else if(_.isEmpty(object) == false && array.length == 0)
    {
      let errorMes = "";
      for (let i = 0; i < _.keys(object).length; i++ )
      {
        let propertyName = _.keys(object)[i];
        let duplicateVal = object[propertyName];
        errorMes += "\n" + duplicateVal[0] + " and " + duplicateVal[1] + " are duplicates ";
      }
      errorMes += "\nPlease fix your input and submit again";
      alert(errorMes);
    }
  //unrec and duplicate
  else
  {
    let errorMes = "";
    for (let i = 0; i < _.keys(object).length; i++ )
      {
        let propertyName = _.keys(object)[i];
        let duplicateVal = object[propertyName];
        errorMes += "\n" + duplicateVal[0] + " and " + duplicateVal[1] + " are duplicates ";
      }
    for (let i = 0; i < array.length; i++)
    {
      errorMes += "\n" + array[i] + " is not recognized";
    }
    errorMes += "\nPlease fix your input and submit again";
    alert(errorMes);
  }
}

class Enrichment extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      cy: make_cytoscape({headless: true}),
      componentConfig: enrichmentConfig,
      layoutConfig: {},
      networkJSON: {},
      networkMetadata: {
        name: '',
        datasource: '',
        comments: []
      },
      query: '',
      titleContainer: [],
    };
  }

  geneInputChange(e) {
    this.setState( {query: e.target.value});
  }

  geneInputSubmission(input){
    const geneArray = input.split(/\n/g);
    const inputObject = {genes: _.pull(geneArray,"")};
    console.log(inputObject.genes);

    ServerAPI.enrichmentAPI(inputObject, "validation").then(function(result) {
      //object
      let duplicate = result.duplicate;
      //array of objects
      let geneInfo = result.geneInfo;
      //array
      let unrecognized = result.unrecognized;
      console.log(unrecognized);
      console.log(duplicate);
      validateInput(inputObject, unrecognized, duplicate);
    });
  }

  render() {
    const state = this.state;
    const baseView = h(BaseNetworkView.component, {
      componentConfig: state.componentConfig,
      //titles at top of toolbar
      networkMetadata: {},
      titleContainer: [
        h('h4', [
          h('span', 'Pathway Enrichment   '),]),
          h('img', {
            src: '/img/humanIcon.png'
            }),
          h('div.gene-input-container', [
            h('textarea.gene-input-box', {
             placeholder: 'Enter one gene per line',
             onChange: e => this.geneInputChange(e),
             onKeyPress: e => {
               this.geneInputChange(e);
             }
            })]),
          h('submit-container', {
            onClick: () => {
              this.geneInputSubmission(this.state.query);
            }},
          [
          h('button.submit', 'Submit'),
          ])
      ]
    });
    return h('div.main', [baseView]);
  }
}
module.exports = Enrichment;

//NOTE: CURRENTLY ONLY RENDERS ON PAGE WHEN base-network-view.js function 'componentDidMount(){}'
//      IS COMMENTED OUT<commit_msg>take into account that min set size default is 5 and max is 200<commit_after>const React = require('react');
const h = require('react-hyperscript');
//const queryString = require('query-string');
const _ = require('lodash');
//const Loader = require('react-loader');

// const hideTooltips = require('../../common/cy/events/click').hideTooltips;
// const removeStyle= require('../../common/cy/manage-style').removeStyle;
// const make_cytoscape = require('../../common/cy/');
// const interactionsStylesheet= require('../../common/cy/interactions-stylesheet');
const { BaseNetworkView } = require('../../common/components');
//const { getLayoutConfig } = require('../../common/cy/layout');
//const downloadTypes = require('../../common/config').downloadTypes;

const enrichmentConfig={
  //extablish toolbar and declare features to not include
  toolbarButtons: _.differenceBy(BaseNetworkView.config.toolbarButtons,[{'id': 'expandCollapse'}, {'id': 'showInfo'}],'id'),
  menus: BaseNetworkView.config.menus,
  //allow for searching of nodes
  useSearchBar: true
};

function validateInput(query, array, object)
{
  //recognized input
  if(_.isEmpty(object) && array.length == 0 )
  {
    alert("Thank you for your input. ***Service will continue to analysis");
    //ServerAPI.enrichmentAPI(query, 'analysis');
    //console.log(ServerAPI.enrichmentAPI(query, 'validate'));
    //console.log(ServerAPI.enrichmentAPI(query, 'analysis'));
  }
    //unrec gene
  else if(array.length != 0 && _.isEmpty(object) == true)
  {
    let errorMes = "";
    for (let i = 0; i < array.length; i++)
    {
      errorMes += "\n" + array[i] + " is not a recognized";
    }
    errorMes += "\nPlease fix your input and submit again";
    alert(errorMes);
  }
  //duplicate
  else if(_.isEmpty(object) == false && array.length == 0)
    {
      let errorMes = "";
      for (let i = 0; i < _.keys(object).length; i++ )
      {
        let propertyName = _.keys(object)[i];
        let duplicateVal = object[propertyName];
        errorMes += "\n" + duplicateVal[0] + " and " + duplicateVal[1] + " are duplicates ";
      }
      errorMes += "\nPlease fix your input and submit again";
      alert(errorMes);
    }
  //unrec and duplicate
  else
  {
    let errorMes = "";
    for (let i = 0; i < _.keys(object).length; i++ )
      {
        let propertyName = _.keys(object)[i];
        let duplicateVal = object[propertyName];
        errorMes += "\n" + duplicateVal[0] + " and " + duplicateVal[1] + " are duplicates ";
      }
    for (let i = 0; i < array.length; i++)
    {
      errorMes += "\n" + array[i] + " is not recognized";
    }
    errorMes += "\nPlease fix your input and submit again";
    alert(errorMes);
  }
}

class Enrichment extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      componentConfig: enrichmentConfig,
      networkMetadata: {
        name: '',
        datasource: '',
        comments: []
      },
      query: '',
      titleContainer: [],
    };
  }

  geneInputChange(e) {
    this.setState( {query: e.target.value});
  }

  geneInputSubmission(input){
    const geneArray = input.split(/\n/g);
    if(geneArray.length < 5) return alert("Please input 4 or more tokens");
    if(geneArray.length > 200)return alert("Please input less than 200 tokens");
    const inputObject = {genes: _.pull(geneArray,"")};
    //console.log(inputObject.genes);

    ServerAPI.enrichmentAPI(inputObject, "validation").then(function(result) {
      //object
      let duplicate = result.duplicate;
      //array of objects
      let geneInfo = result.geneInfo;
      //array
      let unrecognized = result.unrecognized;
      //console.log(unrecognized);
      //console.log(duplicate);
      validateInput(inputObject, unrecognized, duplicate);
    });
  }

  render() {
    const state = this.state;
    const baseView = h(BaseNetworkView.component, {
      componentConfig: state.componentConfig,
      //titles at top of toolbar
      networkMetadata: {},
      titleContainer: [
        h('h4', [
          h('span', 'Pathway Enrichment   '),]),
          h('img', {
            src: '/img/humanIcon.png'
            }),
          h('div.gene-input-container', [
            h('textarea.gene-input-box', {
             placeholder: 'Enter one gene per line',
             onChange: e => this.geneInputChange(e),
             onKeyPress: e => {
               this.geneInputChange(e);
             }
            })]),
          h('submit-container', {
            onClick: () => {
              this.geneInputSubmission(this.state.query);
            }},
          [
          h('button.submit', 'Submit'),
          ])
      ]
    });
    return h('div.main', [baseView]);
  }
}
module.exports = Enrichment;

//NOTE: CURRENTLY ONLY RENDERS ON PAGE WHEN base-network-view.js function 'componentDidMount(){}'
//      IS COMMENTED OUT<|endoftext|>


<commit_before>/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
/*global require, exports */

////////////////////////////////////////////////////////////////////////////////
/// @brief Graph functionality
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler, Lucas Dohmen
/// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

var arangodb = require("org/arangodb"),
  arangosh = require("org/arangodb/arangosh"),
  is = require("org/arangodb/is"),
  ArangoQueryCursor = require("org/arangodb/arango-query-cursor").ArangoQueryCursor,
  common = require("org/arangodb/graph-common"),
  Edge = common.Edge,
  Graph = common.Graph,
  Vertex = common.Vertex,
  GraphArray = common.GraphArray,
  request;

request = {
  send: function (method, graph, path, data) {
    var results = graph._connection[method]("/_api/graph/" +
      encodeURIComponent(graph._properties._key) +
      path,
      JSON.stringify(data));

    arangosh.checkRequestResult(results);
    return results;
  },

  postEdge: function (graph, edge, data) {
    var results = this.send("POST",
      graph,
      "/edges/" + encodeURIComponent(edge._properties._key),
      data);

    return results;
  },

  putEdge: function (graph, edge, data) {
    var results = this.send("PUT",
      graph,
      "/edge/" + encodeURIComponent(edge._properties._key),
      data);

    return results;
  },

  putVertex: function (graph, vertex, data) {
    var results = this.send("PUT",
      graph,
      "/vertex/" + encodeURIComponent(vertex._properties._key),
      data);

    return results;
  }
};

// -----------------------------------------------------------------------------
// --SECTION--                                       module "org/arangodb/graph"
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// --SECTION--                                                              Edge
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoGraph
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief constructs a new edge object
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                    public methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoGraph
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief returns the to vertex
////////////////////////////////////////////////////////////////////////////////

Edge.prototype.getInVertex = function () {
  return this._graph.getVertex(this._properties._to);
};

////////////////////////////////////////////////////////////////////////////////
/// @brief returns the from vertex
////////////////////////////////////////////////////////////////////////////////

Edge.prototype.getOutVertex = function () {
  return this._graph.getVertex(this._properties._from);
};

////////////////////////////////////////////////////////////////////////////////
/// @brief returns the other vertex
////////////////////////////////////////////////////////////////////////////////

Edge.prototype.getPeerVertex = function (vertex) {
  if (vertex._properties._id === this._properties._to) {
    return this._graph.getVertex(this._properties._from);
  }

  if (vertex._properties._id === this._properties._from) {
    return this._graph.getVertex(this._properties._to);
  }

  return null;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief changes a property of an edge
////////////////////////////////////////////////////////////////////////////////

Edge.prototype.setProperty = function (name, value) {
  var requestResult;
  var update = this._properties;

  update[name] = value;

  requestResult = request.putEdge(this._graph, this, update);

  this._properties = requestResult.edge;

  return name;
};

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                            Vertex
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoGraph
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief constructs a new vertex object
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                    public methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoGraph
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief inbound and outbound edges
////////////////////////////////////////////////////////////////////////////////

Vertex.prototype.edges = function () {
  var graph = this._graph;
  var requestResult;
  var edges;
  var cursor;

  requestResult = request.postEdge(this._graph, this, {
    filter: { direction: "any" }
  });

  cursor = new ArangoQueryCursor(graph._vertices._database, requestResult);
  edges = new GraphArray();

  while (cursor.hasNext()) {
    var edge = new Edge(graph, cursor.next());

    edges.push(edge);
  }

  return edges;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief inbound edges with given label
////////////////////////////////////////////////////////////////////////////////

Vertex.prototype.getInEdges = function () {
  var labels = Array.prototype.slice.call(arguments);
  var graph = this._graph;
  var requestResult;
  var edges;
  var cursor;

  requestResult = request.postEdge(this._graph, this, {
    filter : { direction : "in", labels: labels }
  });

  cursor = new ArangoQueryCursor(graph._vertices._database, requestResult);
  edges = new GraphArray();

  while (cursor.hasNext()) {
    var edge = new Edge(graph, cursor.next());

    edges.push(edge);
  }

  return edges;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief outbound edges with given label
////////////////////////////////////////////////////////////////////////////////

Vertex.prototype.getOutEdges = function () {
  var labels = Array.prototype.slice.call(arguments);
  var graph = this._graph;
  var requestResult;
  var edges;
  var cursor;

  requestResult = request.postEdge(this._graph, this, {
    filter : { direction : "out", labels: labels }
  });

  cursor = new ArangoQueryCursor(graph._vertices._database, requestResult);
  edges = new GraphArray();

  while (cursor.hasNext()) {
    var edge = new Edge(graph, cursor.next());

    edges.push(edge);
  }

  return edges;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief in- or outbound edges with given label
////////////////////////////////////////////////////////////////////////////////

Vertex.prototype.getEdges = function () {
  var labels = Array.prototype.slice.call(arguments);
  var graph = this._graph;
  var requestResult;
  var edges;
  var cursor;

  requestResult = request.postEdge(this._graph, this, {
    filter : { labels: labels }
  });

  cursor = new ArangoQueryCursor(graph._vertices._database, requestResult);
  edges = new GraphArray();

  while (cursor.hasNext()) {
    var edge = new Edge(graph, cursor.next());

    edges.push(edge);
  }

  return edges;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief inbound edges
////////////////////////////////////////////////////////////////////////////////

Vertex.prototype.inbound = function () {
  return this.getInEdges();
};

////////////////////////////////////////////////////////////////////////////////
/// @brief outbound edges
////////////////////////////////////////////////////////////////////////////////

Vertex.prototype.outbound = function () {
  return this.getOutEdges();
};

////////////////////////////////////////////////////////////////////////////////
/// @brief changes a property of a vertex
////////////////////////////////////////////////////////////////////////////////

Vertex.prototype.setProperty = function (name, value) {
  var requestResult;
  var update = this._properties;

  update[name] = value;

  requestResult = request.putVertex(this._graph, this, update);

  this._properties = requestResult.vertex;

  return name;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief returns the number of edges
////////////////////////////////////////////////////////////////////////////////

Vertex.prototype.degree = function () {
  return this.getEdges().length;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief returns the number of in-edges
////////////////////////////////////////////////////////////////////////////////

Vertex.prototype.inDegree = function () {
  return this.getInEdges().length;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief returns the number of out-edges
////////////////////////////////////////////////////////////////////////////////

Vertex.prototype.outDegree = function () {
  return this.getOutEdges().length;
};

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                             Graph
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoGraph
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief constructs a new graph object
////////////////////////////////////////////////////////////////////////////////

Graph.prototype.initialize = function (name, vertices, edges) {
  var requestResult;

  if (vertices === undefined && edges === undefined) {
    requestResult = arangodb.arango.GET("/_api/graph/" + encodeURIComponent(name));
  }
  else {
    requestResult = arangodb.arango.POST("/_api/graph", JSON.stringify({
      _key: name,
      vertices: vertices,
      edges: edges
    }));
  }

  arangosh.checkRequestResult(requestResult);

  this._properties = requestResult.graph;
  this._vertices = arangodb.db._collection(this._properties.vertices);
  this._edges = arangodb.db._collection(this._properties.edges);
  this._connection = arangodb.arango;

  return this;
};

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                    public methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoGraph
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief drops the graph, the vertices, and the edges
////////////////////////////////////////////////////////////////////////////////

Graph.prototype.drop = function () {
  var requestResult;

  requestResult = this._connection.DELETE("/_api/graph/" +
    encodeURIComponent(this._properties._key));

  arangosh.checkRequestResult(requestResult);
};

////////////////////////////////////////////////////////////////////////////////
/// @brief saves an edge to the graph
////////////////////////////////////////////////////////////////////////////////

Graph.prototype._saveEdge = function(id, out_vertex, in_vertex, params) {
  params._key = id;
  params._from = out_vertex._properties._key;
  params._to = in_vertex._properties._key;

  var requestResult = this._connection.POST("/_api/graph/"
    + encodeURIComponent(this._properties._key) + "/edge",
    JSON.stringify(params));

  arangosh.checkRequestResult(requestResult);

  return new Edge(this, requestResult.edge);
};

////////////////////////////////////////////////////////////////////////////////
/// @brief saves a vertex to the graph
////////////////////////////////////////////////////////////////////////////////

Graph.prototype._saveVertex = function (id, params) {
  var requestResult;

  if (is.existy(id)) {
    params._key = id;
  }

  requestResult = this._connection.POST("/_api/graph/" +
    encodeURIComponent(this._properties._key) + "/vertex",
    JSON.stringify(params));

  arangosh.checkRequestResult(requestResult);

  return new Vertex(this, requestResult.vertex);
};

////////////////////////////////////////////////////////////////////////////////
/// @brief returns a vertex given its id
////////////////////////////////////////////////////////////////////////////////

Graph.prototype.getVertex = function (id) {
  var requestResult;

  requestResult = this._connection.GET("/_api/graph/" +
    encodeURIComponent(this._properties._key) +
    "/vertex/" +
    encodeURIComponent(id));

  if (requestResult.error === true && requestResult.code === 404) {
    return null;
  }

  arangosh.checkRequestResult(requestResult);

  if (requestResult.vertex !== null) {
    return new Vertex(this, requestResult.vertex);
  }

  return null;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief returns an iterator for all vertices
////////////////////////////////////////////////////////////////////////////////

Graph.prototype.getVertices = function () {
  var that = this;
  var requestResult;
  var cursor;
  var Iterator;

  requestResult = this._connection.POST("/_api/graph/" +
    encodeURIComponent(this._properties._key) +
    "/vertices",
    "{}");

  arangosh.checkRequestResult(requestResult);

  cursor = new ArangoQueryCursor(this._vertices._database, requestResult);

  Iterator = function () {
    this.next = function next() {
      if (cursor.hasNext()) {
        return new Vertex(that, cursor.next());
      }

      return undefined;
    };

    this.hasNext = function hasNext() {
      return cursor.hasNext();
    };

    this._PRINT = function (context) {
      context.output += "[vertex iterator]";
    };
  };

  return new Iterator();
};

////////////////////////////////////////////////////////////////////////////////
/// @brief returns an edge given its id
////////////////////////////////////////////////////////////////////////////////

Graph.prototype.getEdge = function (id) {
  var requestResult;

  requestResult = this._connection.GET("/_api/graph/" +
    encodeURIComponent(this._properties._key) +
    "/edge/" +
    encodeURIComponent(id));

  if (requestResult.error === true && requestResult.code === 404) {
    return null;
  }

  arangosh.checkRequestResult(requestResult);

  if (requestResult.edge !== null) {
    return new Edge(this, requestResult.edge);
  }

  return null;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief returns an iterator for all edges
////////////////////////////////////////////////////////////////////////////////

Graph.prototype.getEdges = function () {
  var that = this;
  var requestResult;
  var cursor;
  var Iterator;

  requestResult = this._connection.POST("/_api/graph/" +
    encodeURIComponent(this._properties._key) +
    "/edges",
    "{}");

  arangosh.checkRequestResult(requestResult);

  cursor = new ArangoQueryCursor(this._vertices._database, requestResult);

  Iterator = function () {
    this.next = function next() {
      if (cursor.hasNext()) {
        return new Edge(that, cursor.next());
      }

      return undefined;
    };

    this.hasNext = function hasNext() {
      return cursor.hasNext();
    };

    this._PRINT = function (context) {
      context.output += "[edge iterator]";
    };
  };

  return new Iterator();
};

////////////////////////////////////////////////////////////////////////////////
/// @brief removes a vertex and all in- or out-bound edges
////////////////////////////////////////////////////////////////////////////////

Graph.prototype.removeVertex = function (vertex) {
  var requestResult;

  requestResult = this._connection.DELETE("/_api/graph/" +
    encodeURIComponent(this._properties._key) +
    "/vertex/" +
    encodeURIComponent(vertex._properties._key));

  arangosh.checkRequestResult(requestResult);

  vertex._properties = undefined;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief removes an edge
////////////////////////////////////////////////////////////////////////////////

Graph.prototype.removeEdge = function (edge) {
  var requestResult;

  requestResult = this._connection.DELETE("/_api/graph/" +
    encodeURIComponent(this._properties._key) +
    "/edge/" +
    encodeURIComponent(edge._properties._key));

  arangosh.checkRequestResult(requestResult);

  edge._properties = undefined;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief returns the number of vertices
///
/// @FUN{@FA{graph}.order()}
////////////////////////////////////////////////////////////////////////////////

Graph.prototype.order = function () {
  return this._vertices.count();
};

////////////////////////////////////////////////////////////////////////////////
/// @brief returns the number of edges
///
/// @FUN{@FA{graph}.size()}
////////////////////////////////////////////////////////////////////////////////

Graph.prototype.size = function () {
  return this._edges.count();
};

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                    MODULE EXPORTS
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoGraph
/// @{
////////////////////////////////////////////////////////////////////////////////

exports.Edge = Edge;
exports.Graph = Graph;
exports.Vertex = Vertex;
exports.GraphArray = GraphArray;

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:
<commit_msg>Graph Module (Client): First step of extracting shared getEdge behaviour<commit_after>/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
/*global require, exports */

////////////////////////////////////////////////////////////////////////////////
/// @brief Graph functionality
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler, Lucas Dohmen
/// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

var arangodb = require("org/arangodb"),
  arangosh = require("org/arangodb/arangosh"),
  is = require("org/arangodb/is"),
  ArangoQueryCursor = require("org/arangodb/arango-query-cursor").ArangoQueryCursor,
  common = require("org/arangodb/graph-common"),
  Edge = common.Edge,
  Graph = common.Graph,
  Vertex = common.Vertex,
  GraphArray = common.GraphArray,
  request;

request = {
  send: function (method, graph, path, data) {
    var results = graph._connection[method]("/_api/graph/" +
      encodeURIComponent(graph._properties._key) +
      path,
      JSON.stringify(data));

    arangosh.checkRequestResult(results);
    return results;
  },

  postEdge: function (graph, edge, data) {
    var results = this.send("POST",
      graph,
      "/edges/" + encodeURIComponent(edge._properties._key),
      data);

    return results;
  },

  putEdge: function (graph, edge, data) {
    var results = this.send("PUT",
      graph,
      "/edge/" + encodeURIComponent(edge._properties._key),
      data);

    return results;
  },

  putVertex: function (graph, vertex, data) {
    var results = this.send("PUT",
      graph,
      "/vertex/" + encodeURIComponent(vertex._properties._key),
      data);

    return results;
  }
};

// -----------------------------------------------------------------------------
// --SECTION--                                       module "org/arangodb/graph"
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// --SECTION--                                                              Edge
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoGraph
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief constructs a new edge object
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                    public methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoGraph
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief returns the to vertex
////////////////////////////////////////////////////////////////////////////////

Edge.prototype.getInVertex = function () {
  return this._graph.getVertex(this._properties._to);
};

////////////////////////////////////////////////////////////////////////////////
/// @brief returns the from vertex
////////////////////////////////////////////////////////////////////////////////

Edge.prototype.getOutVertex = function () {
  return this._graph.getVertex(this._properties._from);
};

////////////////////////////////////////////////////////////////////////////////
/// @brief returns the other vertex
////////////////////////////////////////////////////////////////////////////////

Edge.prototype.getPeerVertex = function (vertex) {
  if (vertex._properties._id === this._properties._to) {
    return this._graph.getVertex(this._properties._from);
  }

  if (vertex._properties._id === this._properties._from) {
    return this._graph.getVertex(this._properties._to);
  }

  return null;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief changes a property of an edge
////////////////////////////////////////////////////////////////////////////////

Edge.prototype.setProperty = function (name, value) {
  var requestResult;
  var update = this._properties;

  update[name] = value;

  requestResult = request.putEdge(this._graph, this, update);

  this._properties = requestResult.edge;

  return name;
};

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                            Vertex
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoGraph
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief constructs a new vertex object
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                    public methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoGraph
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief inbound and outbound edges
////////////////////////////////////////////////////////////////////////////////

Vertex.prototype.edges = function (direction, labels) {
  var requestResult,
    edge,
    edges = new GraphArray(),
    cursor;

  requestResult = request.postEdge(this._graph, this, {
    filter : { direction : direction, labels: labels }
  });

  cursor = new ArangoQueryCursor(this._graph._vertices._database, requestResult);

  while (cursor.hasNext()) {
    edge = new Edge(this._graph, cursor.next());
    edges.push(edge);
  }

  return edges;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief inbound edges with given label
////////////////////////////////////////////////////////////////////////////////

Vertex.prototype.getInEdges = function () {
  var labels = Array.prototype.slice.call(arguments);
  return this.edges("in", labels);
};

////////////////////////////////////////////////////////////////////////////////
/// @brief outbound edges with given label
////////////////////////////////////////////////////////////////////////////////

Vertex.prototype.getOutEdges = function () {
  var labels = Array.prototype.slice.call(arguments);
  return this.edges("out", labels);
};

////////////////////////////////////////////////////////////////////////////////
/// @brief in- or outbound edges with given label
////////////////////////////////////////////////////////////////////////////////

Vertex.prototype.getEdges = function () {
  var labels = Array.prototype.slice.call(arguments);
  return this.edges("any", labels);
};

////////////////////////////////////////////////////////////////////////////////
/// @brief inbound edges
////////////////////////////////////////////////////////////////////////////////

Vertex.prototype.inbound = function () {
  return this.getInEdges();
};

////////////////////////////////////////////////////////////////////////////////
/// @brief outbound edges
////////////////////////////////////////////////////////////////////////////////

Vertex.prototype.outbound = function () {
  return this.getOutEdges();
};

////////////////////////////////////////////////////////////////////////////////
/// @brief changes a property of a vertex
////////////////////////////////////////////////////////////////////////////////

Vertex.prototype.setProperty = function (name, value) {
  var requestResult;
  var update = this._properties;

  update[name] = value;

  requestResult = request.putVertex(this._graph, this, update);

  this._properties = requestResult.vertex;

  return name;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief returns the number of edges
////////////////////////////////////////////////////////////////////////////////

Vertex.prototype.degree = function () {
  return this.getEdges().length;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief returns the number of in-edges
////////////////////////////////////////////////////////////////////////////////

Vertex.prototype.inDegree = function () {
  return this.getInEdges().length;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief returns the number of out-edges
////////////////////////////////////////////////////////////////////////////////

Vertex.prototype.outDegree = function () {
  return this.getOutEdges().length;
};

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                             Graph
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoGraph
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief constructs a new graph object
////////////////////////////////////////////////////////////////////////////////

Graph.prototype.initialize = function (name, vertices, edges) {
  var requestResult;

  if (vertices === undefined && edges === undefined) {
    requestResult = arangodb.arango.GET("/_api/graph/" + encodeURIComponent(name));
  }
  else {
    requestResult = arangodb.arango.POST("/_api/graph", JSON.stringify({
      _key: name,
      vertices: vertices,
      edges: edges
    }));
  }

  arangosh.checkRequestResult(requestResult);

  this._properties = requestResult.graph;
  this._vertices = arangodb.db._collection(this._properties.vertices);
  this._edges = arangodb.db._collection(this._properties.edges);
  this._connection = arangodb.arango;

  return this;
};

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                    public methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoGraph
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief drops the graph, the vertices, and the edges
////////////////////////////////////////////////////////////////////////////////

Graph.prototype.drop = function () {
  var requestResult;

  requestResult = this._connection.DELETE("/_api/graph/" +
    encodeURIComponent(this._properties._key));

  arangosh.checkRequestResult(requestResult);
};

////////////////////////////////////////////////////////////////////////////////
/// @brief saves an edge to the graph
////////////////////////////////////////////////////////////////////////////////

Graph.prototype._saveEdge = function(id, out_vertex, in_vertex, params) {
  params._key = id;
  params._from = out_vertex._properties._key;
  params._to = in_vertex._properties._key;

  var requestResult = this._connection.POST("/_api/graph/" +
    encodeURIComponent(this._properties._key) + "/edge",
    JSON.stringify(params));

  arangosh.checkRequestResult(requestResult);

  return new Edge(this, requestResult.edge);
};

////////////////////////////////////////////////////////////////////////////////
/// @brief saves a vertex to the graph
////////////////////////////////////////////////////////////////////////////////

Graph.prototype._saveVertex = function (id, params) {
  var requestResult;

  if (is.existy(id)) {
    params._key = id;
  }

  requestResult = this._connection.POST("/_api/graph/" +
    encodeURIComponent(this._properties._key) + "/vertex",
    JSON.stringify(params));

  arangosh.checkRequestResult(requestResult);

  return new Vertex(this, requestResult.vertex);
};

////////////////////////////////////////////////////////////////////////////////
/// @brief returns a vertex given its id
////////////////////////////////////////////////////////////////////////////////

Graph.prototype.getVertex = function (id) {
  var requestResult;

  requestResult = this._connection.GET("/_api/graph/" +
    encodeURIComponent(this._properties._key) +
    "/vertex/" +
    encodeURIComponent(id));

  if (requestResult.error === true && requestResult.code === 404) {
    return null;
  }

  arangosh.checkRequestResult(requestResult);

  if (requestResult.vertex !== null) {
    return new Vertex(this, requestResult.vertex);
  }

  return null;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief returns an iterator for all vertices
////////////////////////////////////////////////////////////////////////////////

Graph.prototype.getVertices = function () {
  var that = this;
  var requestResult;
  var cursor;
  var Iterator;

  requestResult = this._connection.POST("/_api/graph/" +
    encodeURIComponent(this._properties._key) +
    "/vertices",
    "{}");

  arangosh.checkRequestResult(requestResult);

  cursor = new ArangoQueryCursor(this._vertices._database, requestResult);

  Iterator = function () {
    this.next = function next() {
      if (cursor.hasNext()) {
        return new Vertex(that, cursor.next());
      }

      return undefined;
    };

    this.hasNext = function hasNext() {
      return cursor.hasNext();
    };

    this._PRINT = function (context) {
      context.output += "[vertex iterator]";
    };
  };

  return new Iterator();
};

////////////////////////////////////////////////////////////////////////////////
/// @brief returns an edge given its id
////////////////////////////////////////////////////////////////////////////////

Graph.prototype.getEdge = function (id) {
  var requestResult;

  requestResult = this._connection.GET("/_api/graph/" +
    encodeURIComponent(this._properties._key) +
    "/edge/" +
    encodeURIComponent(id));

  if (requestResult.error === true && requestResult.code === 404) {
    return null;
  }

  arangosh.checkRequestResult(requestResult);

  if (requestResult.edge !== null) {
    return new Edge(this, requestResult.edge);
  }

  return null;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief returns an iterator for all edges
////////////////////////////////////////////////////////////////////////////////

Graph.prototype.getEdges = function () {
  var that = this;
  var requestResult;
  var cursor;
  var Iterator;

  requestResult = this._connection.POST("/_api/graph/" +
    encodeURIComponent(this._properties._key) +
    "/edges",
    "{}");

  arangosh.checkRequestResult(requestResult);

  cursor = new ArangoQueryCursor(this._vertices._database, requestResult);

  Iterator = function () {
    this.next = function next() {
      if (cursor.hasNext()) {
        return new Edge(that, cursor.next());
      }

      return undefined;
    };

    this.hasNext = function hasNext() {
      return cursor.hasNext();
    };

    this._PRINT = function (context) {
      context.output += "[edge iterator]";
    };
  };

  return new Iterator();
};

////////////////////////////////////////////////////////////////////////////////
/// @brief removes a vertex and all in- or out-bound edges
////////////////////////////////////////////////////////////////////////////////

Graph.prototype.removeVertex = function (vertex) {
  var requestResult;

  requestResult = this._connection.DELETE("/_api/graph/" +
    encodeURIComponent(this._properties._key) +
    "/vertex/" +
    encodeURIComponent(vertex._properties._key));

  arangosh.checkRequestResult(requestResult);

  vertex._properties = undefined;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief removes an edge
////////////////////////////////////////////////////////////////////////////////

Graph.prototype.removeEdge = function (edge) {
  var requestResult;

  requestResult = this._connection.DELETE("/_api/graph/" +
    encodeURIComponent(this._properties._key) +
    "/edge/" +
    encodeURIComponent(edge._properties._key));

  arangosh.checkRequestResult(requestResult);

  edge._properties = undefined;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief returns the number of vertices
///
/// @FUN{@FA{graph}.order()}
////////////////////////////////////////////////////////////////////////////////

Graph.prototype.order = function () {
  return this._vertices.count();
};

////////////////////////////////////////////////////////////////////////////////
/// @brief returns the number of edges
///
/// @FUN{@FA{graph}.size()}
////////////////////////////////////////////////////////////////////////////////

Graph.prototype.size = function () {
  return this._edges.count();
};

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                    MODULE EXPORTS
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoGraph
/// @{
////////////////////////////////////////////////////////////////////////////////

exports.Edge = Edge;
exports.Graph = Graph;
exports.Vertex = Vertex;
exports.GraphArray = GraphArray;

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:
<|endoftext|>


<commit_before>/*
Name:           geoip2ws - geoip2ws.js
Description:    Maxmind GeoIP2 Web Services for node.js (unofficial)
Author:         Franklin (https://fvdm.com)
Source & docs:  https://github.com/fvdm/nodejs-geoip2ws
Feedback:       https://github.com/fvdm/nodejs-geoip2ws/issues
License:        Unlicense (public domain, see LICENSE file)
*/

const { isIP } = require ('net');
const { doRequest } = require ('httpreq');

// setup
let api = {
  userId: null,
  licenseKey: null,
  service: 'city',
  endpoint: 'https://geoip.maxmind.com',
  timeout: 5000,
};

/**
 * Check if string is a service
 *
 * @param   {string}  service  Service name
 *
 * @return  {boolean}          `true` if string is a service name
 */

function isService (service) {
  return /^(country|city|insights)$/.test (service);
}

/**
 * Promisify doRequest without deps
 *
 * @param   {object}  props  doRequest() options
 *
 * @return  {Promise<object>}
 */

async function get (options) {
  return new Promise ((resolve, reject) => {
    doRequest (options, (err, res) => {
      if (err) {
        reject (err);
        return;
      }

      resolve (res);
    });
  });
}

/**
 * Process response body
 *
 * @param   {object}  res  doRequest() response
 *
 * @return  {Promise<object>}
 */

async function doResponse (res) {
  const data = JSON.parse (res.body);
  let error;

  if (data.error) {
    error = new Error (data.error);
    error.code = data.code;
    throw error;
  }

  // Fix API inconsistencies
  if (Array.isArray (data.subdivisions) && data.subdivisions.length) {
    data.most_specific_subdivision = data.subdivisions[data.subdivisions.length - 1];
  }
  else {
    data.subdivisions = [];
  }

  if (!data.most_specific_subdivision) {
    data.most_specific_subdivision = {};
  }

  for (let key in data) {
    if (key.match (/^(city|country|postal|subdivisions)$/) && !data[key].confidence) {
      data[key].confidence = 0;
    }
  }

  return data;
}

/**
 * Perform lookup
 *
 * @param   {object}  args
 *
 * @param   {string}  args.ip                                    IP-address, hostname or 'me' to look up
 * @param   {string}  [args.userId]                              Account user ID
 * @param   {string}  [args.licenseKey]                          Account license key
 * @param   {string}  [args.service=city]                        Account service name
 * @param   {string}  [args.endpoint=https://geoip.maxmind.com]  API hostname or url
 * @param   {number}  [args.timeout=5000]                        Request time out in milliseconds
 *
 * @return  {Promise<object>}
 */

async function doLookup ({

  ip,
  userId = api.userId,
  licenseKey = api.licenseKey,
  service = api.service,
  endpoint = api.endpoint,
  timeout = api.timeout,

}) {

  // check input
  if (!isService (service)) {
    throw new Error ('invalid service');
  }

  if (ip !== 'me' && !isIP (ip)) {
    throw new Error ('invalid ip');
  }

  // build url
  endpoint = endpoint.replace (/\/$/, '');
  endpoint += `/geoip/v2.1/${service}/${ip}`;

  if (!endpoint.match (/^https?\:\/\//)) {
    endpoint = `https://${endpoint}`;
  }

  // build request
  const httpProps = {
    method: 'GET',
    auth: `${userId}:${licenseKey}`,
    timeout,
    headers: {
      'Accept': `application/vnd.maxmind.com-${service}+json; charset=UTF-8; version=2.1`,
      'User-Agent': 'geoip2ws.js (https://github.com/fvdm/nodejs-geoip2ws)',
    },
    url: endpoint,
  };

  // do promise
  return get (httpProps)
    .then (doResponse)
  ;

}

/**
 * Module interface
 *
 * @param   {object}    args
 *
 * @param   {string}    [args.userId]                                Account user ID
 * @param   {string}    [args.licenseKey]                            Account license key
 * @param   {string}    [args.service=city]                          Account service name
 * @param   {string}    [args.endpoint='https://geoip.maxmind.com']  API hostname or url
 * @param   {number}    [args.timeout=5000]                          Request time out in milliseconds
 *
 * @return  {function}  doLookup
 */

module.exports = function setup ({

  userId = null,
  licenseKey = null,
  service = api.service,
  endpoint = api.endpoint,
  timeout = api.timeout,

} = {}) {

  api.userId = userId;
  api.licenseKey = licenseKey;
  api.service = service;
  api.endpoint = endpoint;
  api.timeout = timeout;

  return doLookup;

};
<commit_msg>Refactor: httpreq now supports promises<commit_after>/*
Name:           geoip2ws - geoip2ws.js
Description:    Maxmind GeoIP2 Web Services for node.js (unofficial)
Author:         Franklin (https://fvdm.com)
Source & docs:  https://github.com/fvdm/nodejs-geoip2ws
Feedback:       https://github.com/fvdm/nodejs-geoip2ws/issues
License:        Unlicense (public domain, see LICENSE file)
*/

const { isIP } = require ('net');
const { doRequest } = require ('httpreq');

// setup
let api = {
  userId: null,
  licenseKey: null,
  service: 'city',
  endpoint: 'https://geoip.maxmind.com',
  timeout: 5000,
};

/**
 * Check if string is a service
 *
 * @param   {string}  service  Service name
 *
 * @return  {boolean}          `true` if string is a service name
 */

function isService (service) {
  return /^(country|city|insights)$/.test (service);
}

/**
 * Process response body
 *
 * @param   {object}  res  doRequest() response
 *
 * @return  {Promise<object>}
 */

async function doResponse (res) {
  const data = JSON.parse (res.body);
  let error;

  if (data.error) {
    error = new Error (data.error);
    error.code = data.code;
    throw error;
  }

  // Fix API inconsistencies
  if (Array.isArray (data.subdivisions) && data.subdivisions.length) {
    data.most_specific_subdivision = data.subdivisions[data.subdivisions.length - 1];
  }
  else {
    data.subdivisions = [];
  }

  if (!data.most_specific_subdivision) {
    data.most_specific_subdivision = {};
  }

  for (let key in data) {
    if (key.match (/^(city|country|postal|subdivisions)$/) && !data[key].confidence) {
      data[key].confidence = 0;
    }
  }

  return data;
}

/**
 * Perform lookup
 *
 * @param   {object}  args
 *
 * @param   {string}  args.ip                                    IP-address, hostname or 'me' to look up
 * @param   {string}  [args.userId]                              Account user ID
 * @param   {string}  [args.licenseKey]                          Account license key
 * @param   {string}  [args.service=city]                        Account service name
 * @param   {string}  [args.endpoint=https://geoip.maxmind.com]  API hostname or url
 * @param   {number}  [args.timeout=5000]                        Request time out in milliseconds
 *
 * @return  {Promise<object>}
 */

async function doLookup ({

  ip,
  userId = api.userId,
  licenseKey = api.licenseKey,
  service = api.service,
  endpoint = api.endpoint,
  timeout = api.timeout,

}) {

  // check input
  if (!isService (service)) {
    throw new Error ('invalid service');
  }

  if (ip !== 'me' && !isIP (ip)) {
    throw new Error ('invalid ip');
  }

  // build url
  endpoint = endpoint.replace (/\/$/, '');
  endpoint += `/geoip/v2.1/${service}/${ip}`;

  if (!endpoint.match (/^https?\:\/\//)) {
    endpoint = `https://${endpoint}`;
  }

  // build request
  const httpProps = {
    method: 'GET',
    auth: `${userId}:${licenseKey}`,
    timeout,
    headers: {
      'Accept': `application/vnd.maxmind.com-${service}+json; charset=UTF-8; version=2.1`,
      'User-Agent': 'geoip2ws.js (https://github.com/fvdm/nodejs-geoip2ws)',
    },
    url: endpoint,
  };

  // do promise
  return doRequest (httpProps)
    .then (doResponse)
  ;

}

/**
 * Module interface
 *
 * @param   {object}    args
 *
 * @param   {string}    [args.userId]                                Account user ID
 * @param   {string}    [args.licenseKey]                            Account license key
 * @param   {string}    [args.service=city]                          Account service name
 * @param   {string}    [args.endpoint='https://geoip.maxmind.com']  API hostname or url
 * @param   {number}    [args.timeout=5000]                          Request time out in milliseconds
 *
 * @return  {function}  doLookup
 */

module.exports = function setup ({

  userId = null,
  licenseKey = null,
  service = api.service,
  endpoint = api.endpoint,
  timeout = api.timeout,

} = {}) {

  api.userId = userId;
  api.licenseKey = licenseKey;
  api.service = service;
  api.endpoint = endpoint;
  api.timeout = timeout;

  return doLookup;

};
<|endoftext|>