<commit_before>var fs = require('fs')
  , f = require('util').format;

var restartAndDone = function(configuration, test) {
  configuration.manager.restart(function() {
    test.done();
  });
}

// ../topology_test_descriptions/rs/discover_arbiters.json
exports['Discover arbiters'] = {
  metadata: {
    requires: {
      topology: "replicaset"
    }
  },

  test: function(configuration, test) {
    var Server = configuration.require.Server
      , ReplSet = configuration.require.ReplSet
      , manager = configuration.manager;

    // Get the primary server
    manager.getServerManagerByType('primary', function(err, serverManager) {
      test.equal(null, err);

      // Attempt to connect
      var server = new ReplSet([{
          host: serverManager.host
        , port: serverManager.port
      }], {
        setName: configuration.setName
      });

      server.on('joined', function(_type, _server) {
        if(_type == 'arbiter') {
          server.destroy();
          test.done();
        }
      });

      // Start connection
      server.connect();
    });
  }
}

// ../topology_test_descriptions/rs/discover_passives.json
exports['Discover passives'] = {
  metadata: {
    requires: {
      topology: "replicaset"
    }
  },

  test: function(configuration, test) {
    var Server = configuration.require.Server
      , ReplSet = configuration.require.ReplSet
      , manager = configuration.manager;

    // Get the primary server
    manager.getServerManagerByType('primary', function(err, serverManager) {
      test.equal(null, err);

      // Attempt to connect
      var server = new ReplSet([{
          host: serverManager.host
        , port: serverManager.port
      }], {
        setName: configuration.setName
      });

      server.on('joined', function(_type, _server) {
        if(_type == 'passive') {
          server.destroy();
          test.done();
        }
      });

      // Start connection
      server.connect();
    });
  }
}

// ../topology_test_descriptions/rs/discover_primary.json
exports['Discover primary'] = {
  metadata: {
    requires: {
      topology: "replicaset"
    }
  },

  test: function(configuration, test) {
    var Server = configuration.require.Server
      , ReplSet = configuration.require.ReplSet
      , manager = configuration.manager;

    // Get the primary server
    manager.getServerManagerByType('primary', function(err, serverManager) {
      test.equal(null, err);

      // Attempt to connect
      var server = new ReplSet([{
          host: serverManager.host
        , port: serverManager.port
      }], {
        setName: configuration.setName
      });

      server.on('joined', function(_type, _server) {
        if(_type == 'primary') {
          server.destroy();
          test.done();
        }
      });

      // Start connection
      server.connect();
    });
  }
}

// ../topology_test_descriptions/rs/discover_secondary.json
exports['Discover secondaries'] = {
  metadata: {
    requires: {
      topology: "replicaset"
    }
  },

  test: function(configuration, test) {
    var Server = configuration.require.Server
      , ReplSet = configuration.require.ReplSet
      , manager = configuration.manager;

    // Get the primary server
    manager.getServerManagerByType('primary', function(err, serverManager) {
      test.equal(null, err);

      // Attempt to connect
      var server = new ReplSet([{
          host: serverManager.host
        , port: serverManager.port
      }], {
        setName: configuration.setName
      });

      var count = 0;
      server.on('joined', function(_type, _server) {
        if(_type == 'secondary') count = count + 1;
        if(count == 2) {
          server.destroy();
          test.done();
        }
      });

      // Start connection
      server.connect();
    });
  }
}

// ../topology_test_descriptions/rs/discovery.json
exports['Replica set discovery'] = {
  metadata: {
    requires: {
      topology: "replicaset"
    }
  },

  test: function(configuration, test) {
    var Server = configuration.require.Server
      , ReplSet = configuration.require.ReplSet
      , manager = configuration.manager;

    // State
    var state = {'primary':1, 'secondary': 2, 'arbiter': 1, 'passive': 1};
    // Get the primary server
    manager.getServerManagerByType('primary', function(err, serverManager) {
      test.equal(null, err);

      // Attempt to connect
      var server = new ReplSet([{
          host: serverManager.host
        , port: serverManager.port
      }], {
        setName: configuration.setName
      });

      server.on('joined', function(_type, _server) {
        state[_type] = state[_type] - 1;

        if(state.primary == 0
          && state.secondary == 0
          && state.arbiter == 0
          && state.passive == 0) {
          server.destroy();
          test.done();
        }
      });

      // Start connection
      server.connect();
    });
  }
}

var waitForPrimary = function(ReplSet, count, config, options, callback) {
  if(count == 0) return callback(new Error("could not connect"));
  // Attempt to connect
  var server = new ReplSet(config, options);
  server.on('error', function(err) {
    server.destroy();

    setTimeout(function() {
      waitForPrimary(ReplSet, count - 1, config, options, callback);
    }, 1000);
  });

  server.on('fullsetup', function(_server) {
    server.destroy();
    callback();
  });

  // Start connection
  server.connect();
}

// ../topology_test_descriptions/rs/ghost_discovery.json
exports['Ghost discovered/Member brought up as standalone'] = {
  metadata: {
    requires: {
      topology: "replicaset"
    }
  },

  test: function(configuration, test) {
    var Server = configuration.require.Server
      , ServerManager = configuration.require.ServerManager
      , ReplSet = configuration.require.ReplSet
      , manager = configuration.manager;

    // State
    var state = {'primary':1, 'secondary': 1, 'arbiter': 1, 'passive': 1};
    // Get the primary server
    manager.getServerManagerByType('primary', function(err, primaryServerManager) {
      test.equal(null, err);

      // Get the secondary server
      manager.getServerManagerByType('secondary', function(err, serverManager) {
        test.equal(null, err);

        // Stop the secondary
        serverManager.stop(function(err, r) {

          // Start a new server manager
          var nonReplSetMember = new ServerManager({
              host: serverManager.host
            , port: serverManager.port
            , dbpath: serverManager.dbpath
            , logpath: serverManager.logpath
          });

          // Start a non replset member
          nonReplSetMember.start(function() {
            var config = [{
                host: primaryServerManager.host
              , port: primaryServerManager.port
            }];

            var options = {
              setName: configuration.setName
            };

            // Wait for primary
            waitForPrimary(ReplSet, 30, config, options, function(err, r) {
              test.equal(null, err);

              // Attempt to connect
              var server = new ReplSet(config, options);
              server.on('joined', function(_type, _server) {
                state[_type] = state[_type] - 1;

                if(state.primary == 0
                  && state.secondary == 0
                  && state.arbiter == 0
                  && state.passive == 0) {
                  server.destroy();

                  // Stop the normal server
                  nonReplSetMember.stop(function() {
                    // Restart the secondary server
                    serverManager.start(function() {
                      test.done();
                    });
                  });
                }
              });

              // Start connection
              server.connect();
            });
          });
        });
      });
    });
  }
}

// ../topology_test_descriptions/rs/hosts_differ_from_seeds.json
exports['Host list differs from seeds'] = {
  metadata: {
    requires: {
      topology: "replicaset"
    }
  },

  test: function(configuration, test) {
    var Server = configuration.require.Server
      , ReplSet = configuration.require.ReplSet
      , manager = configuration.manager;

    // State
    var state = {'primary':1, 'secondary': 2, 'arbiter': 1, 'passive': 1};
    // Get the primary server
    manager.getServerManagerByType('primary', function(err, serverManager) {
      test.equal(null, err);

      // Attempt to connect
      var server = new ReplSet([{
          host: serverManager.host
        , port: serverManager.port
      }, {
          host: 'localhost'
        , port: 41000
      }], {
        setName: configuration.setName
      });

      server.on('joined', function(_type, _server) {
        state[_type] = state[_type] - 1;

        if(state.primary == 0
          && state.secondary == 0
          && state.arbiter == 0
          && state.passive == 0) {
          server.destroy();
          test.done();
        }
      });

      // Start connection
      server.connect();
    });
  }
}

// ../topology_test_descriptions/rs/member_reconfig.json
exports['Member removed by reconfig'] = {
  metadata: {
    requires: {
      topology: "replicaset"
    }
  },

  test: function(configuration, test) {
    var Server = configuration.require.Server
      , ServerManager = configuration.require.ServerManager
      , ReplSet = configuration.require.ReplSet
      , manager = configuration.manager;

    // State
    var state = {'primary':[], 'secondary': [], 'arbiter': [], 'passive': []};
    // Get the primary server
    manager.getServerManagerByType('primary', function(err, primaryServerManager) {
      test.equal(null, err);

      manager.getServerManagerByType('secondary', function(err, secondaryServerManager) {
        test.equal(null, err);

        var config = [{
            host: primaryServerManager.host
          , port: primaryServerManager.port
        }];

        var options = {
          setName: configuration.setName
        };

        // Contains the details for the removed server
        var removedSever = null;
        // Attempt to connect
        var server = new ReplSet(config, options);
        server.on('fullsetup', function(_server) {
          var removedServer = null;

          // Let's listen to changes
          server.on('left', function(_t, _server) {});

          server.on('joined', function(_t, _server) {
            if(_t == 'primary') {
              test.ok(server.state.primary != null);
              test.equal(1, server.state.secondaries.length);
              test.equal(1, server.state.arbiters.length);
              test.equal(1, server.state.passives.length);
              server.destroy();

              // Add back the secondary
              manager.add(removedServer, function(err) {
                test.equal(null, err);
                restartAndDone(configuration, test);
              });
            }
          });

          // Get the secondary server
          manager.remove('secondary', function(err, _removedServer) {
            test.equal(null, err);
            removedServer = _removedServer;
          });
        });

        // Start connection
        server.connect();
      });
    });
  }
}

