//# sourceURL=widgets/GraphWidget.js
/**
 * $Id: GraphWidget.js 282 2018-03-02 23:54:32Z patrick $
 */
/* globals define,GraphWidget */

/* 
To-Do: 
1) If messageNotify is given an array, use it as the series instead of creating our own.
*/

define( [ 'Widget', 'Job', 'jobs/SeriesTracker', 'util' ], function( Widget, Job, SeriesTracker, util ) {
	
	GraphWidget = function( elem ) {
		Widget.call( this, elem );
		this.name = "GraphWidget";
		this.title = this.getData('title', "[graph]");
		this.seriesLength = this.getData('series-length', 24);
		this.interval = this.getData('series-interval', 3600);
		this.fit = [];
		this.graph = undefined;
		this.tracker = undefined;
		$(this.elem).addClass("widget-graph");
	}

	GraphWidget.prototype = Object.create(Widget.prototype);
    GraphWidget.prototype.constructor = GraphWidget;

	GraphWidget.prototype.start = function() {
		this.loadLayout();
		
		var field = this.getData( 'source', 'Vera@default:device#32:device.temperature' );
		var key = 'SeriesTracker.' + field;

		var sourceSpec = util.parseSource( field );
		
		var tracker = Job.getInstance( SeriesTracker, key );
        tracker.wrap( this.getController().getJob(), field );
		tracker.addObserver( self );
		tracker.setSeriesLength( self.seriesLength );
		tracker.setInterval( self.interval );
        tracker.start();
		this.tracker = tracker;

        Widget.start.call( this );
	}

	GraphWidget.prototype.messageNotify = function( msg ) {
		var val = msg.value;
		var job = msg.arguments[0];

		if ( val.length < 2 ) return;
		// this.applyFilters( val );

		// Convert to x/y pairs
		var series = [];
		for (var ix=0; ix<val.length; ++ix) series.push( { x: ix, y: parseFloat(val[ix]) } );

		/* For fun, fit the series */
		this.bestFit( series );
		
		/* Display the graph; first time we have to create it */
		var rng = job.getMinMax();
		var chartElement = $('#chart', this.elem);
		$( chartElement ).html("");
		$( '#y_axis', this.elem ).html("");
		if ( true || this.graph === undefined ) {
			this.graph = new Rickshaw.Graph( {
				element: $( chartElement ).get(0),
				width: $( this.elem ).parent().width(),
				height: $( this.elem ).parent().height(),
				renderer: 'line',
				min: rng.min - 1,
				max: rng.max + 1,
				series: [ {
					name: this.title,
					color: 'steelblue',
					data: series
				}, {
					color: 'blue',
					data: this.fit
				} ]
			} );

			// var xAxis = new Rickshaw.Graph.Axis.X( { graph: this.graph } );
if (0) {			
			var yAxis = new Rickshaw.Graph.Axis.Y( { 
				graph: this.graph,
				width: 40,
				pixelsPerTick: Math.floor( 77 / 3 ),
				orientation: 'left'
				, element: $('#y_axis', this.elem).get(0)
			});
}
			this.graph.render();
		} else {
			// this.graph.update();
		}
	}

	GraphWidget.prototype.bestFit = function( series ) {
		if ( series.length < 2) {
			this.fit[0] = { x:0, y: 0 };
			this.fit[1] = this.fit[0];
			return;
		}

		var sum_x=0, sum_y=0, sum_xy=0, sum_xx=0, min_x=false, max_x=false;
		var n=0;
		$.each( series, function( ix, p ) {
			++n;
			sum_x += p.x;
			sum_y += p.y;
			sum_xy += p.x*p.y;
			sum_xx += p.x*p.x;
			min_x = ( min_x === false || min_x > p.x ) ? p.x : min_x;
			max_x = ( max_x === false || max_x < p.x ) ? p.x : max_x;
		});
		
		var m = (sum_xy - sum_x * sum_y / n) / (sum_xx - sum_x * sum_x / n);
		var b = (sum_y - m * sum_x) / n;
		var y1 = b + m * min_x;
		var y2 = b + m * max_x;

		this.fit[0] = { x:min_x, y:y1 };
		this.fit[1] = { x:max_x, y:y2 };
	}
	
	GraphWidget.prototype.click = function() {
		this.tracker.resetMinMax();
	}
	
	return GraphWidget;

}); // define
