var io = require('socket.io').listen(8000),
  http = require('http');

var graphiteHost = 'CHANGE-ME-YOU-NOOB',
  handlers = [];

io.enable('browser client minification');
io.enable('browser client etag');
io.enable('browser client gzip');
io.set('log level', 1);

function buildQueryString(parameters) {
  'use strict';
  var queryParameters = [];

  parameters.targets.forEach(function(target) {
    queryParameters.push('target=' + target);
  });

  queryParameters.push('from=' + parameters.from);
  queryParameters.push('format=json');

  return(queryParameters.join('&'));
}

function processHandlers() {
  'use strict';
  handlers.map(function(handler) {
    if (handler.shouldUpdate()) {
      handler.data(function(data) {
        handler.socket.emit('metricData', {id: handler.id, metrics: data});
      });
    }
  });

  setTimeout(processHandlers, 1000);
}

function MetricHandler(socket, params) {
  'use strict';
  var from = typeof(params.from) !== 'undefined' ? params.from : '-24h',
    lastUpdateTime = 0,
    updateInterval = typeof(params.updateInterval) !== 'undefined' ? params.updateInterval : 5000,
    queryParameters = {
      'targets': params.targets,
      'from': from
    };

  this.id = params.id;
  this.socket = socket;

  this.addTarget = function(target) {
    queryParameters.targets.push(target);
  };

  this.removeTarget = function(target) {
    var index = queryParameters.targets.indexOf(target);
    queryParameters.targets.splice(index, 1);
  };

  this.data = function(callback) {
    var httpOptions = {
        host: graphiteHost,
        port: 80,
        path: '/render?' + buildQueryString(queryParameters)
      },
      metricData = '';

    http.get(httpOptions, function(res) {
      res.on('data', function(chunk) {
        metricData += chunk.toString();
      }).on('error', function(e) {
        console.log('Got error: ' + e.message);
      }).on('end', function() {
        lastUpdateTime = new Date().getTime();
        callback(metricData);
      });
    });
  };

  this.shouldUpdate = function() {
    if ((lastUpdateTime + updateInterval) < new Date().getTime()) {
      if (lastUpdateTime > 0) {
        queryParameters.from = Math.floor((lastUpdateTime - (updateInterval * 3)) / 1000);
      }
      return(true);
    } else {
      return(false);
    }
  };
}

io.sockets.on('connection', function(socket) {
  'use strict';
  socket.on('fetchMetrics', function(params) {
    handlers.push(new MetricHandler(socket, params));
  }).on('addTarget', function(target) {
    handlers.forEach(function(handler) {
      if (handler.socket === socket) {
        handler.addTarget(target);
      }
    });
  }).on('removeTarget', function(target) {
    handlers.forEach(function(handler) {
      if (handler.socket === socket) {
        handler.removeTarget(target);
      }
    });
  });
});

processHandlers();

@@ -931,195 +931,25 @@
 var 
-from = typeof(params.from) !== 'undefined' ? params.from : '-24h',%0A    lastUpdateTime = 0,%0A    updateInterval = typeof(params.updateInterval) !== 'undefined' ? params.updateInterval : 500
+lastUpdateTime = 
 0,%0A 
@@ -1018,16 +1018,23 @@
 'from': 
+params.
 from%0A   
@@ -1901,16 +1901,44 @@
     if (
+(params.refresh === true && 
 (lastUpd
@@ -1947,16 +1947,23 @@
 eTime + 
+params.
 updateIn
@@ -1968,17 +1968,16 @@
 Interval
-)
  %3C new D
@@ -1988,24 +1988,50 @@
 ).getTime())
+) %7C%7C lastUpdateTime === 0)
  %7B%0A      if 
@@ -2114,16 +2114,23 @@
 Time - (
+params.
 updateIn

clean up MetricHandler parameters and support passing refresh flag