// ../topology_test_descriptions/rs/new_primary.json
exports['New primary'] = {
  metadata: {
    requires: {
      topology: "replicaset"
    }
  },

  test: function(configuration, test) {
    var Server = configuration.require.Server
      , ServerManager = configuration.require.ServerManager
      , ReplSet = configuration.require.ReplSet
      , manager = configuration.manager;

    // State
    var state = {'primary':[], 'secondary': [], 'arbiter': [], 'passive': []};
    // Get the primary server
    manager.getServerManagerByType('primary', function(err, primaryServerManager) {
      test.equal(null, err);

      var config = [{
          host: primaryServerManager.host
        , port: primaryServerManager.port
      }];

      var options = {
        setName: configuration.setName
      };

      // Attempt to connect
      var server = new ReplSet(config, options);
      server.on('fullsetup', function(_server) {
        var removedServer = null;

        // Let's listen to changes
        server.on('left', function(_t, _server) {
          if(_t == 'primary') {
            test.equal(f('%s:%s', primaryServerManager.host, primaryServerManager.port), _server.name);
          }
        });

        server.on('joined', function(_t, _server) {
          if(_t == 'primary') {
            test.ok(server.state.primary != null);
            test.equal(2, server.state.secondaries.length);
            test.equal(1, server.state.arbiters.length);
            test.equal(1, server.state.passives.length);
            server.destroy();
            test.done();
          }
        });

        manager.stepDown(function(err) {});
      });

      // Start connection
      server.connect();
    });
  }
}

// ../topology_test_descriptions/rs/primary_becomes_standalone.json
exports['Primary becomes standalone'] = {
  metadata: {
    requires: {
      topology: "replicaset"
    }
  },

  test: function(configuration, test) {
    var Server = configuration.require.Server
      , ServerManager = configuration.require.ServerManager
      , ReplSet = configuration.require.ReplSet
      , manager = configuration.manager;

    // State
    var joined = {'primary':[], 'secondary': [], 'arbiter': [], 'passive': []};
    var left = {'primary':[], 'secondary': [], 'arbiter': [], 'passive': []};
    // Get the primary server
    manager.getServerManagerByType('primary', function(err, primaryServerManager) {
      test.equal(null, err);

      // Get the secondary server
      manager.getServerManagerByType('secondary', function(err, serverManager) {
        test.equal(null, err);

        // Start a new server manager
        var nonReplSetMember = new ServerManager({
            host: primaryServerManager.host
          , port: primaryServerManager.port
          , dbpath: primaryServerManager.dbpath
          , logpath: primaryServerManager.logpath
        });

        var config = [{
            host: serverManager.host
          , port: serverManager.port
        }];

        var options = {
          setName: configuration.setName
        };

        // Attempt to connect
        var server = new ReplSet(config, options);
        server.on('fullsetup', function(_server) {
          server.on('joined', function(_type, _server) {
            joined[_type].push(_server);

            if(_type == 'primary') {
              server.destroy();
              restartAndDone(configuration, test);
            }
          });

          server.on('left', function(_type, _server) {
            left[_type].push(_server);
          });

          // Stop the primary
          primaryServerManager.stop(function(err, r) {

            // Start a non replset member
            nonReplSetMember.start(function() {

              // Wait for primary
              waitForPrimary(ReplSet, 30, config, options, function(err, r) {
                test.equal(null, err);

                // Stop the normal server
                nonReplSetMember.stop(function() {

                  // Restart the primary server
                  primaryServerManager.start(function() {

                    // Wait for primary
                    waitForPrimary(ReplSet, 30, config, options, function(err, r) {
                      test.equal(null, err);
                      test.equal(1, left.primary.length);
                      test.equal(1, left.secondary.length);
                    });
                  });
                });
              });
            });
          });
        });

        // Start connection
        server.connect();
      });
    });
  }
}
<commit_msg>Fixed issue for UTF8 encoding collection names on wire commands, added ability to force close emission on destroy<commit_after>var fs = require('fs')
  , f = require('util').format;

var restartAndDone = function(configuration, test) {
  configuration.manager.restart(function() {
    test.done();
  });
}

// ../topology_test_descriptions/rs/discover_arbiters.json
exports['Discover arbiters'] = {
  metadata: {
    requires: {
      topology: "replicaset"
    }
  },

  test: function(configuration, test) {
    var Server = configuration.require.Server
      , ReplSet = configuration.require.ReplSet
      , manager = configuration.manager;

    // Get the primary server
    manager.getServerManagerByType('primary', function(err, serverManager) {
      test.equal(null, err);

      // Attempt to connect
      var server = new ReplSet([{
          host: serverManager.host
        , port: serverManager.port
      }], {
        setName: configuration.setName
      });

      server.on('joined', function(_type, _server) {
        if(_type == 'arbiter') {
          server.destroy();
          test.done();
        }
      });

      // Start connection
      server.connect();
    });
  }
}

// ../topology_test_descriptions/rs/discover_passives.json
exports['Discover passives'] = {
  metadata: {
    requires: {
      topology: "replicaset"
    }
  },

  test: function(configuration, test) {
    var Server = configuration.require.Server
      , ReplSet = configuration.require.ReplSet
      , manager = configuration.manager;

    // Get the primary server
    manager.getServerManagerByType('primary', function(err, serverManager) {
      test.equal(null, err);

      // Attempt to connect
      var server = new ReplSet([{
          host: serverManager.host
        , port: serverManager.port
      }], {
        setName: configuration.setName
      });

      server.on('joined', function(_type, _server) {
        if(_type == 'passive') {
          server.destroy();
          test.done();
        }
      });

      // Start connection
      server.connect();
    });
  }
}

// ../topology_test_descriptions/rs/discover_primary.json
exports['Discover primary'] = {
  metadata: {
    requires: {
      topology: "replicaset"
    }
  },

  test: function(configuration, test) {
    var Server = configuration.require.Server
      , ReplSet = configuration.require.ReplSet
      , manager = configuration.manager;

    // Get the primary server
    manager.getServerManagerByType('primary', function(err, serverManager) {
      test.equal(null, err);

      // Attempt to connect
      var server = new ReplSet([{
          host: serverManager.host
        , port: serverManager.port
      }], {
        setName: configuration.setName
      });

      server.on('joined', function(_type, _server) {
        if(_type == 'primary') {
          server.destroy();
          test.done();
        }
      });

      // Start connection
      server.connect();
    });
  }
}

// ../topology_test_descriptions/rs/discover_secondary.json
exports['Discover secondaries'] = {
  metadata: {
    requires: {
      topology: "replicaset"
    }
  },

  test: function(configuration, test) {
    var Server = configuration.require.Server
      , ReplSet = configuration.require.ReplSet
      , manager = configuration.manager;

    // Get the primary server
    manager.getServerManagerByType('primary', function(err, serverManager) {
      test.equal(null, err);

      // Attempt to connect
      var server = new ReplSet([{
          host: serverManager.host
        , port: serverManager.port
      }], {
        setName: configuration.setName
      });

      var count = 0;
      server.on('joined', function(_type, _server) {
        if(_type == 'secondary') count = count + 1;
        if(count == 2) {
          server.destroy();
          test.done();
        }
      });

      // Start connection
      server.connect();
    });
  }
}

// ../topology_test_descriptions/rs/discovery.json
exports['Replica set discovery'] = {
  metadata: {
    requires: {
      topology: "replicaset"
    }
  },

  test: function(configuration, test) {
    var Server = configuration.require.Server
      , ReplSet = configuration.require.ReplSet
      , manager = configuration.manager;

    // State
    var state = {'primary':1, 'secondary': 2, 'arbiter': 1, 'passive': 1};
    // Get the primary server
    manager.getServerManagerByType('primary', function(err, serverManager) {
      test.equal(null, err);

      // Attempt to connect
      var server = new ReplSet([{
          host: serverManager.host
        , port: serverManager.port
      }], {
        setName: configuration.setName
      });

      server.on('joined', function(_type, _server) {
        state[_type] = state[_type] - 1;

        if(state.primary == 0
          && state.secondary == 0
          && state.arbiter == 0
          && state.passive == 0) {
          server.destroy();
          test.done();
        }
      });

      // Start connection
      server.connect();
    });
  }
}

var waitForPrimary = function(ReplSet, count, config, options, callback) {
  if(count == 0) return callback(new Error("could not connect"));
  // Attempt to connect
  var server = new ReplSet(config, options);
  server.on('error', function(err) {
    server.destroy();

    setTimeout(function() {
      waitForPrimary(ReplSet, count - 1, config, options, callback);
    }, 1000);
  });

  server.on('fullsetup', function(_server) {
    server.destroy();
    callback();
  });

  // Start connection
  server.connect();
}

// ../topology_test_descriptions/rs/ghost_discovery.json
exports['Ghost discovered/Member brought up as standalone'] = {
  metadata: {
    requires: {
      topology: "replicaset"
    }
  },

  test: function(configuration, test) {
    var Server = configuration.require.Server
      , ServerManager = configuration.require.ServerManager
      , ReplSet = configuration.require.ReplSet
      , manager = configuration.manager;

    // State
    var state = {'primary':1, 'secondary': 1, 'arbiter': 1, 'passive': 1};
    // Get the primary server
    manager.getServerManagerByType('primary', function(err, primaryServerManager) {
      test.equal(null, err);

      // Get the secondary server
      manager.getServerManagerByType('secondary', function(err, serverManager) {
        test.equal(null, err);

        // Stop the secondary
        serverManager.stop(function(err, r) {

          // Start a new server manager
          var nonReplSetMember = new ServerManager({
              host: serverManager.host
            , port: serverManager.port
            , dbpath: serverManager.dbpath
            , logpath: serverManager.logpath
          });

          // Start a non replset member
          nonReplSetMember.start(function() {
            var config = [{
                host: primaryServerManager.host
              , port: primaryServerManager.port
            }];

            var options = {
              setName: configuration.setName
            };

            // Wait for primary
            waitForPrimary(ReplSet, 30, config, options, function(err, r) {
              test.equal(null, err);

              // Attempt to connect
              var server = new ReplSet(config, options);
              server.on('joined', function(_type, _server) {
                state[_type] = state[_type] - 1;

                if(state.primary == 0
                  && state.secondary == 0
                  && state.arbiter == 0
                  && state.passive == 0) {
                  server.destroy();

                  // Stop the normal server
                  nonReplSetMember.stop(function() {
                    // Restart the secondary server
                    serverManager.start(function() {
                      test.done();
                    });
                  });
                }
              });

              // Start connection
              server.connect();
            });
          });
        });
      });
    });
  }
}

