/**
 * @Author: Bachir Soussi Chiadmi <bach>
 * @Date:   18-12-2017
 * @Email:  bachir@figureslibres.io
 * @Filename: corpus.js
 * @Last modified by:   bach
 * @Last modified time: 20-12-2017
 * @License: GPL-V3
 */

/**
  * depends on :
  *

  * physics.js : http://jonobr1.com/Physics/#
  * EaselJS : https://createjs.com/docs/easeljs/modules/EaselJS.html
  *
  */

(function($, Drupal, drupalSettings) {

  EdlpCorpus = function(){
    var _activated = true;
    var _$body = $('body');
    var _$container = _$body;
    var _$canvas = $('<canvas id="corpus-map">').appendTo(_$container);
    var _canvas = _$canvas[0];
    var _ctx = _canvas.getContext('2d');
    var _canvas_props = {
      'margin_top':100,
      'margin_right':0,
      'margin_bottom':100,
      'margin_left':0
    };
    var _physics = new Physics();
    // var _stage = new createjs.Stage('corpus-map');
    var _nodes = [];
    var _articles_nodes = [];
    var _no_articles_nodes = [];
    var _nodes_by_entries = {};
    var _nodes_by_nid = {};
    var _nodes_centered = [];
    var _nodes_centered_attractions = [];

    var _playlist = [];

    // var _particules = [];
    // var _base_radius = 3; // nodes radius (real radius, not diametre)
    var _p_velocity_factor = 0.5;
    var _mouse_in = true;
    var _m_pos = {x:0, y:0};
    var _node_hover_id = -1;
    var _node_opened_id = -1;
    var _$entrees_block = $('#block-edlpentreesblock');
    var _$entrees_block_termlinks = $('a.term-link', _$entrees_block);
    var _$articles_link;
    var _node_pop_up;
    // Colors depend on drupalSettings loaded by edlp_corpus.module
    var _ecolors = drupalSettings.edlp_corpus.colors;
    console.log('Corpus : _ecolors', _ecolors);
    // Physics
    var _attracter,
        _repulser_top,
        _repulser_center,
        _repulser_bottom,
        _scrambler_TL,
        _scrambler_TR,
        _scrambler_BR,
        _scrambler_BL,
        _scrambler_CL,
        _scrambler_CR;

    //     ____      _ __
    //    /  _/___  (_) /______
    //    / // __ \/ / __/ ___/
    //  _/ // / / / / /_(__  )
    // /___/_/ /_/_/\__/____/
    function init(){
      initCanvas();
      if(_activated){
        loadCorpus();
      }else{
        _$canvas.addClass('de-activated');
      }
    };

    //   ___
    //  / __|__ _ _ ___ ____ _ ___
    // | (__/ _` | ' \ V / _` (_-<
    //  \___\__,_|_||_\_/\__,_/__/
    function initCanvas(){
      // resize the canvas to fill browser window dynamically
      window.addEventListener('resize', onResizeCanvas, false);
      onResizeCanvas();
    };
    function onResizeCanvas() {
      _canvas.width = window.innerWidth;
      _canvas.height = window.innerHeight;
      for (var i = 0; i < _nodes.length; i++) {
        _nodes[i].onResizeCanvas();
        // move _attracter and _repulser to the center again
        resizePhysics();
      }
    };

    //   ___
    //  / __|___ _ _ _ __ _  _ ___
    // | (__/ _ \ '_| '_ \ || (_-<
    //  \___\___/_| | .__/\_,_/__/
    //              |_|
    function loadCorpus(){
      // console.log('drupalSettings',drupalSettings);
      // console.log('window.location', window.location);
      var path = window.location.origin + drupalSettings.basepath + "edlp/corpus";
      $.getJSON(path, {})
        .done(function(data){
          onCorpusLoaded(data);
        })
        .fail(function(jqxhr, textStatus, error){
          onCorpusLoadError(jqxhr, textStatus, error);
        });
    };
    function onCorpusLoadError(jqxhr, textStatus, error){
      console.warn('corpus load failed', jqxhr.responseText);
    };
    function onCorpusLoaded(data){
      console.log('corpus loaded : data', data);
      // console.log('first node', data.nodes[0]);
      // buildParticles(data.nodes);
      initPhysics();
      buildNodes(data.nodes);
      initArtilesLink();
      initNodePopup();
      initEvents();
      startAnime();
    };

    //  ___ _           _
    // | _ \ |_ _  _ __(_)__ ___
    // |  _/ ' \ || (_-< / _(_-<
    // |_| |_||_\_, /__/_\__/__/
    //          |__/
    function initPhysics(){
      _attracter = _physics.makeParticle(1000);
      _attracter.fixed = true;
      _repulser_top = _physics.makeParticle(100);
      _repulser_top.fixed = true;
      _repulser_center = _physics.makeParticle(100);
      _repulser_center.fixed = true;
      _repulser_bottom = _physics.makeParticle(100);
      _repulser_bottom.fixed = true;
      _scrambler_TL = _physics.makeParticle(100);
      _scrambler_TL.fixed = true;
      _scrambler_TR = _physics.makeParticle(100);
      _scrambler_TR.fixed = true;
      _scrambler_BR = _physics.makeParticle(100);
      _scrambler_BR.fixed = true;
      _scrambler_BL = _physics.makeParticle(100);
      _scrambler_BL.fixed = true;
      _scrambler_CR = _physics.makeParticle(100);
      _scrambler_CR.fixed = true;
      _scrambler_CL = _physics.makeParticle(100);
      _scrambler_CL.fixed = true;
      // move _attracter and _repulser on window resize
      resizePhysics();
    };
    function resizePhysics(){
      // attracters
      _attracter.position = {x:_canvas.width/2, y:_canvas.height/2};
      // repulsers
      _repulser_top.position = {x:_canvas.width/2, y:0};
      _repulser_center.position = {x:_canvas.width/2, y:_canvas.height/2};
      _repulser_bottom.position = {x:_canvas.width/2, y:_canvas.height};
      // scramblers
      _scrambler_TL.position = {x:-200, y:_canvas.height/40};
      _scrambler_BL.position = {x:-200, y:_canvas.height-_canvas.height/40};
      // _scrambler_CL.position = {x:-200, y:_canvas.height/2};
      _scrambler_TR.position = {x:_canvas.width+200, y:_canvas.height/40};
      _scrambler_BR.position = {x:_canvas.width+200, y:_canvas.height-_canvas.height/40};
      // _scrambler_CR.position = {x:_canvas.width+200, y:_canvas.height/2};
    };


    //  _  _         _
    // | \| |___  __| |___ ___
    // | .` / _ \/ _` / -_|_-<
    // |_|\_\___/\__,_\___/__/
    function buildNodes(nodes){
      console.log("buildNodes", nodes);
      var d;
      for (var i in nodes) {
        d = i < 1 ? true : false;
        // _nodes.push(new Node(i,nodes[i],d));
        new Node(i,nodes[i],d);

        _playlist.push({
          'id':i,
          'nid':nodes[i].nid,
          'audio_url':nodes[i].audio_url
        });
      }
      console.log('_nodes',_nodes);
      console.log('_articles_nodes',_articles_nodes);
      console.log('_no_articles_nodes',_no_articles_nodes);
      console.log('_nodes_by_entries', _nodes_by_entries);

      console.log('_physics.attractions.length', _physics.attractions.length);
    };

    function Node(i,node,d){
      this.id = i;
      for(key in node)
        this[key] = node[key];

      // record the node in different lists
      _nodes.push(this);

      _nodes_by_nid[this.nid] = this;

      if(this.has_article == 1){
        _articles_nodes.push(this);
      }else{
        _no_articles_nodes.push(this);
      }

      for (var j = 0; j < this.entrees.length; j++) {
        if(typeof _nodes_by_entries[this.entrees[j]] == 'undefined')
          _nodes_by_entries[this.entrees[j]] = [];

        _nodes_by_entries[this.entrees[j]].push(this);
      }

      this.debug = d;
      this.mass = Math.max(1, this.entrees.length); //1;
      this.velocity_threshold = 0.01;
      // define radius regarding entries length
      switch(true){
        case this.entrees.length > 3:
          this.r = 10;
          break;
        case this.entrees.length > 1 && this.entrees.length <= 3:
          this.r = 7;
          break;
        default:
          this.r = 4;
          break;
      }

      this.e_color = 'e_col_'+this.entrees[Math.floor(Math.random(this.entrees.length))];

      this.hover = false;
      this.opened = false;
      this.faded = false;
      this.center = false;
      this.aside = false;
      this.scrambling = false;

      this.n_repulses = {};

      // prototypes
      if (typeof Node.initialized == "undefined") {

        Node.prototype.init = function(){
          this.calcWallLimits();

          this.x = this.wall_limits.left + Math.random()*(this.wall_limits.right - this.wall_limits.left);
          this.y = this.wall_limits.top  + Math.random()*(this.wall_limits.bottom - this.wall_limits.top);

          this.initPhysics();

          // if(this.id == '620'){
          //   _node_pop_up.setNode(this);
          // }
        };

        Node.prototype.initPhysics = function(){
          // particule
          this.p = _physics.makeParticle(this.mass, this.x, this.y);
          this.p.velocity = new Physics.Vector((Math.random()-0.5)*_p_velocity_factor, (Math.random()-0.5)*_p_velocity_factor);
          // attracter
          this.attract = _physics.makeAttraction(_attracter, this.p, 1000, _canvas.width*2);
          this.attract.on = false;
          // repulsers
          this.repulse_top = _physics.makeAttraction(_repulser_top, this.p, -60, _canvas.height/6);
          this.repulse_center = _physics.makeAttraction(_repulser_center, this.p, -50, _canvas.height/6);
          this.repulse_bottom = _physics.makeAttraction(_repulser_bottom, this.p, -60, _canvas.height/6);
          this.repulse_top.on = false;
          this.repulse_center.on = false;
          this.repulse_bottom.on = false;
          // Scramblers
          this.scramble_TL = _physics.makeAttraction(_scrambler_TL, this.p, -100, _canvas.height/2.5);
          this.scramble_TR = _physics.makeAttraction(_scrambler_TR, this.p, -100, _canvas.height/2.5);
          this.scramble_BR = _physics.makeAttraction(_scrambler_BR, this.p, -100, _canvas.height/2.5);
          this.scramble_BL = _physics.makeAttraction(_scrambler_BL, this.p, -100, _canvas.height/2.5);
          // this.scramble_CR = _physics.makeAttraction(_scrambler_CR, this.p, -50, _canvas.height/4);
          // this.scramble_CL = _physics.makeAttraction(_scrambler_CL, this.p, -50, _canvas.height/4);
          this.scramble_TL.on = false;
          this.scramble_TR.on = false;
          this.scramble_BR.on = false;
          this.scramble_BL.on = false;
          // this.scramble_CR.on = false;
          // this.scramble_CL.on = false;
        };

        Node.prototype.calcWallLimits = function(){
          this.wall_limits = {
            top:    _canvas_props.margin_top  +this.r,
            right:  _canvas.width  -_canvas_props.margin_right  -this.r,
            bottom: _canvas.height -_canvas_props.margin_bottom -this.r,
            left:   _canvas_props.margin_left +this.r
          }
        };

        Node.prototype.onResizeCanvas = function(){
          this.calcWallLimits();
          // TODO: when canvas is smaller what about nodes hors champs, they are coming back alone but it's too long
        };

        Node.prototype.onUpdate = function(){

          // this.p.velocity.multiplyScalar(0.99);

          if(this.center)
            this.slowDownNearCenter();

          if(!this.p.resting()){
            // this.checkVelocityThreshold();
            this.checkWallBouncing();
            this.updatePos();
          }
          if(_mouse_in && !this.aside)
            this.checkMouse();

          // if(this.debug)
          //   console.log("Node pos: ", {x:this.x, y:this.y});
          this.draw();
        };

        Node.prototype.checkVelocityThreshold = function(){
          if(!this.centered || !this.aside){
            if (Math.abs(this.p.velocity.x) < this.velocity_threshold
            && Math.abs(this.p.velocity.y) < this.velocity_threshold){
              this.p.velocity.multiplyScalar(0);
              // this.p.makeFixed();
            }
          }
        };

        Node.prototype.checkWallBouncing = function(){
          switch(true){
            case this.x < this.wall_limits.left && this.p.velocity.x < 0:
              this.p.position.x = this.wall_limits.left;
              this.p.velocity.multiplyScalarXY(-1, 1).multiplyScalar(0.75);
              break;
            case this.x > this.wall_limits.right && this.p.velocity.x > 0:
              this.p.position.x = this.wall_limits.right;
              this.p.velocity.multiplyScalarXY(-1, 1).multiplyScalar(0.75);
              break;
            case this.y < this.wall_limits.top && this.p.velocity.y < 0 :
              this.p.position.y = this.wall_limits.top;
              this.p.velocity.multiplyScalarXY(1,-1).multiplyScalar(0.75);
              break;
            case this.y > this.wall_limits.bottom && this.p.velocity.y > 0 :
              this.p.position.y = this.wall_limits.bottom;
              this.p.velocity.multiplyScalarXY(1,-1).multiplyScalar(0.75);
              break;
          }
        };

        Node.prototype.updatePos = function(){
          this.x = this.p.position.x;
          this.y = this.p.position.y;
        };

        Node.prototype.checkMouse = function(){

          if( _m_pos.x > this.x - this.r
           && _m_pos.x < this.x + this.r
           && _m_pos.y > this.y - this.r
           && _m_pos.y < this.y + this.r){
            if(_node_hover_id == -1 || _node_hover_id !== this.id){
              // console.log("Node hover", this.id);
              this.hover = true;
              _node_hover_id = this.id;
              _node_pop_up.setNode(this);
            }
          }else{
            this.hover = false;
            if (_node_hover_id == this.id) {
              _node_hover_id = -1;
              _node_pop_up.removeNode();
            }
          }
        };

        Node.prototype.open = function(){
          this.opened = true;
        };
        Node.prototype.close = function(){
          this.opened = false;
        };

        Node.prototype.fade = function(){
          this.faded = true;
        };
        Node.prototype.unFade = function(){
          this.faded = false;
        };

        Node.prototype.setCenteredOnEntree = function(tid){
          this.e_color = 'e_col_'+tid;
          this.setCentered();
        };

        Node.prototype.setCentered = function(){
          this.center = true;
          this.stopScrambling();
          this.unsetAside();
          this.attract.on = true;
        }
        Node.prototype.unsetCentered = function(){
          this.center = false;
          this.attract.on = false;
        }

        Node.prototype.slowDownNearCenter = function(){
          // smouthly slow down node near center
          // if(this.id == 1)
          //   console.log('this.p.velocity', this.p.velocity);
          this.dist_to_attracter = this.p.distanceTo(_attracter);
          if( this.dist_to_attracter < _canvas.width/4){
            if( this.p.velocity.length() > 0.4 ){
              this.p.velocity.multiplyScalar(0.995);
            }
            // if(Math.abs(this.p.velocity.x) > 1){
            //   this.p.velocity.x *= 0.99;
            // }
            // if(Math.abs(this.p.velocity.y) > 1){
            //   this.p.velocity.y *= 0.99;
            // }

          }
        }

        Node.prototype.setAside = function(){
          this.aside = true;
          // this.fade();
          this.stopScrambling();
          this.unsetCentered();
          this.repulse_top.on = true;
          this.repulse_center.on = true;
          this.repulse_bottom.on = true;
        }
        Node.prototype.unsetAside = function(){
          this.aside = false;
          // this.unFade();
          this.repulse_top.on = false;
          this.repulse_center.on = false;
          this.repulse_bottom.on = false;
        }

        Node.prototype.scramble = function(){
          this.scrambling = true;
          this.unsetCentered();
          this.unsetAside();
          this.scramble_TL.on = true;
          this.scramble_TR.on = true;
          this.scramble_BR.on = true;
          this.scramble_BL.on = true;
          // this.scramble_CR.on = true;
          // this.scramble_CL.on = true;
        }
        Node.prototype.stopScrambling = function(){
          this.scrambling = false;
          this.scramble_TL.on = false;
          this.scramble_TR.on = false;
          this.scramble_BR.on = false;
          this.scramble_BL.on = false;
          // this.scramble_CR.on = false;
          // this.scramble_CL.on = false;
        }

        Node.prototype.draw = function(){
          // carre plein
          // clouleur aléatoire ds les entrees
          // 3 tailles :
          // - 1 entree : petit carre 5px
          // - 2-3 entrees : moyen 7.5px
          // - >3 entrees : grand 10px
          // actif entouré de rouge

          _ctx.beginPath();
          _ctx.globalAlpha = this.faded ? 0.1 : 1;
          // _ctx.fillStyle = !this.p.resting() ? _ecolors[this.e_color] : 'rgb(0, 0, 0)';
          _ctx.fillStyle = _ecolors[this.e_color];
          _ctx.fillRect(this.x - this.r,this.y - this.r,this.r*2,this.r*2);

          if(this.opened){
            _ctx.lineWidth = '1px';
            _ctx.strokeStyle = 'rgb(255,0,0)';
            _ctx.strokeRect(this.x - this.r-3,this.y - this.r-3,this.r*2+6,this.r*2+6);
          }
          _ctx.globalAlpha = 1;
          _ctx.closePath();
        };

        Node.initialized = true;
      }

      this.init();
    };
    // TODO: we may convert a lot of computation into a web worker
    // https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers
    function checkParticulesCollisions(){
      // pre create vars to save memory;
      var d, full_rad, margin,
          newVelX1, newVelY1, newVelX2, newVelY2,
          makeup, angle;
      // colisions between _particules
      for (var n = 0; n < _nodes.length; n++) {

        // avoid colliding for centered nodes
        // if(_nodes[n].center) continue;

        // avoid colliding for scrambling nodes
        if(_nodes[n].scrambling) continue;

        for (var q = n+1; q < _nodes.length; q++) {
          if(q===n) continue;


          // avoid impact between center and aside particules
          if((_nodes[n].center && _nodes[q].aside) || (_nodes[n].aside && _nodes[q].center))
            continue;

          // TODO: what if centered nodes are repulsing each other ??

          margin = _nodes[n].center ? 1 : 1;

          // avoid impact between two centered particulses that comes to the center
          if(_nodes[n].center && _nodes[q].center){
            if(Math.min(_nodes[n].p.distanceTo(_attracter), _nodes[q].p.distanceTo(_attracter)) > 300){
              if( Math.random()>0.3 ) continue;
            }
          }

          d = _nodes[n].p.distanceTo(_nodes[q].p);

          full_rad = _nodes[n].r*margin + _nodes[q].r*margin;

          // if not colliding skip following
          if(d > full_rad) continue;

          // apply new forces if colliding
          newVelX1 = (_nodes[n].p.velocity.x * (_nodes[n].p.mass - _nodes[q].p.mass)
                      + (2 * _nodes[q].p.mass * _nodes[q].p.velocity.x)) / (_nodes[n].p.mass + _nodes[q].p.mass);
          newVelY1 = (_nodes[n].p.velocity.y * (_nodes[n].p.mass - _nodes[q].p.mass)
                      + (2 * _nodes[q].p.mass * _nodes[q].p.velocity.y)) / (_nodes[n].p.mass + _nodes[q].p.mass);
          newVelX2 = (_nodes[q].p.velocity.x * (_nodes[q].p.mass - _nodes[n].p.mass)
                      + (2 * _nodes[n].p.mass * _nodes[n].p.velocity.x)) / (_nodes[n].p.mass + _nodes[q].p.mass);
          newVelY2 = (_nodes[q].p.velocity.y * (_nodes[q].p.mass - _nodes[n].p.mass)
                      + (2 * _nodes[n].p.mass * _nodes[n].p.velocity.y)) / (_nodes[n].p.mass + _nodes[q].p.mass);

          _nodes[n].p.velocity.x = newVelX1;
          _nodes[n].p.velocity.y = newVelY1;
          _nodes[q].p.velocity.x = newVelX2;
          _nodes[q].p.velocity.y = newVelY2;

          // slow down particule on impact
          _nodes[n].p.velocity.multiplyScalar(_nodes[n].center && _nodes[n].p.velocity.length() < 1 ? 1.1 : 0.90);
          _nodes[q].p.velocity.multiplyScalar(_nodes[q].center && _nodes[q].p.velocity.length() < 1 ? 1.1 : 0.90);


          // move particles if they overlap
          if (d < full_rad) {
            makeup = (full_rad/2 - d/2)*1.2;
            angle = Math.atan2(_nodes[q].p.position.y - _nodes[n].p.position.y, _nodes[q].p.position.x - _nodes[n].p.position.x);

            _nodes[q].p.position.x += makeup * Math.cos(angle);
            _nodes[q].p.position.y += makeup * Math.sin(angle);

            angle += Math.PI;

            _nodes[n].p.position.x += makeup * Math.cos(angle);
            _nodes[n].p.position.y += makeup * Math.sin(angle);

          }

        }
      }
    };
    // show opened audio node
    function openNode(id){
      closeNode();
      _node_opened_id = id;
      _nodes[id].open();
    }
    function closeNode(){
      if(_node_opened_id != -1){
        _nodes[_node_opened_id].close();
        _node_opened_id = -1;
      }
    }
    function createNodesRepulsions(){
      // how to delete all these attractions before creates new once
      console.log('_nodes_centered', _nodes_centered);
      purgeNodesRepulsions();
      for (var n = 0; n < _nodes_centered.length; n++) {
        for (var q = n+1; q < _nodes_centered.length; q++) {
          _physics.makeAttraction(_nodes_centered[n].p, _nodes_centered[q].p, -0.4, 10);
        }
      }
    };
    function purgeNodesRepulsions(){
      // console.log('_physics.attractions.length', _physics.attractions.length);
      for (var a = _physics.attractions.length-1; a >= 0; a--) {
        // assuming that only nodes repulsions have constant < 1
        // and are all at the end of array
        if(Math.abs(_physics.attractions[a].constant) < 1){
          _physics.attractions.splice(a,1);
        }else{
          break;
        }
      }
      // console.log('_physics.attractions.length', _physics.attractions.length);
    };

    //  ___     _
    // | __|_ _| |_ _ _ ___ ___ ___
    // | _|| ' \  _| '_/ -_) -_|_-<
    // |___|_||_\__|_| \___\___/__/
    function filterEntree(t){
      // shuydown articles if active
      if(_$articles_link.is('.is-active'))
        _$articles_link.trigger('click');

      _nodes_centered = [];
      for (var n = 0; n < _nodes.length; n++) {
        if(_nodes[n].entrees.indexOf(t) == -1){
          _nodes[n].setAside();
        }else{
          _nodes[n].setCenteredOnEntree(t);
          // record centered nodes for inter node repulsions
          _nodes_centered.push(_nodes[n]);
        }
      }
      createNodesRepulsions();
    };
    function highlightEntries(){
      _$entrees_block_termlinks.removeClass('highlighted');
      var entree;
      for (var i = 0; i < _nodes[_node_hover_id].entrees.length; i++) {
        entree = _nodes[_node_hover_id].entrees[i];
        _$entrees_block_termlinks.filter(function(){
          return $(this).attr('tid') == entree;
        }).addClass('highlighted');
      }
    };

    //  ___                    _    _ _
    // / __| __ _ _ __ _ _ __ | |__| (_)_ _  __ _
    // \__ \/ _| '_/ _` | '  \| '_ \ | | ' \/ _` |
    // |___/\__|_| \__,_|_|_|_|_.__/_|_|_||_\__, |
    //                                      |___/
    function scrambleCollection(){
      for (var i = 0; i < _nodes.length; i++) {
        _nodes[i].scramble();
      }
      // setTimeout(stopScrambling, 2000);
      stopScrambling();
    };
    function stopScrambling(){
      for (var i = 0; i < _nodes.length; i++) {
        setTimeout(function(n){
          n.stopScrambling();
        }.bind(this, _nodes[i]), 1000 + Math.random()*4000);
      }
    };
    function closeAllEntries(){
      _$entrees_block_termlinks.each(function(index, el) {
        if($(this).parents('li').is('.opened')){
          $(this).trigger('click');
          return false;
        }
      });
    };

    //    _       _   _    _
    //   /_\  _ _| |_(_)__| |___ ___
    //  / _ \| '_|  _| / _| / -_|_-<
    // /_/ \_\_|  \__|_\__|_\___/__/
    function initArtilesLink(){
     // add "articles link to blockentrees"
     _$articles_link = $('<a>')
       .html('Articles')
       .attr("href", "#articles")
       .addClass('articles-link')
       .on('click', onCLickedOnArticles);

       $('.item-list ul',_$entrees_block).append(
         $('<li>').append(
           $('<span class="oblique-wrapper">').append(_$articles_link)
         )
       );
    };
    function onCLickedOnArticles(e){
      e.preventDefault();
      $(this).toggleClass('is-active');
      if($(this).is('.is-active')){
        filterArticles();
        closeAllEntries();
      }else{
        resetArticlesFilter();
      }
      // _$canvas.trigger({
      //   'type':'corpus-cliqued-on-articles'
      // });
      return false;
    };
    function filterArticles(){
      console.log('filterArticles');
      for (var i = 0; i < _no_articles_nodes.length; i++) {
        _no_articles_nodes[i].fade();
      }
    };
    function resetArticlesFilter(){
      console.log('resetArticlesFilter');
      for (var i = 0; i < _no_articles_nodes.length; i++) {
        _no_articles_nodes[i].unFade();
      }
    };

    //  ___             _
    // | __|_ _____ _ _| |_ ___
    // | _|\ V / -_) ' \  _(_-<
    // |___|\_/\___|_||_\__/__/
    function initEvents(){
      _$canvas
        .on('mousemove', function(event) {
          event.preventDefault();
          _m_pos.x = event.originalEvent.clientX;
          _m_pos.y = event.originalEvent.clientY;
        })
        .on('mouseenter', function(event){
          // console.log('onMouseIN');
          _mouse_in = true;
        })
        .on('mouseout', function(event){
          // console.log('onMouseOUT');
          _mouse_in = false;
          _node_pop_up.removeNode();
        })
        .on('click', function(event) {
          if(event.target.tagName != "A" && event.target.tagName != "INPUT"){
            // console.log("Corpus : click");
            event.preventDefault();
            if(_node_hover_id != -1){
              // console.log("corpus : click on node", _nodes[_node_hover_id]);
              var event = {
                'type':'corpus-cliked-on-node',
                'target_node':{
                  'id':_node_hover_id,
                  'nid':_nodes[_node_hover_id].nid,
                  'audio_url':_nodes[_node_hover_id].audio_url
                },
              };
              _$canvas.trigger(event);
              // instead of directly opening the doc, create an event listener (e.g. : audio played from random)
              // openNode(_node_hover_id);
            }else{
              // console.log('corpus : click on map');
              _$canvas.trigger('corpus-cliked-on-map');
            }
          }
        })
        .on('audio-node-opened', function(e){
          openNode(e.id);
        })
        .on('audio-node-closed', function(e){
          closeNode();
        });

      _$entrees_block_termlinks.on('click', function(event) {
        event.preventDefault();
        var tid = $(this).attr('tid');
        var $li = $(this).parents('li');
        if(!$li.is('.opened')){
          _$entrees_block_termlinks.parents('li').removeClass('opened');
          $li.addClass('opened');
          filterEntree(tid);
          _$body.trigger({'type':'open_entree', 'tid':tid});
        }else{
          $li.removeClass('opened');
          scrambleCollection();
          _$body.trigger({'type':'close_entree', 'tid':tid});
        }

        return false;
      });

      // $('body').trigger({
      //       'type':'chutier-action-done',
      //       'action_done':data.action_done,
      //       'target_id':$link.attr('target_id'),
      //     });
      _$body.on('chutier-action-done', function(e) {
        _nodes_by_nid[e.target_id].chutier_action = e.new_action;
      });
    };

    //  _  _         _     ___          _   _
    // | \| |___  __| |___| _ \___ _ __| | | |_ __
    // | .` / _ \/ _` / -_)  _/ _ \ '_ \ |_| | '_ \
    // |_|\_\___/\__,_\___|_| \___/ .__/\___/| .__/
    //                            |_|        |_|
    function initNodePopup(){
      _node_pop_up = new NodePopUp();
    };
    function NodePopUp(){
      this.visible = false;
      this.node;
      this.$dom = $('<div>')
        .addClass('node-popup')
        .attr('pos', 'top-right')
        .appendTo('body');
      this.$content = $('<div>').addClass('inner').appendTo(this.$dom);

      if (typeof NodePopUp.initialized == "undefined") {

        NodePopUp.prototype.setNode = function(n){
          // console.log('NodePopUp setNode()');
          this.node = n;
          // positioning NodePopUp regarding node position
          this.setPositioning();
          // update NodePopUp content
          this.setContent();
        };

        NodePopUp.prototype.setPositioning = function(){
          switch(true){
            case this.node.x > this.node.wall_limits.right-350 && this.node.y < this.node.wall_limits.top+200:
              this.$dom.attr('pos', 'bottom-left');
              break;
            case this.node.x > this.node.wall_limits.right-350:
              this.$dom.attr('pos', 'top-left');
              break;
            case this.node.y < this.node.wall_limits.top+200:
              this.$dom.attr('pos', 'bottom-right');
              break;
            default:
              this.$dom.attr('pos', 'top-right');
          }
        };

        NodePopUp.prototype.setContent = function(){
          // console.log(this.node);
          this.$content.html('');
          var $entrees = $('<div>').addClass('entrees');
          for (var i = 0; i < this.node.entrees.length; i++) {
            var tid = this.node.entrees[i];
            $entrees.append($('<span>').addClass('entree').attr('tid', tid));
          }
          var $chutier_action = $('<span>').addClass('chutier-icon').attr('action', this.node.chutier_action);
          this.$content
            .append($entrees)
            .append('<h2 class="title">'+this.node.title+'</h2>')
            .append('<section class="description">'+this.node.description+'</section>')
            .append($chutier_action);

          // TODO: favoris marker
        };

        NodePopUp.prototype.removeNode = function(){
          // console.log('NodePopUp removeNode()');
          this.node = false;
        };

        NodePopUp.prototype.draw = function(){
          if(this.node){
            this.$dom.css({
              'display':"block",
              'left':this.node.x+"px",
              'top':this.node.y+"px",
            });
          }else{
            this.$dom.css({
              'display':"none",
            });
          }
        };

        NodePopUp.initialized = true;
      }
    }

    //  ___             _
    // | _ \___ _ _  __| |___ _ _
    // |   / -_) ' \/ _` / -_) '_|
    // |_|_\___|_||_\__,_\___|_|
    function render(){
      _ctx.clearRect(0, 0, _canvas.width, _canvas.height);

      checkParticulesCollisions();

      for (var i = 0; i < _nodes.length; i++) {
        _nodes[i].onUpdate();
      }

      _node_pop_up.draw();

      if(_node_hover_id != -1){
        _canvas.style.cursor = 'pointer';
        highlightEntries();
        // _node_pop_up.visible = true;
      }else{
        _canvas.style.cursor = 'auto';
        _$entrees_block_termlinks.removeClass('highlighted');
        // _node_pop_up.visible = false;
      }
    };

    //  ___ _            _     _        _
    // / __| |_ __ _ _ _| |_  /_\  _ _ (_)_ __  ___
    // \__ \  _/ _` | '_|  _|/ _ \| ' \| | '  \/ -_)
    // |___/\__\__,_|_|  \__/_/ \_\_||_|_|_|_|_\___|
    function startAnime(){
      _physics.onUpdate(render);
      _physics.play()
      $('body').trigger({
        'type':'corpus-map-ready',
        'playlist':_playlist
      });
    };

    init();
  }


  $(document).ready(function($) {
    var edlpcorpus = new EdlpCorpus();
  });


})(jQuery, Drupal, drupalSettings);
