/*
Flot plugin for for highlighting gaps in the x-axis, mainly intended
for time series data where there may be missing readings. Controlled either
globally in the series options:

  series: {
    showgaps: {
      rounding: number
    }
  }

or in a specific series

  $.plot($("#placeholder"), [{ data: [ ... ], showgaps: { ... }}])

The plugin works by determining the mode interval between data points and then treating
any readings less frequent than that as gaps. Gaps are indicated by the insertion of nulls
into the dataset to force a break in the line.

The "rounding" parameter allows you to specify wiggle room, so that, for example, intervals
of 60 minutes and 60.1 minutes are considered equal. It is specified in milliseconds

@todo add options for hilighting datapoints which are more frequent than the mode interval.

*/

(function ($)
{
    var options = {
        series: { 
            showgaps: {rounding:0}
        }
    };
    
    function init(plot)
    {
        function showgaps(plot, s, datapoints)
        {
            if (!s.showgaps) return;

            var ps = datapoints.pointsize;
            var rounding = s.showgaps.rounding;
            var origpoints = datapoints.points;
            var bins = [];
            var binned;
            var mode;
            var i,j,x,p;
            var diff;
            var newpoints = [];

            //sort intervals into buckets.
            for (i = 0; i < origpoints.length; i += ps)
            {
                lastx = x;
                x = origpoints[i];
                
                if(lastx)
                {
                    diff = Math.abs(x - lastx);
                    binned = false;
                    for(j in bins)
                    {
                        if(bins[j].val-diff < rounding)
                        {
                            bins[j].val = ( (bins[j].count * bins[j].val) + diff) / ++bins[j].count;
                            binned = true;
                        }
                    }
                    if(!binned)
                    {
                        bins.push({val:diff,count:1});
                    }
                }
            }

            //determine mode
            j=0;
            for(i in bins)
            {
                if(bins[j].count < bins[i].count) j = i;
            }
            mode = bins[j].val;

            //process data
            lastx=null;
            x = null;
            for (i = 0; i < origpoints.length; i += ps)
            {
                lastx = x;
                x = origpoints[i];
                diff = Math.abs(x - lastx);
                if(lastx && (mode - diff < rounding))
                {
                    //insert null point to create gap
                    for(j=0;j<ps;j++)
                    {
                        newpoints.push(null);
                    }
                }
                //and add current point
                for(j=0;j<ps;j++)
                {
                    newpoints.push(origpoints[i+j]);
                }
            }
            datapoints.points = newpoints;
        }
    }
    
    $.plot.plugins.push({
        init: init,
        options: options,
        name: 'showgaps',
        version: '1.0'
    });
})(jQuery);