// ../topology_test_descriptions/rs/hosts_differ_from_seeds.json
exports['Host list differs from seeds'] = {
  metadata: {
    requires: {
      topology: "replicaset"
    }
  },

  test: function(configuration, test) {
    var Server = configuration.require.Server
      , ReplSet = configuration.require.ReplSet
      , manager = configuration.manager;

    // State
    var state = {'primary':1, 'secondary': 2, 'arbiter': 1, 'passive': 1};
    // Get the primary server
    manager.getServerManagerByType('primary', function(err, serverManager) {
      test.equal(null, err);

      // Attempt to connect
      var server = new ReplSet([{
          host: serverManager.host
        , port: serverManager.port
      }, {
          host: 'localhost'
        , port: 41000
      }], {
        setName: configuration.setName
      });

      server.on('joined', function(_type, _server) {
        state[_type] = state[_type] - 1;

        if(state.primary == 0
          && state.secondary == 0
          && state.arbiter == 0
          && state.passive == 0) {
          server.destroy();
          test.done();
        }
      });

      // Start connection
      server.connect();
    });
  }
}

// ../topology_test_descriptions/rs/member_reconfig.json
exports['Member removed by reconfig'] = {
  metadata: {
    requires: {
      topology: "replicaset"
    }
  },

  test: function(configuration, test) {
    var Server = configuration.require.Server
      , ServerManager = configuration.require.ServerManager
      , ReplSet = configuration.require.ReplSet
      , manager = configuration.manager;

    // State
    var state = {'primary':[], 'secondary': [], 'arbiter': [], 'passive': []};
    // Get the primary server
    manager.getServerManagerByType('primary', function(err, primaryServerManager) {
      test.equal(null, err);

      manager.getServerManagerByType('secondary', function(err, secondaryServerManager) {
        test.equal(null, err);

        var config = [{
            host: primaryServerManager.host
          , port: primaryServerManager.port
        }];

        var options = {
          setName: configuration.setName
        };

        // Contains the details for the removed server
        var removedSever = null;
        // Attempt to connect
        var server = new ReplSet(config, options);
        server.on('fullsetup', function(_server) {
          var removedServer = null;

          // Let's listen to changes
          server.on('left', function(_t, _server) {});

          server.on('joined', function(_t, _server) {
            if(_t == 'primary') {
              test.ok(server.state.primary != null);
              test.equal(1, server.state.secondaries.length);
              test.equal(1, server.state.arbiters.length);
              test.equal(1, server.state.passives.length);
              server.destroy();

              // Add back the secondary
              manager.add(removedServer, function(err) {
                test.equal(null, err);
                restartAndDone(configuration, test);
              });
            }
          });

          // Get the secondary server
          manager.remove('secondary', function(err, _removedServer) {
            test.equal(null, err);
            removedServer = _removedServer;
          });
        });

        // Start connection
        server.connect();
      });
    });
  }
}

// ../topology_test_descriptions/rs/new_primary.json
exports['New primary'] = {
  metadata: {
    requires: {
      topology: "replicaset"
    }
  },

  test: function(configuration, test) {
    var Server = configuration.require.Server
      , ServerManager = configuration.require.ServerManager
      , ReplSet = configuration.require.ReplSet
      , manager = configuration.manager;

    // State
    var state = {'primary':[], 'secondary': [], 'arbiter': [], 'passive': []};
    // Get the primary server
    manager.getServerManagerByType('primary', function(err, primaryServerManager) {
      test.equal(null, err);

      var config = [{
          host: primaryServerManager.host
        , port: primaryServerManager.port
      }];

      var options = {
        setName: configuration.setName
      };

      // Attempt to connect
      var server = new ReplSet(config, options);
      server.on('fullsetup', function(_server) {
        var removedServer = null;

        // Let's listen to changes
        server.on('left', function(_t, _server) {
          if(_t == 'primary') {
            test.equal(f('%s:%s', primaryServerManager.host, primaryServerManager.port), _server.name);
          }
        });

        server.on('joined', function(_t, _server) {
          if(_t == 'primary') {
            test.ok(server.state.primary != null);
            test.equal(2, server.state.secondaries.length);
            test.equal(1, server.state.arbiters.length);
            test.equal(1, server.state.passives.length);
            server.destroy();
            test.done();
          }
        });

        manager.stepDown(function(err) {});
      });

      // Start connection
      server.connect();
    });
  }
}

// ../topology_test_descriptions/rs/primary_becomes_standalone.json
exports['Primary becomes standalone'] = {
  metadata: {
    requires: {
      topology: "replicaset"
    }
  },

  test: function(configuration, test) {
    var Server = configuration.require.Server
      , ServerManager = configuration.require.ServerManager
      , ReplSet = configuration.require.ReplSet
      , manager = configuration.manager;

    // State
    var joined = {'primary':[], 'secondary': [], 'arbiter': [], 'passive': []};
    var left = {'primary':[], 'secondary': [], 'arbiter': [], 'passive': []};
    // Get the primary server
    manager.getServerManagerByType('primary', function(err, primaryServerManager) {
      test.equal(null, err);

      // Get the secondary server
      manager.getServerManagerByType('secondary', function(err, serverManager) {
        test.equal(null, err);

        // Start a new server manager
        var nonReplSetMember = new ServerManager({
            host: primaryServerManager.host
          , port: primaryServerManager.port
          , dbpath: primaryServerManager.dbpath
          , logpath: primaryServerManager.logpath
        });

        var config = [{
            host: serverManager.host
          , port: serverManager.port
        }];

        var options = {
          setName: configuration.setName
        };

        // Attempt to connect
        var server = new ReplSet(config, options);
        server.on('fullsetup', function(_server) {
          server.on('joined', function(_type, _server) {
            joined[_type].push(_server);

            if(_type == 'primary') {
              server.destroy();
              restartAndDone(configuration, test);
            }
          });

          server.on('left', function(_type, _server) {
            left[_type].push(_server);
          });

          // Stop the primary
          primaryServerManager.stop(function(err, r) {

            // Start a non replset member
            nonReplSetMember.start(function() {

              // Wait for primary
              waitForPrimary(ReplSet, 30, config, options, function(err, r) {
                test.equal(null, err);

                // Stop the normal server
                nonReplSetMember.stop(function() {

                  // Restart the primary server
                  primaryServerManager.start(function() {

                    // Wait for primary
                    waitForPrimary(ReplSet, 30, config, options, function(err, r) {
                      test.equal(null, err);
                      test.equal(1, left.primary.length);
                      test.equal(1, left.secondary.length);
                    });
                  });
                });
              });
            });
          });
        });

        // Start connection
        server.connect();
      });
    });
  }
}
<|endoftext|>


<commit_before>"use strict";

const pkg = require("../package.json");
var _ = require("lodash");
var path = require("path");
var os = require("os");
var fs = require("fs");
var net = require("net");
var bcrypt = require("bcryptjs");
const colors = require("colors/safe");

let homePath;
let configPath;
let usersPath;
let storagePath;
let packagesPath;

const Helper = {
	config: null,
	expandHome,
	getHomePath,
	getPackagesPath,
	getPackageModulePath,
	getStoragePath,
	getConfigPath,
	getUsersPath,
	getUserConfigPath,
	getUserLogsPath,
	setHome,
	getVersion,
	getGitCommit,
	ip2hex,

	password: {
		hash: passwordHash,
		compare: passwordCompare,
		requiresUpdate: passwordRequiresUpdate,
	},
};

module.exports = Helper;

Helper.config = require(path.resolve(path.join(
	__dirname,
	"..",
	"defaults",
	"config.js"
)));

function getVersion() {
	const gitCommit = getGitCommit();
	return gitCommit ? `source (${gitCommit})` : `v${pkg.version}`;
}

let _gitCommit;
function getGitCommit() {
	if (_gitCommit !== undefined) {
		return _gitCommit;
	}
	try {
		_gitCommit = require("child_process")
			.execSync("git rev-parse --short HEAD 2> /dev/null") // Returns hash of current commit
			.toString()
			.trim();
		return _gitCommit;
	} catch (e) {
		// Not a git repository or git is not installed
		_gitCommit = null;
		return null;
	}
}

function setHome(newPath) {
	homePath = expandHome(newPath);
	configPath = path.join(homePath, "config.js");
	usersPath = path.join(homePath, "users");
	storagePath = path.join(homePath, "storage");
	packagesPath = path.join(homePath, "packages", "node_modules");

	// Reload config from new home location
	if (fs.existsSync(configPath)) {
		var userConfig = require(configPath);
		this.config = _.merge(this.config, userConfig);
	}

	if (!this.config.displayNetwork && !this.config.lockNetwork) {
		this.config.lockNetwork = true;

		log.warn(`${colors.bold("displayNetwork")} and ${colors.bold("lockNetwork")} are false, setting ${colors.bold("lockNetwork")} to true.`);
	}

	// Load theme color from manifest.json
	const manifest = require("../public/manifest.json");
	this.config.themeColor = manifest.theme_color;

	// TODO: Remove in future release
	if (this.config.debug === true) {
		log.warn("debug option is now an object, see defaults file for more information.");
		this.config.debug = {ircFramework: true};
	}

	// TODO: Remove in future release
	// Backwards compatibility for old way of specifying themes in settings
	if (this.config.theme.includes(".css")) {
		log.warn(`Referring to CSS files in the ${colors.green("theme")} setting of ${colors.green(configPath)} is ${colors.bold("deprecated")} and will be removed in a future version.`);
	} else {
		this.config.theme = `themes/${this.config.theme}.css`;
	}
}

function getHomePath() {
	return homePath;
}

function getConfigPath() {
	return configPath;
}

function getUsersPath() {
	return usersPath;
}

function getUserConfigPath(name) {
	return path.join(usersPath, name + ".json");
}

function getUserLogsPath(name, network) {
	return path.join(homePath, "logs", name, network);
}

function getStoragePath() {
	return storagePath;
}

function getPackagesPath() {
	return packagesPath;
}

function getPackageModulePath(packageName) {
	return path.join(Helper.getPackagesPath(), packageName);
}

function ip2hex(address) {
	// no ipv6 support
	if (!net.isIPv4(address)) {
		return "00000000";
	}

	return address.split(".").map(function(octet) {
		var hex = parseInt(octet, 10).toString(16);

		if (hex.length === 1) {
			hex = "0" + hex;
		}

		return hex;
	}).join("");
}

// Expand ~ into the current user home dir.
// This does *not* support `~other_user/tmp` => `/home/other_user/tmp`.
function expandHome(shortenedPath) {
	if (!shortenedPath) {
		return "";
	}

	const home = os.homedir().replace("$", "$$$$");
	return path.resolve(shortenedPath.replace(/^~($|\/|\\)/, home + "$1"));
}

