/*
 * NATSboard
 * Copyright (c) 2015 Fatih Cetinkaya (http://github.com/cmfatih/natsboard)
 * For the full copyright and license information, please view the LICENSE.txt file.
 */

/* jslint node: true */
'use strict';

var util    = require('util'),
    express = require('express'),
    Client  = require('./client');

module.exports = function(app) {

  if(!app || typeof app.get !== 'function') {
    throw new Error('invalid app instance');
  }

  var NATS_URL      = app.get('NATS_URL'),
      WS            = app.get('WS'),
      router        = express.Router(),
      client        = new Client(),
      serverMetrics = {
        varz: {
          connections:    [],
          mem:            [],
          cpu:            [],
          slow_consumers: [],
          in_msgs:        [],
          out_msgs:       [],
          in_bytes:       [],
          out_bytes:      []
        }
      },
      metricRates = {
        varz: {
          connections:    [],
          mem:            [],
          cpu:            [],
          slow_consumers: [],
          in_msgs:        [],
          out_msgs:       [],
          in_bytes:       [],
          out_bytes:      []
        }
      };

  // Disable client caching
  client.caching(false);

  // Gets metrics
  var getMetrics = function getMetrics() {
    return serverMetrics;
  };

  // Gets rates
  var getRates = function getRates() {
    return metricRates;
  };

  // Processes data
  var processData = function processData(url, cb) {

    if(typeof cb !== 'function') {
      throw new Error('invalid callback function');
    }
    else if(typeof url !== 'string') {
      return cb(new Error('invalid url'));
    }

    // Fetch all data
    client.fetchDataAll(url, function(err, result) {
      if(err) {
        return cb(err);
      }

      // Iterate metrics
      Object.keys(serverMetrics).forEach(function(type) {
        if(result[type]) {
          Object.keys(serverMetrics[type]).forEach(function(metric) {
            if(typeof result[type][metric] !== 'undefined') {

              // Calculate rate
              if(metricRates[type] && typeof metricRates[type][metric] !== 'undefined') {
                var metricRate = result[type][metric] || 0,
                    metricLen  = serverMetrics[type][metric].length;

                // If there is a metric then
                if(metricLen) {
                  if(['in_msgs', 'out_msgs', 'in_bytes', 'out_bytes'].indexOf(metric) !== -1) {
                    // TODO: There is no guarantee that metrics will be per second with this code
                    //       so add timestamp to metrics and calculate base on it.
                    var metricLast = serverMetrics[type][metric][serverMetrics[type][metric].length-1] || 0;
                    metricRate = metricRate-metricLast;
                  }
                }

                // Add rate
                metricRates[type][metric].push(metricRate);
                // If length is greater then limit
                if(metricRates[type][metric].length > 5) {
                  metricRates[type][metric].shift(); // remove first element
                }
              }

              // Add metric
              serverMetrics[type][metric].push(result[type][metric]);
              // If length is greater then limit
              if(serverMetrics[type][metric].length > 5) {
                serverMetrics[type][metric].shift(); // remove first element
              }
            }
          });
        }
      });

      return cb();
    });
  };

  // Fetches data periodically
  var fetcher = function fetcher(url) {
    var running = false;
    setInterval(function() {
      if(!running) {
        running = true;
        processData(url, function(err) {
          if(err) {
            console.error(err);
          }
          running = false;
        });
      }
    }, 1000);
  };

  // Pushes data periodically
  var pusher = function pusher() {
    var running = false;
    setInterval(function() {
      if(!running) {
        running = true;
        // Send data
        WS.connections.forEach(function(client) {
          client.sendText(JSON.stringify({
            timestamp: new Date().getTime(),
            rates:     getRates()
          }));
        });
        running = false;
      }
    }, 1000);
  };

  // Start fetcher
  fetcher(NATS_URL);
  console.log(util.format('Fetching data from %s', NATS_URL));

  // Start pusher
  pusher();
  console.log('Pushing data to websocket connections...');

  // Handles metrics route
  router.get('/metrics/metrics', function(req, res) {
    return res.json(getMetrics());
  });

  // Handles metrics route
  router.get('/metrics/rates', function(req, res) {
    return res.json(getRates());
  });

  // Return
  return router;
};
@@ -2046,24 +2046,100 @@
 efined') %7B%0A%0A
+              var metricTime = result%5Btype%5D._time %7C%7C new Date().getTime();%0A%0A
             
@@ -2154,24 +2154,24 @@
 culate rate%0A
-
             
@@ -2834,16 +2834,22 @@
 ength-1%5D
+.value
  %7C%7C 0;%0A 
@@ -3017,16 +3017,47 @@
 c%5D.push(
+%7Btimestamp: metricTime, value: 
 metricRa
@@ -3058,16 +3058,17 @@
 tricRate
+%7D
 );%0A     
@@ -3359,16 +3359,47 @@
 c%5D.push(
+%7Btimestamp: metricTime, value: 
 result%5Bt
@@ -3410,16 +3410,17 @@
 %5Bmetric%5D
+%7D
 );%0A     
@@ -4334,38 +4334,21 @@
    t
-imestamp: new Date().getTime()
+ype:  'rates'
 ,%0A  
@@ -4363,20 +4363,16 @@
   rates:
-    
  getRate

Change metric format