/**
 * Service which pings an endpoint URL and estimates the latency to it.
 */
angular.module('quay').factory('PingService', [function() {
  var pingService = {};
  var pingCache = {};

  var invokeCallback = function($scope, pings, callback) {
    if (pings[0] == -1) {
      setTimeout(function() {
        $scope.$apply(function() {
          callback(-1, false, -1);
        });
      }, 0);
      return;
    }

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

    // Report the average ping.
    setTimeout(function() {
      $scope.$apply(function() {
        callback(Math.floor(sum / pings.length), true, pings.length);
      });
    }, 0);
  };

  var reportPingResult = function($scope, url, ping, callback) {
    // Lookup the cached ping data, if any.
    var cached = pingCache[url];
    if (!cached) {
      cached = pingCache[url] = {
        'pings': []
      };
    }

    // If an error occurred, report it and done.
    if (ping < 0) {
      cached['pings'] = [-1];
      invokeCallback($scope, [-1], callback);
      return;
    }

    // Otherwise, add the current ping and determine the average.
    cached['pings'].push(ping);

    // Invoke the callback.
    invokeCallback($scope, cached['pings'], callback);

    // Schedule another check if we've done less than three.
    if (cached['pings'].length < 3) {
      setTimeout(function() {
        pingUrlInternal($scope, url, callback);
      }, 1000);
    }
  };

  var pingUrlInternal = function($scope, url, callback) {
    var path = url + '?cb=' + (Math.random() * 100);
    var start = new Date();
    var xhr = new XMLHttpRequest();
    xhr.onerror = function() {
          reportPingResult($scope, url, -1, callback);
    };

    xhr.onreadystatechange = function () {
      if (xhr.readyState === xhr.HEADERS_RECEIVED) {
        if (xhr.status != 200) {
              reportPingResult($scope, url, -1, callback);
          return;
        }

            var ping = (new Date() - start);
            reportPingResult($scope, url, ping, callback);
      }
    };

    xhr.open("GET", path);
    xhr.send(null);
  };

  pingService.pingUrl = function($scope, url, callback) {
    if (pingCache[url]) {
      invokeCallback($scope, pingCache[url]['pings'], callback);
      return;
    }

    // Note: We do each in a callback after 1s to prevent it running when other code
    // runs (which can skew the results).
    setTimeout(function() {
      pingUrlInternal($scope, url, callback);
    }, 1000);
  };

  return pingService;
}]);