function passwordRequiresUpdate(password) {
	return bcrypt.getRounds(password) !== 11;
}

function passwordHash(password) {
	return bcrypt.hashSync(password, bcrypt.genSaltSync(11));
}

function passwordCompare(password, expected) {
	return bcrypt.compare(password, expected);
}
<commit_msg>Warn if user configuration being loaded is empty<commit_after>"use strict";

const pkg = require("../package.json");
var _ = require("lodash");
var path = require("path");
var os = require("os");
var fs = require("fs");
var net = require("net");
var bcrypt = require("bcryptjs");
const colors = require("colors/safe");

let homePath;
let configPath;
let usersPath;
let storagePath;
let packagesPath;

const Helper = {
	config: null,
	expandHome,
	getHomePath,
	getPackagesPath,
	getPackageModulePath,
	getStoragePath,
	getConfigPath,
	getUsersPath,
	getUserConfigPath,
	getUserLogsPath,
	setHome,
	getVersion,
	getGitCommit,
	ip2hex,

	password: {
		hash: passwordHash,
		compare: passwordCompare,
		requiresUpdate: passwordRequiresUpdate,
	},
};

module.exports = Helper;

Helper.config = require(path.resolve(path.join(
	__dirname,
	"..",
	"defaults",
	"config.js"
)));

function getVersion() {
	const gitCommit = getGitCommit();
	return gitCommit ? `source (${gitCommit})` : `v${pkg.version}`;
}

let _gitCommit;
function getGitCommit() {
	if (_gitCommit !== undefined) {
		return _gitCommit;
	}
	try {
		_gitCommit = require("child_process")
			.execSync("git rev-parse --short HEAD 2> /dev/null") // Returns hash of current commit
			.toString()
			.trim();
		return _gitCommit;
	} catch (e) {
		// Not a git repository or git is not installed
		_gitCommit = null;
		return null;
	}
}

function setHome(newPath) {
	homePath = expandHome(newPath);
	configPath = path.join(homePath, "config.js");
	usersPath = path.join(homePath, "users");
	storagePath = path.join(homePath, "storage");
	packagesPath = path.join(homePath, "packages", "node_modules");

	// Reload config from new home location
	if (fs.existsSync(configPath)) {
		const userConfig = require(configPath);

		if (_.isEmpty(userConfig)) {
			log.warn(`The file located at ${colors.green(configPath)} does not appear to expose anything.`);
			log.warn(`Make sure it is non-empty and the configuration is exported using ${colors.bold("module.exports = { ... }")}.`);
			log.warn("Using default configuration...");
		}

		this.config = _.merge(this.config, userConfig);
	}

	if (!this.config.displayNetwork && !this.config.lockNetwork) {
		this.config.lockNetwork = true;

		log.warn(`${colors.bold("displayNetwork")} and ${colors.bold("lockNetwork")} are false, setting ${colors.bold("lockNetwork")} to true.`);
	}

	// Load theme color from manifest.json
	const manifest = require("../public/manifest.json");
	this.config.themeColor = manifest.theme_color;

	// TODO: Remove in future release
	if (this.config.debug === true) {
		log.warn("debug option is now an object, see defaults file for more information.");
		this.config.debug = {ircFramework: true};
	}

	// TODO: Remove in future release
	// Backwards compatibility for old way of specifying themes in settings
	if (this.config.theme.includes(".css")) {
		log.warn(`Referring to CSS files in the ${colors.green("theme")} setting of ${colors.green(configPath)} is ${colors.bold("deprecated")} and will be removed in a future version.`);
	} else {
		this.config.theme = `themes/${this.config.theme}.css`;
	}
}

function getHomePath() {
	return homePath;
}

function getConfigPath() {
	return configPath;
}

function getUsersPath() {
	return usersPath;
}

function getUserConfigPath(name) {
	return path.join(usersPath, name + ".json");
}

function getUserLogsPath(name, network) {
	return path.join(homePath, "logs", name, network);
}

function getStoragePath() {
	return storagePath;
}

function getPackagesPath() {
	return packagesPath;
}

function getPackageModulePath(packageName) {
	return path.join(Helper.getPackagesPath(), packageName);
}

function ip2hex(address) {
	// no ipv6 support
	if (!net.isIPv4(address)) {
		return "00000000";
	}

	return address.split(".").map(function(octet) {
		var hex = parseInt(octet, 10).toString(16);

		if (hex.length === 1) {
			hex = "0" + hex;
		}

		return hex;
	}).join("");
}

// Expand ~ into the current user home dir.
// This does *not* support `~other_user/tmp` => `/home/other_user/tmp`.
function expandHome(shortenedPath) {
	if (!shortenedPath) {
		return "";
	}

	const home = os.homedir().replace("$", "$$$$");
	return path.resolve(shortenedPath.replace(/^~($|\/|\\)/, home + "$1"));
}

function passwordRequiresUpdate(password) {
	return bcrypt.getRounds(password) !== 11;
}

function passwordHash(password) {
	return bcrypt.hashSync(password, bcrypt.genSaltSync(11));
}

function passwordCompare(password, expected) {
	return bcrypt.compare(password, expected);
}
<|endoftext|>


<commit_before>var async = require('../lib');
var assert = require('assert');
var expect = require('chai').expect;
var isBrowser = require('./support/is_browser');

describe('asyncify', function(){

    it('asyncify', function(done) {
        var parse = async.asyncify(JSON.parse);
        parse("{\"a\":1}", function (err, result) {
            assert(!err);
            expect(result.a).to.equal(1);
            done();
        });
    });

    it('asyncify null', function(done) {
        var parse = async.asyncify(function() {
            return null;
        });
        parse("{\"a\":1}", function (err, result) {
            assert(!err);
            expect(result).to.equal(null);
            done();
        });
    });

    it('variable numbers of arguments', function(done) {
        async.asyncify(function (/*x, y, z*/) {
            return arguments;
        })(1, 2, 3, function (err, result) {
            expect(result.length).to.equal(3);
            expect(result[0]).to.equal(1);
            expect(result[1]).to.equal(2);
            expect(result[2]).to.equal(3);
            done();
        });
    });

    it('catch errors', function(done) {
        async.asyncify(function () {
            throw new Error("foo");
        })(function (err) {
            assert(err);
            expect(err.message).to.equal("foo");
            done();
        });
    });

    it('dont catch errors in the callback', function(done) {
        try {
            async.asyncify(function () {})(function (err) {
                if (err) {
                    return done(new Error("should not get an error here"));
                }
                throw new Error("callback error");
            });
        } catch (err) {
            expect(err.message).to.equal("callback error");
            done();
        }
    });

    describe('promisified', function() {
        if (isBrowser()) {
            // node only tests
            return;
        }

        var names = [
            'native-promise-only',
            'bluebird',
            'es6-promise',
            'rsvp'
        ];

        names.forEach(function(name) {
            describe(name, function() {

                var Promise = require(name);
                if (typeof Promise.Promise === 'function') {
                    Promise = Promise.Promise;
                }

                it('resolve', function(done) {
                    var promisified = function(argument) {
                        return new Promise(function (resolve) {
                            setTimeout(function () {
                                resolve(argument + " resolved");
                            }, 15);
                        });
                    };
                    async.asyncify(promisified)("argument", function (err, value) {
                        if (err) {
                            return done(new Error("should not get an error here"));
                        }
                        expect(value).to.equal("argument resolved");
                        done();
                    });
                });

                it('reject', function(done) {
                    var promisified = function(argument) {
                        return new Promise(function (resolve, reject) {
                            reject(argument + " rejected");
                        });
                    };
                    async.asyncify(promisified)("argument", function (err) {
                        assert(err);
                        expect(err.message).to.equal("argument rejected");
                        done();
                    });
                });
            });
        });
    });
});
<commit_msg>Added test case to make sure that callback isn't called multiple times in asyncify<commit_after>var async = require('../lib');
var assert = require('assert');
var expect = require('chai').expect;
var isBrowser = require('./support/is_browser');

describe('asyncify', function(){

    it('asyncify', function(done) {
        var parse = async.asyncify(JSON.parse);
        parse("{\"a\":1}", function (err, result) {
            assert(!err);
            expect(result.a).to.equal(1);
            done();
        });
    });

    it('asyncify null', function(done) {
        var parse = async.asyncify(function() {
            return null;
        });
        parse("{\"a\":1}", function (err, result) {
            assert(!err);
            expect(result).to.equal(null);
            done();
        });
    });

    it('variable numbers of arguments', function(done) {
        async.asyncify(function (/*x, y, z*/) {
            return arguments;
        })(1, 2, 3, function (err, result) {
            expect(result.length).to.equal(3);
            expect(result[0]).to.equal(1);
            expect(result[1]).to.equal(2);
            expect(result[2]).to.equal(3);
            done();
        });
    });

    it('catch errors', function(done) {
        async.asyncify(function () {
            throw new Error("foo");
        })(function (err) {
            assert(err);
            expect(err.message).to.equal("foo");
            done();
        });
    });

    it('dont catch errors in the callback', function(done) {
        try {
            async.asyncify(function () {})(function (err) {
                if (err) {
                    return done(new Error("should not get an error here"));
                }
                throw new Error("callback error");
            });
        } catch (err) {
            expect(err.message).to.equal("callback error");
            done();
        }
    });

    describe('promisified', function() {
        if (isBrowser()) {
            // node only tests
            return;
        }

        var names = [
            'native-promise-only',
            'bluebird',
            'es6-promise',
            'rsvp'
        ];

        // Both Bluebird and native promises emit these events. We handle it because Bluebird
        // will report these rejections to stderr if we don't, which is a great feature for
        // normal cases, but not here, since we expect unhandled rejections:
        process.on('unhandledRejection', function () {
            // Ignore.
        });

        names.forEach(function(name) {
            describe(name, function() {

                var Promise = require(name);
                if (typeof Promise.Promise === 'function') {
                    Promise = Promise.Promise;
                }

                it('resolve', function(done) {
                    var promisified = function(argument) {
                        return new Promise(function (resolve) {
                            setTimeout(function () {
                                resolve(argument + " resolved");
                            }, 15);
                        });
                    };
                    async.asyncify(promisified)("argument", function (err, value) {
                        if (err) {
                            return done(new Error("should not get an error here"));
                        }
                        expect(value).to.equal("argument resolved");
                        done();
                    });
                });

                it('reject', function(done) {
                    var promisified = function(argument) {
                        return new Promise(function (resolve, reject) {
                            reject(argument + " rejected");
                        });
                    };
                    async.asyncify(promisified)("argument", function (err) {
                        assert(err);
                        expect(err.message).to.equal("argument rejected");
                        done();
                    });
                });

                it('callback error', function(done) {
                    var promisified = function(argument) {
                        return new Promise(function (resolve) {
                            resolve(argument + " resolved");
                        });
                    };
                    var call_count = 0;
                    async.asyncify(promisified)("argument", function () {
                        call_count++;
                        if (call_count === 1) {
                            throw new Error("error in callback");
                        }
                    });
                    setTimeout(function () {
                        expect(call_count).to.equal(1);
                        done();
                    }, 15);
                });
            });
        });
    });
});
<|endoftext|>


<commit_before>angular.module('yds').directive('ydsGridAdvanced', ['Data', 'Filters', '$timeout', '$q', function(Data, Filters, $timeout, $q){
	return {
		restrict: 'E',
		scope: {
			projectId: '@',         //id of the project that the data belong
			viewType: '@',         	//name of the array that contains the visualised data
			lang: '@',              //lang of the visualised data
			elementH: '@',          //set the height of the component
			pageSize: '@',			//set the number of results rendered on each grid page

			combobox: '@',			//set the types of the combobox filters (year, country)
			comboboxLabels: '@',	//set the labels that will be used for each combobox
			comboboxAttrs: '@'		//set the parameter each combobox will sent to the the server
		},
		templateUrl: ((typeof Drupal != 'undefined')? Drupal.settings.basePath  + Drupal.settings.yds_project.modulePath  +'/' :'') + 'templates/grid-advanced.html',
		link: function(scope, element, attrs) {
			//reference the dom elements in which the yds-grid-advanced is rendered
			var gridWrapper = angular.element(element[0].querySelector('.component-wrapper'));
			var gridContainer = angular.element(element[0].querySelector('.grid-container'));
			//set the variables which will be used for the creation of the grid
			var grid = {
				elementId: "grid" + Data.createRandomId(),
				lang: scope.lang,
				projectId: scope.projectId,
				viewType: scope.viewType,
				elementH: scope.elementH,
				pageSize: scope.pageSize,
				combobox: scope.combobox,
				comboboxLabels: scope.comboboxLabels,
				comboboxAttrs: scope.comboboxAttrs
			};

			scope.quickFilterValue = "";
			//array containing the selected data of the rendered comboboxes
			scope.comboboxFilters = [];
			//object containing the data for each different type of combobox
			scope.comboboxData = {};

			// Enable quick filtering because the advanced grid needs to show combo boxes
			scope.quickFiltering = "true";

			//check if project id attr is defined
			if(angular.isUndefined(grid.projectId) || grid.projectId.trim()=="") {
				scope.ydsAlert = "The YDS component is not properly initialized " +
					"because the projectId or the viewType attribute aren't configured properly." +
					"Please check the corresponding documentation section";
				return false;
			}

			//check if view-type attribute is empty and assign the default value
			if(_.isUndefined(grid.viewType) || grid.viewType.trim()=="")
				grid.viewType = "default";

			//check if the language attr is defined, else assign default value
			if(_.isUndefined(grid.lang) || grid.lang.trim()=="")
				grid.lang = "en";

			//check if the page size attr is defined, else assign default value
			if(_.isUndefined(grid.pageSize) || isNaN(grid.pageSize))
				grid.pageSize = "100";

			//check if the component's height attr is defined, else assign default value
			if(_.isUndefined(grid.elementH) || isNaN(grid.elementH))
				grid.elementH = 300;

			//add the unique id generated for the grid component and set its height
			gridContainer[0].id = grid.elementId;
			gridWrapper[0].style.height = grid.elementH + 'px';
			gridWrapper[0].style.marginBottom = '80px';

			/**
			 * function show errors on top of the visualization
			 **/
			var showAlert = function(alertMsg, predefined, persistent) {
				if(!predefined)
					scope.ydsAlert = alertMsg;
				else
					scope.ydsAlert = "The YDS component is not properly initialized " +
						"because the projectId or the viewType attribute aren't configured properly." +
						"Please check the corresponding documentation section";

				if (!persistent)
					$timeout(function () { scope.ydsAlert = ""; }, 2000);
			};

			/**
			 * Hide the alert
			 */
			scope.hideAlert = function() {
				scope.ydsAlert = "";
			};

			/**
			 * function to get the required data of each different type of combobox
			 **/
			var getComboFilterData = function(name, attribute) {
				var deferred = $q.defer();

				Data.getComboboxFilters(grid.projectId, "combobox." + name , attribute, grid.lang)
				.then(function(response) {
					scope.comboboxData[attribute] = response.data;

					//find the filter entry and assign the default value
					var filterObj  = _.findWhere(scope.comboboxFilters, {"attribute": attribute});
					if (!_.isUndefined(filterObj))
						filterObj.selected =  _.findWhere(response.data, response.default);

					deferred.resolve(response);
				}, function(error){
					deferred.reject(error);
				});

				return deferred.promise;
			};

			/**
			 * function to extract the combobox values defined on the element's attributes
			 **/
			var extractFilters = function () {
				//check if all the required attributes for the rendering of fthe comboboxes are defined
				if (!_.isUndefined(grid.combobox) && !_.isUndefined(grid.comboboxLabels) && !_.isUndefined(grid.comboboxAttrs)) {
					//extract and trim their values
					var filterPromises = [];
					grid.combobox = grid.combobox.replace(/ /g, "").split(",");
					grid.comboboxAttrs = grid.comboboxAttrs.replace(/ /g, "").split(",");
					grid.comboboxLabels = grid.comboboxLabels.split(",");

					//if the different combobox attributes have the same length, extract and save its values
					if (grid.combobox.length==grid.comboboxLabels.length &&
						grid.combobox.length==grid.comboboxAttrs.length &&
						grid.comboboxLabels.length==grid.comboboxAttrs.length ) {

						//iterate through the user provided comboboxes and fetch their data
						_.each(grid.combobox, function(value, index) {
							var newFilter = {
								selected: "",
								type: value,
								label: grid.comboboxLabels[index],
								attribute: grid.comboboxAttrs[index]
							};

							scope.comboboxFilters.push(newFilter);
							filterPromises.push(getComboFilterData(newFilter.type, newFilter.attribute));
						});

						//when the data of all the filters have been returned, create the corresponding visualization
						$q.all(filterPromises).then(function() {
							scope.applyComboFilters();
						}, function(error) {
							showAlert("", true, true);
						});
					} else {
						showAlert("", true, true);
					}
				} else
					showAlert("", true, true);
			};

			/**
			 * function to render the grid based on the available filters
			 **/
			var visualizeGrid = function(filters) {
				var rawData = [];
				var columnDefs = [];

				//if the grid is being rendered for the first time, create an empty grid
				if (_.isUndefined(scope.gridOptions)) {
					//Define the options of the grid component
					scope.gridOptions = {
						columnDefs: columnDefs,
						enableColResize: true,
						enableSorting: true,
						enableFilter: true,
						rowModelType: 'pagination'
					};

					new agGrid.Grid(gridContainer[0], scope.gridOptions);
					scope.gridOptions.api.setRowData(rawData);
				}

				//if the grid has already been rendered, setup a new datasource used for the paging of the results
				var dataSource = {
					pageSize: parseInt(grid.pageSize),           // define the page size of the grid
					getRows: function (params) {
						//get the data from the server using the projectId, viewType, lang and filters variable,
						//as well as the number indicating the start index of the entire resultset
						Data.getProjectVisAdvanced("grid", grid.projectId, grid.viewType, grid.lang, filters, params.startRow)
						.then(function(response) {
							//format the column definitions returned from the API and add them to the grid
							columnDefs = Data.prepareGridColumns(response.view);
							scope.gridOptions.api.setColumnDefs(columnDefs);

							//format the data returned from the API and add them to the grid
							var rowsThisPage = Data.prepareGridData(response.data, response.view);
							params.successCallback(rowsThisPage, response.pager.total);
						}, function(error) {
							showAlert(error.message, false, false);
						});
					}
				};

				scope.gridOptions.api.setDatasource(dataSource);
			};

			/**
			 * function called when the 'apply filters' btn is clicked
		 	 **/
			scope.applyComboFilters = function() {
				var appliedFilters = {};

				//iterate through the data of the rendered filters and check which of them are selected
				_.each(scope.comboboxFilters, function (filter) {
					if (filter.selected != null && !_.isUndefined(filter.selected.value))
						appliedFilters[filter.attribute] = filter.selected.value;
				});

				///if at least one of the filters is not selected show an error message
				if (_.keys(appliedFilters).length != scope.comboboxFilters.length) {
					var errorMsg = "Please select a value for all the available filters";
					showAlert(errorMsg, false, false);
				} else {
					//if the length of the quickFilter input is greater than 0, append it to the object containing the selected filters
					if (scope.quickFilterValue.trim().length>0)
						appliedFilters["filter"] = scope.quickFilterValue.trim();

					//if all the filters is selected update the grid
					visualizeGrid(appliedFilters);
				}
			};

			/**
			 * function called when the 'clear filters' btn is clicked
			 **/
			scope.clearComboFilters = function() {
				//clear the filters' error message and initialize the selected value of each filter
				scope.ydsAlert = "";

				_.each(scope.comboboxFilters, function (filter) {
					filter.selected = "";
				});
			};

			//extract the user provided filters, and render the grid
			extractFilters();
		}
	};
}]);<commit_msg>Fix grid advanced height not being applied<commit_after>angular.module('yds').directive('ydsGridAdvanced', ['Data', 'Filters', '$timeout', '$q', function(Data, Filters, $timeout, $q){
	return {
		restrict: 'E',
		scope: {
			projectId: '@',         //id of the project that the data belong
			viewType: '@',         	//name of the array that contains the visualised data
			lang: '@',              //lang of the visualised data
			elementH: '@',          //set the height of the component
			pageSize: '@',			//set the number of results rendered on each grid page

			combobox: '@',			//set the types of the combobox filters (year, country)
			comboboxLabels: '@',	//set the labels that will be used for each combobox
			comboboxAttrs: '@'		//set the parameter each combobox will sent to the the server
		},
		templateUrl: ((typeof Drupal != 'undefined')? Drupal.settings.basePath  + Drupal.settings.yds_project.modulePath  +'/' :'') + 'templates/grid-advanced.html',
		link: function(scope, element, attrs) {
			//reference the dom elements in which the yds-grid-advanced is rendered
			var gridWrapper = angular.element(element[0].querySelector('.component-wrapper'));
			var gridContainer = angular.element(element[0].querySelector('.grid-container'));
			//set the variables which will be used for the creation of the grid
			var grid = {
				elementId: "grid" + Data.createRandomId(),
				lang: scope.lang,
				projectId: scope.projectId,
				viewType: scope.viewType,
				elementH: scope.elementH,
				pageSize: scope.pageSize,
				combobox: scope.combobox,
				comboboxLabels: scope.comboboxLabels,
				comboboxAttrs: scope.comboboxAttrs
			};

			scope.quickFilterValue = "";
			//array containing the selected data of the rendered comboboxes
			scope.comboboxFilters = [];
			//object containing the data for each different type of combobox
			scope.comboboxData = {};

			// Enable quick filtering because the advanced grid needs to show combo boxes
			scope.quickFiltering = "true";

			//check if project id attr is defined
			if(angular.isUndefined(grid.projectId) || grid.projectId.trim()=="") {
				scope.ydsAlert = "The YDS component is not properly initialized " +
					"because the projectId or the viewType attribute aren't configured properly." +
					"Please check the corresponding documentation section";
				return false;
			}

			//check if view-type attribute is empty and assign the default value
			if(_.isUndefined(grid.viewType) || grid.viewType.trim()=="")
				grid.viewType = "default";

			//check if the language attr is defined, else assign default value
			if(_.isUndefined(grid.lang) || grid.lang.trim()=="")
				grid.lang = "en";

			//check if the page size attr is defined, else assign default value
			if(_.isUndefined(grid.pageSize) || isNaN(grid.pageSize))
				grid.pageSize = "100";

			//check if the component's height attr is defined, else assign default value
			if(_.isUndefined(grid.elementH) || isNaN(grid.elementH))
				grid.elementH = 300;

			//add the unique id generated for the grid component and set its height
			gridContainer[0].id = grid.elementId;
			gridContainer[0].style.height = grid.elementH + 'px';
			gridWrapper[0].style.height = grid.elementH + 'px';
			gridWrapper[0].style.marginBottom = '80px';

            /**
			 * function show errors on top of the visualization
			 **/
			var showAlert = function(alertMsg, predefined, persistent) {
				if(!predefined)
					scope.ydsAlert = alertMsg;
				else
					scope.ydsAlert = "The YDS component is not properly initialized " +
						"because the projectId or the viewType attribute aren't configured properly." +
						"Please check the corresponding documentation section";

				if (!persistent)
					$timeout(function () { scope.ydsAlert = ""; }, 2000);
			};

			/**
			 * Hide the alert
			 */
			scope.hideAlert = function() {
				scope.ydsAlert = "";
			};

			/**
			 * function to get the required data of each different type of combobox
			 **/
			var getComboFilterData = function(name, attribute) {
				var deferred = $q.defer();

				Data.getComboboxFilters(grid.projectId, "combobox." + name , attribute, grid.lang)
				.then(function(response) {
					scope.comboboxData[attribute] = response.data;

					//find the filter entry and assign the default value
					var filterObj  = _.findWhere(scope.comboboxFilters, {"attribute": attribute});
					if (!_.isUndefined(filterObj))
						filterObj.selected =  _.findWhere(response.data, response.default);

					deferred.resolve(response);
				}, function(error){
					deferred.reject(error);
				});

				return deferred.promise;
			};

			/**
			 * function to extract the combobox values defined on the element's attributes
			 **/
			var extractFilters = function () {
				//check if all the required attributes for the rendering of fthe comboboxes are defined
				if (!_.isUndefined(grid.combobox) && !_.isUndefined(grid.comboboxLabels) && !_.isUndefined(grid.comboboxAttrs)) {
					//extract and trim their values
					var filterPromises = [];
					grid.combobox = grid.combobox.replace(/ /g, "").split(",");
					grid.comboboxAttrs = grid.comboboxAttrs.replace(/ /g, "").split(",");
					grid.comboboxLabels = grid.comboboxLabels.split(",");

					//if the different combobox attributes have the same length, extract and save its values
					if (grid.combobox.length==grid.comboboxLabels.length &&
						grid.combobox.length==grid.comboboxAttrs.length &&
						grid.comboboxLabels.length==grid.comboboxAttrs.length ) {

						//iterate through the user provided comboboxes and fetch their data
						_.each(grid.combobox, function(value, index) {
							var newFilter = {
								selected: "",
								type: value,
								label: grid.comboboxLabels[index],
								attribute: grid.comboboxAttrs[index]
							};

							scope.comboboxFilters.push(newFilter);
							filterPromises.push(getComboFilterData(newFilter.type, newFilter.attribute));
						});

						//when the data of all the filters have been returned, create the corresponding visualization
						$q.all(filterPromises).then(function() {
							scope.applyComboFilters();
						}, function(error) {
							showAlert("", true, true);
						});
					} else {
						showAlert("", true, true);
					}
				} else
					showAlert("", true, true);
			};

			/**
			 * function to render the grid based on the available filters
			 **/
			var visualizeGrid = function(filters) {
				var rawData = [];
				var columnDefs = [];

				//if the grid is being rendered for the first time, create an empty grid
				if (_.isUndefined(scope.gridOptions)) {
					//Define the options of the grid component
					scope.gridOptions = {
						columnDefs: columnDefs,
						enableColResize: true,
						enableSorting: true,
						enableFilter: true,
						rowModelType: 'pagination'
					};

					new agGrid.Grid(gridContainer[0], scope.gridOptions);
					scope.gridOptions.api.setRowData(rawData);
				}

				//if the grid has already been rendered, setup a new datasource used for the paging of the results
				var dataSource = {
					pageSize: parseInt(grid.pageSize),           // define the page size of the grid
					getRows: function (params) {
						//get the data from the server using the projectId, viewType, lang and filters variable,
						//as well as the number indicating the start index of the entire resultset
						Data.getProjectVisAdvanced("grid", grid.projectId, grid.viewType, grid.lang, filters, params.startRow)
						.then(function(response) {
							//format the column definitions returned from the API and add them to the grid
							columnDefs = Data.prepareGridColumns(response.view);
							scope.gridOptions.api.setColumnDefs(columnDefs);

							//format the data returned from the API and add them to the grid
							var rowsThisPage = Data.prepareGridData(response.data, response.view);
							params.successCallback(rowsThisPage, response.pager.total);
						}, function(error) {
							showAlert(error.message, false, false);
						});
					}
				};

				scope.gridOptions.api.setDatasource(dataSource);
			};

			/**
			 * function called when the 'apply filters' btn is clicked
		 	 **/
			scope.applyComboFilters = function() {
				var appliedFilters = {};

				//iterate through the data of the rendered filters and check which of them are selected
				_.each(scope.comboboxFilters, function (filter) {
					if (filter.selected != null && !_.isUndefined(filter.selected.value))
						appliedFilters[filter.attribute] = filter.selected.value;
				});

				///if at least one of the filters is not selected show an error message
				if (_.keys(appliedFilters).length != scope.comboboxFilters.length) {
					var errorMsg = "Please select a value for all the available filters";
					showAlert(errorMsg, false, false);
				} else {
					//if the length of the quickFilter input is greater than 0, append it to the object containing the selected filters
					if (scope.quickFilterValue.trim().length>0)
						appliedFilters["filter"] = scope.quickFilterValue.trim();

					//if all the filters is selected update the grid
					visualizeGrid(appliedFilters);
				}
			};

			/**
			 * function called when the 'clear filters' btn is clicked
			 **/
			scope.clearComboFilters = function() {
				//clear the filters' error message and initialize the selected value of each filter
				scope.ydsAlert = "";

				_.each(scope.comboboxFilters, function (filter) {
					filter.selected = "";
				});
			};

			//extract the user provided filters, and render the grid
			extractFilters();
		}
	};
}]);<|endoftext|>


<commit_before>'use strict';

angular.module('hermes', [])
.provider('Hermes', function() {
	var defaultConfiguration;

	var Configuration = function() {
		this.baseUrl = '';

		this.setBaseUrl = function(url) {
			this.baseUrl = url;
		};
	};

	var Element = function(service, baseUrl, name) {
		var methods = ['get', 'put', 'post', 'patch', 'delete'];
		var url = baseUrl + '/' + name;

		_.each(methods, function(method) {
			this[method] = function(config) {
				return service.sendRequest(method, url, config || {});
			};
		}, this);

		this.element = function(name) {
			return new ELement(service, url, name);
		};
	};

	var Service = function($q, $http, configuration) {
		var builderHooks = [];
		var errorHooks = [];

		this.addBuilderHook = function(hook) {
			var defered = $q.defer();
			var index = builderHooks.length;

			builderHooks.push(hook);

			defered.promise.then(function() {
				builderHooks.splice(index);
			});

			return defered;
		};

		this.addErrorHook = function(hook) {
			var defered = $q.defer();
			var index = errorHooks.length;

			errorHooks.push(hook);

			defered.promise.then(function() {
				errorHooks.splice(index);
			});

			return defered;
		};

		this.sendRequest = function(method, url, config) {
			var defered = $q.defer();
			var request = _.merge({
				url: url,
				method: method,
				headers: {},
				params: {},
				cache: false
			}, config);

			this.processRequest({
				request: request,
				result: defered
			});

			return defered.promise;
		};

		this.processRequest = function(requestData) {
			var self = this;
			var request = _.clone(requestData.request);
			var defered = $q.defer();

			_.each(builderHooks, function(hook) {
				request = hook(request);
			});

			$http(request)
			.success(function(data, status, headers, config) {
				requestData.result.resolve(data, status, headers);
			})
			.error(function(data, status, headers, config) {
				var waiter;

				_.each(errorHooks, function(hook) {
					var result = hook(data, status, headers, request);

					if (result && _.isFunction(result.then)) {
						waiter = result;
					}
				});

				if (waiter) {
					waiter.then(function() {
						self.processRequest(requestData);
					}, function() {
						requestData.result.reject(data, status, headers);
					});
				}
			});
		};

		this.element = function(name) {
			return new Element(this, configuration.baseUrl, name);
		};
	};

	this.$get = function($q, $http) {
		return new Service($q, $http, defaultConfiguration);
	};

	this.Configuration = Configuration;
	this.Service = Service;

	defaultConfiguration = new Configuration();
});

<commit_msg>Fix rejection.<commit_after>'use strict';

angular.module('hermes', [])
.provider('Hermes', function() {
	var defaultConfiguration;

	var Configuration = function() {
		this.baseUrl = '';

		this.setBaseUrl = function(url) {
			this.baseUrl = url;
		};
	};

	var Element = function(service, baseUrl, name) {
		var methods = ['get', 'put', 'post', 'patch', 'delete'];
		var url = baseUrl + '/' + name;

		_.each(methods, function(method) {
			this[method] = function(config) {
				return service.sendRequest(method, url, config || {});
			};
		}, this);

		this.element = function(name) {
			return new ELement(service, url, name);
		};
	};

	var Service = function($q, $http, configuration) {
		var builderHooks = [];
		var errorHooks = [];

		this.addBuilderHook = function(hook) {
			var defered = $q.defer();
			var index = builderHooks.length;

			builderHooks.push(hook);

			defered.promise.then(function() {
				builderHooks.splice(index);
			});

			return defered;
		};

		this.addErrorHook = function(hook) {
			var defered = $q.defer();
			var index = errorHooks.length;

			errorHooks.push(hook);

			defered.promise.then(function() {
				errorHooks.splice(index);
			});

			return defered;
		};

		this.sendRequest = function(method, url, config) {
			var defered = $q.defer();
			var request = _.merge({
				url: url,
				method: method,
				headers: {},
				params: {},
				cache: false
			}, config);

			this.processRequest({
				request: request,
				result: defered
			});

			return defered.promise;
		};

		this.processRequest = function(requestData) {
			var self = this;
			var request = _.clone(requestData.request);
			var defered = $q.defer();

			_.each(builderHooks, function(hook) {
				request = hook(request);
			});

			$http(request)
			.success(function(data, status, headers, config) {
				requestData.result.resolve(data, status, headers);
			})
			.error(function(data, status, headers, config) {
				var waiter;

				_.each(errorHooks, function(hook) {
					var result = hook(data, status, headers, request);

					if (result && _.isFunction(result.then)) {
						waiter = result;
					}
				});

				if (waiter) {
					waiter.then(function() {
						self.processRequest(requestData);
					}, function() {
						requestData.result.reject(data, status, headers);
					});
				} else {
					requestData.result.reject(data, status, headers);
				}
			});
		};

		this.element = function(name) {
			return new Element(this, configuration.baseUrl, name);
		};
	};

	this.$get = function($q, $http) {
		return new Service($q, $http, defaultConfiguration);
	};

	this.Configuration = Configuration;
	this.Service = Service;

	defaultConfiguration = new Configuration();
});

<|endoftext|>


<commit_before>angular.module('yds').directive('ydsLineAdvanced', ['$timeout', '$q', 'Data', 'Filters', function($timeout, $q, Data, Filters){
	return {
		restrict: 'E',
		scope: {
			projectId: '@',     //id of the project that the data belong
			viewType: '@',     //name of the array that contains the visualised data
			lang: '@',          //lang of the visualised data

			showNavigator: '@', //enable or disable line chart's navigation
			exporting: '@',     //enable or disable the export of the chart
			elementH: '@',      //set the height of the component
			titleSize: '@',     //the size of the chart's main title

			combobox: '@',			//set the types of the combobox filters (year, country)
			comboboxLabels: '@',	//set the labels that will be used for each combobox
			comboboxAttrs: '@'		//set the parameter each combobox will sent to the the server
		},
		templateUrl: ((typeof Drupal != 'undefined')? Drupal.settings.basePath  + Drupal.settings.yds_project.modulePath  +'/' :'') + 'templates/line-advanced.html',
		link: function (scope, element, attrs) {
			//reference the dom element in which the yds-line-advanced is rendered
			var lineContainer = angular.element(element[0].querySelector('.line-container'));
			//set the variables which will be used for the creation of the line chart
			var line = {
				elementId: "line" + Data.createRandomId(),
				projectId: scope.projectId,
				viewType: scope.viewType,
				lang: scope.lang,
				showNavigator: scope.showNavigator,
				exporting: scope.exporting,
				elementH: scope.elementH,
				titleSize: scope.titleSize,
				combobox: scope.combobox,
				comboboxLabels: scope.comboboxLabels,
				comboboxAttrs: scope.comboboxAttrs
			};

			//array containing the selected data of the rendered comboboxes
			scope.comboboxFilters = [];
			//object containing the data for each different type of combobox
			scope.comboboxData = {};

			//check if the projectId attr is defined, else stop the process
			if (angular.isUndefined(line.projectId) || line.projectId.trim()=="") {
				scope.ydsAlert = "The YDS component is not properly configured." +
					"Please check the corresponding documentation section";
				return false;
			}

			//check if pie-type attribute is empty and assign the default value
			if(_.isUndefined(line.viewType) || line.viewType.trim()=="")
				line.viewType = "default";

			//check if the language attr is defined, else assign default value
			if(angular.isUndefined(line.lang) || line.lang.trim()=="")
				line.lang = "en";

			//check if the exporting attr is defined, else assign default value
			if(angular.isUndefined(line.showNavigator) || (line.showNavigator!="true" && line.showNavigator!="false"))
				line.showNavigator = "true";

			//check if the exporting attr is defined, else assign default value
			if(angular.isUndefined(line.exporting) || (line.exporting!="true" && line.exporting!="false"))
				line.exporting = "true";

			//check if the component's height attr is defined, else assign default value
			if(angular.isUndefined(line.elementH) || isNaN(line.elementH))
				line.elementH = 200 ;

			//check if the component's title size attr is defined, else assign default value
			if(angular.isUndefined(line.titleSize) || isNaN(line.titleSize))
				line.titleSize = 18 ;

			//add the unique id generated for the line component and set its height
			lineContainer[0].id = line.elementId;
			lineContainer[0].style.height = line.elementH + 'px';

			/**
			 * function show errors on top of the visualization
			 **/
			var showAlert = function(alertMsg, predefined, persistent) {
				if(!predefined)
					scope.ydsAlert = alertMsg;
				else
					scope.ydsAlert = "The YDS component is not properly initialized " +
						"because the projectId or the viewType attribute aren't configured properly." +
						"Please check the corresponding documentation section";

				if (!persistent)
					$timeout(function () { scope.ydsAlert = ""; }, 2000);
			};

			/**
			 * function to get the required data of each different type of combobox
			 **/
			var getComboFilterData = function(name, attribute) {
				var deferred = $q.defer();

				Data.getComboboxFilters(line.projectId, "combobox." + name , attribute, line.lang)
				.then(function(response) {
					scope.comboboxData[attribute] = response.data;

					//find the filter entry and assign the default value
					var filterObj  = _.findWhere(scope.comboboxFilters, {"attribute": attribute});
					if (!_.isUndefined(filterObj))
						filterObj.selected =  _.findWhere(response.data, response.default);

					deferred.resolve(response);
				}, function(error){
					deferred.reject(error);
				});

				return deferred.promise;
			};

			/**
			 * function to extract the combobox values defined on the element's attributes
			 **/
			var extractFilters = function () {
				//check if all the required attributes for the rendering of fthe comboboxes are defined
				if (!_.isUndefined(line.combobox) && !_.isUndefined(line.comboboxLabels) && !_.isUndefined(line.comboboxAttrs)) {
					//extract and trim their values
					var filterPromises = [];
					line.combobox = line.combobox.replace(/ /g, "").split(",");
					line.comboboxAttrs = line.comboboxAttrs.replace(/ /g, "").split(",");
					line.comboboxLabels = line.comboboxLabels.split(",");

					//if the different combobox attributes have the same length, extract and save its values
					if (line.combobox.length==line.comboboxLabels.length &&
						line.combobox.length==line.comboboxAttrs.length &&
						line.comboboxLabels.length==line.comboboxAttrs.length ) {

						//iterate through the user provided comboboxes and fetch their data
						_.each(line.combobox, function(value, index) {
							var newFilter = {
								selected: "",
								type: value,
								label: line.comboboxLabels[index],
								attribute: line.comboboxAttrs[index]
							};

							scope.comboboxFilters.push(newFilter);
							filterPromises.push(getComboFilterData(newFilter.type, newFilter.attribute));
						});

						//when the data of all the filters have been returned, create the corresponding visualization
						$q.all(filterPromises).then(function() {
							scope.applyComboFilters();
						}, function(error) {
							showAlert("", true, true);
						});
					} else {
						showAlert("", true, true);
					}
				} else
					showAlert("", true, true);
			};

			/**
			 * function to render the line chart based on the available filters
			 **/
			var visualizeLineChart = function(filters) {
				//if the line chart is being initialized for the first time
				//set its options and render the chart without data
				if (_.isUndefined(line["chart"])) {
					var options = {
						chart: { renderTo: line.elementId },
						rangeSelector : {
							enabled: (line.showNavigator === "true"),
							selected : 1
						},
						scrollbar : { enabled: (line.showNavigator === "true") },
						title : {
							text : "",
							style: { fontSize: line.titleSize + "px" }
						},
						exporting: { enabled: (line.exporting === "true") },
						navigator: { enabled: (line.showNavigator === "true") }
					};

					line["chart"] = new Highcharts.StockChart(options);
				}

				//if the chart has already been rendered, fetch data from the server and visualize the results
				Data.getProjectVisAdvanced("line", line.projectId, line.viewType, line.lang, filters)
				.then(function(response) {
					//get the title of the chart from the result
					var titlePath = response.view[0].attribute;
					var lineTitle = Data.deepObjSearch(response.data, titlePath);

					//set the chart's title
					line["chart"].setTitle({text: lineTitle});

					//remove the existing line chart series
					while(line["chart"].series.length > 0)
						line["chart"].series[0].remove(true);

					//add the new series to the line chart
					line["chart"].addSeries({
						name : response.data.series,
						data : response.data.data
					});
				}, function (error) {
					showAlert(error.message, false, false);
				});
			};

			/**
			 * function called when the 'apply filters' btn is clicked
			 **/
			scope.applyComboFilters = function() {
				var appliedFilters = {};

				//iterate through the data of the rendered filters and check which of them are selected
				_.each(scope.comboboxFilters, function (filter) {
					if (filter.selected != null && !_.isUndefined(filter.selected.value))
						appliedFilters[filter.attribute] = filter.selected.value;
				});

				///if at least one of the filters is not selected show an error message
				if (_.keys(appliedFilters).length != scope.comboboxFilters.length) {
					var errorMsg = "Please select a value for all the available filters";
					showAlert(errorMsg, false, false);
				} else {
					//if all the filters is selected update the line
					visualizeLineChart(appliedFilters);
				}
			};

			/**
			 * function called when the 'clear filters' btn is clicked
			 **/
			scope.clearComboFilters = function() {
				//clear the filters' error message and initialize the selected value of each filter
				scope.ydsAlert = "";

				_.each(scope.comboboxFilters, function (filter) {
					filter.selected = "";
				});
			};

			//extract the user provided filters, and render the line chart
			extractFilters();
		}
	};
}]);<commit_msg>Fix advanced line chart after API changes<commit_after>angular.module('yds').directive('ydsLineAdvanced', ['$timeout', '$q', 'Data', 'Filters', function($timeout, $q, Data, Filters){
	return {
		restrict: 'E',
		scope: {
			projectId: '@',     //id of the project that the data belong
			viewType: '@',     //name of the array that contains the visualised data
			lang: '@',          //lang of the visualised data

			showNavigator: '@', //enable or disable line chart's navigation
			exporting: '@',     //enable or disable the export of the chart
			elementH: '@',      //set the height of the component
			titleSize: '@',     //the size of the chart's main title

			combobox: '@',			//set the types of the combobox filters (year, country)
			comboboxLabels: '@',	//set the labels that will be used for each combobox
			comboboxAttrs: '@'		//set the parameter each combobox will sent to the the server
		},
		templateUrl: ((typeof Drupal != 'undefined')? Drupal.settings.basePath  + Drupal.settings.yds_project.modulePath  +'/' :'') + 'templates/line-advanced.html',
		link: function (scope, element, attrs) {
			//reference the dom element in which the yds-line-advanced is rendered
			var lineContainer = angular.element(element[0].querySelector('.line-container'));
			//set the variables which will be used for the creation of the line chart
			var line = {
				elementId: "line" + Data.createRandomId(),
				projectId: scope.projectId,
				viewType: scope.viewType,
				lang: scope.lang,
				showNavigator: scope.showNavigator,
				exporting: scope.exporting,
				elementH: scope.elementH,
				titleSize: scope.titleSize,
				combobox: scope.combobox,
				comboboxLabels: scope.comboboxLabels,
				comboboxAttrs: scope.comboboxAttrs
			};

			//array containing the selected data of the rendered comboboxes
			scope.comboboxFilters = [];
			//object containing the data for each different type of combobox
			scope.comboboxData = {};

			//check if the projectId attr is defined, else stop the process
			if (angular.isUndefined(line.projectId) || line.projectId.trim()=="") {
				scope.ydsAlert = "The YDS component is not properly configured." +
					"Please check the corresponding documentation section";
				return false;
			}

			//check if pie-type attribute is empty and assign the default value
			if(_.isUndefined(line.viewType) || line.viewType.trim()=="")
				line.viewType = "default";

			//check if the language attr is defined, else assign default value
			if(angular.isUndefined(line.lang) || line.lang.trim()=="")
				line.lang = "en";

			//check if the exporting attr is defined, else assign default value
			if(angular.isUndefined(line.showNavigator) || (line.showNavigator!="true" && line.showNavigator!="false"))
				line.showNavigator = "true";

			//check if the exporting attr is defined, else assign default value
			if(angular.isUndefined(line.exporting) || (line.exporting!="true" && line.exporting!="false"))
				line.exporting = "true";

			//check if the component's height attr is defined, else assign default value
			if(angular.isUndefined(line.elementH) || isNaN(line.elementH))
				line.elementH = 200 ;

			//check if the component's title size attr is defined, else assign default value
			if(angular.isUndefined(line.titleSize) || isNaN(line.titleSize))
				line.titleSize = 18 ;

			//add the unique id generated for the line component and set its height
			lineContainer[0].id = line.elementId;
			lineContainer[0].style.height = line.elementH + 'px';

			/**
			 * function show errors on top of the visualization
			 **/
			var showAlert = function(alertMsg, predefined, persistent) {
				if(!predefined)
					scope.ydsAlert = alertMsg;
				else
					scope.ydsAlert = "The YDS component is not properly initialized " +
						"because the projectId or the viewType attribute aren't configured properly." +
						"Please check the corresponding documentation section";

				if (!persistent)
					$timeout(function () { scope.ydsAlert = ""; }, 2000);
			};

			/**
			 * function to get the required data of each different type of combobox
			 **/
			var getComboFilterData = function(name, attribute) {
				var deferred = $q.defer();

				Data.getComboboxFilters(line.projectId, "combobox." + name , attribute, line.lang)
				.then(function(response) {
					scope.comboboxData[attribute] = response.data;

					//find the filter entry and assign the default value
					var filterObj  = _.findWhere(scope.comboboxFilters, {"attribute": attribute});
					if (!_.isUndefined(filterObj))
						filterObj.selected =  _.findWhere(response.data, response.default);

					deferred.resolve(response);
				}, function(error){
					deferred.reject(error);
				});

				return deferred.promise;
			};

			/**
			 * function to extract the combobox values defined on the element's attributes
			 **/
			var extractFilters = function () {
				//check if all the required attributes for the rendering of fthe comboboxes are defined
				if (!_.isUndefined(line.combobox) && !_.isUndefined(line.comboboxLabels) && !_.isUndefined(line.comboboxAttrs)) {
					//extract and trim their values
					var filterPromises = [];
					line.combobox = line.combobox.replace(/ /g, "").split(",");
					line.comboboxAttrs = line.comboboxAttrs.replace(/ /g, "").split(",");
					line.comboboxLabels = line.comboboxLabels.split(",");

					//if the different combobox attributes have the same length, extract and save its values
					if (line.combobox.length==line.comboboxLabels.length &&
						line.combobox.length==line.comboboxAttrs.length &&
						line.comboboxLabels.length==line.comboboxAttrs.length ) {

						//iterate through the user provided comboboxes and fetch their data
						_.each(line.combobox, function(value, index) {
							var newFilter = {
								selected: "",
								type: value,
								label: line.comboboxLabels[index],
								attribute: line.comboboxAttrs[index]
							};

							scope.comboboxFilters.push(newFilter);
							filterPromises.push(getComboFilterData(newFilter.type, newFilter.attribute));
						});

						//when the data of all the filters have been returned, create the corresponding visualization
						$q.all(filterPromises).then(function() {
							scope.applyComboFilters();
						}, function(error) {
							showAlert("", true, true);
						});
					} else {
						showAlert("", true, true);
					}
				} else
					showAlert("", true, true);
			};

			/**
			 * function to render the line chart based on the available filters
			 **/
			var visualizeLineChart = function(filters) {
				//if the line chart is being initialized for the first time
				//set its options and render the chart without data
				if (_.isUndefined(line.chart)) {
					var options = {
						chart: { renderTo: line.elementId },
						rangeSelector : {
							enabled: (line.showNavigator === "true"),
							selected : 1
						},
						scrollbar : { enabled: (line.showNavigator === "true") },
						title : {
							text : "",
							style: { fontSize: line.titleSize + "px" }
						},
						exporting: { enabled: (line.exporting === "true") },
						navigator: { enabled: (line.showNavigator === "true") }
					};

					line.chart = new Highcharts.StockChart(options);
				}

				//if the chart has already been rendered, fetch data from the server and visualize the results
				Data.getProjectVisAdvanced("line", line.projectId, line.viewType, line.lang, filters)
				.then(function(response) {
					// Find and set chart title
					for (var i = 0; i < response.view.length; i++) {
						if (response.view[i].header == "Title") {
							var lineTitleAttr = response.view[i].attribute;						// Get title attribute
							var lineTitle = Data.deepObjSearch(response.data, lineTitleAttr);	// Find chart title

							line.chart.setTitle({text: lineTitle});								// Set chart title
							break;
						}
					}

					// Remove the existing line chart series
					while(line.chart.series.length > 0)
						line.chart.series[0].remove(true);

					// Add the new series to the line chart
					var series = response.data.series;

					_.each(series, function(s) {
						line.chart.addSeries(s);
					});

					// Update the chart's x and y axes
					_.each(response.view, function(view) {
						if (view.header == "xAxis") {
							// Update type for x axis
							line.chart.xAxis[0].update({
								type: view.type
							});
						} else if (view.header == "yAxis") {
							// Update type for all y axes
							_.each(line.chart.yAxis, function(axis) {
								axis.update({
									type: view.type
								});
							});
						}
					});
				}, function (error) {
					showAlert(error.message, false, false);
				});
			};

			/**
			 * function called when the 'apply filters' btn is clicked
			 **/
			scope.applyComboFilters = function() {
				var appliedFilters = {};

				//iterate through the data of the rendered filters and check which of them are selected
				_.each(scope.comboboxFilters, function (filter) {
					if (filter.selected != null && !_.isUndefined(filter.selected.value))
						appliedFilters[filter.attribute] = filter.selected.value;
				});

				///if at least one of the filters is not selected show an error message
				if (_.keys(appliedFilters).length != scope.comboboxFilters.length) {
					var errorMsg = "Please select a value for all the available filters";
					showAlert(errorMsg, false, false);
				} else {
					//if all the filters is selected update the line
					visualizeLineChart(appliedFilters);
				}
			};

			/**
			 * function called when the 'clear filters' btn is clicked
			 **/
			scope.clearComboFilters = function() {
				//clear the filters' error message and initialize the selected value of each filter
				scope.ydsAlert = "";

				_.each(scope.comboboxFilters, function (filter) {
					filter.selected = "";
				});
			};

			//extract the user provided filters, and render the line chart
			extractFilters();
		}
	};
}]);<|endoftext|>