/*
 * Shows buzz stats on permalink page (/user/buzz-uri)
 *
 * Assigns a handler to buzz_stats bucket (runs on page load)
 * 	- retrieves stats from amazon ec2 server
 * 			example cloud url: http://75.101.131.10/cloud/hourly_panel?buzzid=335405
 *
 * 	- generates google chart with stats
 * 	- displays stats, google chart, and top linker domains
 *
 *	Bucket is defined in tt/public/permalinks/_buzz_stats.tt
 *	See universal_dom_handler.js for more information on how buckets work
 *
 * To test out google chart URLs:
 * 	http://code.google.com/apis/chart/docs/chart_playground.html
 */
function BF_buzz_stats( name ) {
	
	/* 
	 * Object must be accessible globally by name, 
	 * so that amazon callback can run
	 */
	this.name = name;
	var fn = window[name] = this;
	
	// Root template node
	var node;

	// # of hours expected in hourly stats
	// This is necessary because cloud returns awkward array
	var hours = 72;

	/* PUBLIC FUNCTIONS */
	
	/*
	 * Assign handler to element that started this process
	 * in public/permalinks/_buzz_stats.tt
	 * (rel:bf_bucket_data in template)
	 */
	universal_dom.assign_handler( {
		bucket: "buzz_stats", 
		event: "click", 
		handler: function( ev ) {
			
			var el = ev.target;
			var buzz_id = el.getAttribute( "rel:buzz_id" );
			var node = el.getAttribute( "rel:node" );
		
			// Store root buzz_stats node in object
			fn.node = $$( node )[0];
			
			// Hide clicked button
			el.className = "hidden";
			
			// Spinner shows activity
			fn.node.select( ".spinner" )[0].removeClassName( "hidden" );

			// Get stats from amazon
			stats( buzz_id );
		}
	} );

	/* PUBLIC FUNCTIONS */

	/*
	 * Callback from amazon stats retrieval
	 */
	this.update = function( stats ) {

		var el = fn.node;

		// Base chart size on template styling
		var img = el.select( "img.chart" )[0];
		var size = {
			width: 	parseInt( img.getStyle( "width" ) ),
			height: 	parseInt( img.getStyle( "height" ) )
		};

		//var image_url = pie_chart_url( viral, seed, size );
		var image_url = sparkline_chart_url( stats, size );

		var counts = count( stats );	

		// Values into DOM
		update_values( el, counts, image_url );

		// Hide displaying of views elsewhere in page
		hide_local_views();

		// Update Domain favicons
		update_top_domains( el, stats.domains );
		
		// Hide local stats
		el.select( ".local_stats" )[0].addClassName( "hidden" );
		// Show remote stats
		el.select( ".remote_stats" )[0].removeClassName( "hidden" );
	};

	/* PRIVATE FUNCTIONS */

	/*
	 * Return dictionary of * viral, seed, total, shares, and viral list counts
	 */
	function count( stats ) {
		
		// use existing stats
		var shares = $('buzz_stats_share_totals').innerHTML;
		var impressions = $('buzz_stats_impression_totals').innerHTML.replace(/,/g, '');

		var counts = {
			viral: 	stats.all_rollup[ "Viral Impressions" ], 
			total: impressions,
			shares:	shares 
		};

		counts.seed = counts.total - counts.viral;
		counts.lift = viral_lift( counts );

		// Commas
		for( var name in counts ) 
			counts[ name ] = TT_Filters.add_commas( counts[ name ] );

		return counts;
	}

	/*
	 * Determine how viral lift should be displayed
	 *
	 * Hacks the number to make it seem more palatable to users
	 */
	function viral_lift( counts ) {
		// Decimals are only useful for small viral lift numbers

		//counts.lift = ( parseFloat( counts.viral / counts.seed ) + 1 ).toFixed( 1 );
		//if( counts.lift > 1.5 ) 
		//	counts.lift = Math.round( counts.lift );

		if( counts.viral >= 1 && counts.seed >= 1) {
			counts.lift = parseFloat( counts.viral / counts.seed ) + 1;
			if( counts.lift > 10 )
				return parseInt( counts.lift );
			else if( counts.lift > 1 )
				return counts.lift.toFixed(1);
			else
				return counts.lift.toFixed(2);
		}
		else
			return 1;
	}

	/*
	 * Calculate viral hourly stats
	 * viral = link + search + direct
	 *
	 * Fake increase by cumulatively adding each value
	 * to the previous
	 */
	function viral_hourly_stats( stats ) {
		var direct 	= hourly_totals( stats, "direct" );
		var link 	= hourly_totals( stats, "link" );
		var search 	= hourly_totals( stats, "search" );
		
		var viral = [];
		for( var i=0; i<hours; i++ ) {
			
			var previous = viral[ i-1 ] || 0;
			
			viral.push( 
				previous + 
				( direct[i] || 0 ) + 
				( link[i] || 0 ) + 
				( search[i] || 0 )
			);
		}
		
		return viral;
	};

	/*
	 * Calculate seed hourly stats
	 * seed = internal + network, 
	 *
	 * Fake increase by cumulatively adding each value
	 * to the previous
	 */
	function seed_hourly_stats( stats ) {
		var internal 	= hourly_totals( stats, "internal" );
		var network 	= hourly_totals( stats, "network" );

		var seed = [];
		for( var i=0; i<hours; i++ ) {

			var previous = seed[ i-1 ] || 0;

			seed.push( 
				previous + 
				( internal[i] || 0 ) +
				( network[i] || 0 )
			);
		}

		return seed;
	};
	
	/*
	 * Calculate total hourly stats
	 * total = seed + viral
	 */
	function total_hourly_stats( stats ) {
		var seed 	= seed_hourly_stats( stats );
		var viral 	= viral_hourly_stats( stats );

		var total = [];
		for( var i=0; i<hours; i++ ) {

			total.push( 
					( seed[i] || 0 ) + 
					( viral[i] || 0 ) 
			);
		}

		return total;
	};
	
	/*
	 * Loop through hourly stats and find certain type
	 * This data should be in a dictionary, but it's in an array, 
	 * so JS has to compensate for poor design
	 */
	function hourly_totals( stats, type ) {
		stats = stats.hourly_impressions;

		for( var i = 0; i<stats.length; i++ )
			if( stats[i].type_name.toLowerCase() == type.toLowerCase() )
				return stats[i].totals;

		// No stats found
		return [];
	};

	/*
	 * Hide view display blow permalink section
	 */
	function hide_local_views() {
		var views = $$( ".views-tags .views" );
		if( views.length )
			views.addClassName( "hidden" );
	};

	/*
	 * Update DOM with stat values and chart image url
	 */
	function update_values( el, counts, image_url ) {

		el.select( ".viral_views .value" )[0].update( counts.viral );
		el.select( ".seed_views .value" )[0].update( counts.seed );
		el.select( ".viral_lift .value" )[0].update( counts.lift + "X" );
		el.select( "img.chart" )[0].writeAttribute( "src", image_url );
		el.select( ".total_views .value" )[1].update( counts.total );
		el.select( ".shares .value" )[1].update( counts.shares );
	};

	/*
	 * Update template with favicons images from the top 5 linker domains
	 */
	function update_top_domains( el, domains ) {

		if( ! domains.length )
			console.error( "No buzz_stats domain linkers to update" );

		el = el.select( ".top_linkers .value" )[0];

		domains.each( function( item, idx ) {
			if( idx == 5 )
				throw $break; 
			// ^ Really, prototype?  Break Arrays, then break naming consistency to fix it?
			// An inconsistent keyword!  Maybe you should get together with the PHP folks and 
			// come up with another 10 functions to manage Arrays.  It'll be fun.

			// New <img /> using Prototype helper
			var img = new Element( "img", {
				alt: item.domain, 
				title: item.domain, 
				// Google caches site favicons
				src: "http://www.google.com/s2/favicons?domain=" + item.domain, 
				border: 0
			} );
		
			var a = new Element( "a", {
				href: "http://" + item.domain
			} );

			a.insert( img );
			el.insert( a );
		} );
	};

	/*
	 * Use Math.max with array as opposed to list
	 */
	Array.max = function( array ){
		return Math.max.apply( Math, array );
	};

	/*
	 * Returns google sparkline chart url
	 */
	function sparkline_chart_url( stats, size ) {

		var colors = [ "EE3322", "0077EE" ];
		
		var seed = seed_hourly_stats( stats );
		var total = total_hourly_stats( stats );
		
		// Default size if not specified
		var width = size.width || 300;
		var height = size.height || 100;

		// Array of zeros for data baseline
		var zeros = [];
		for( var i=0; i<total.length; i++ )
			zeros.push( 0 );
				
		var url = "http://chart.apis.google.com/chart?cht=ls" + 
			// Data
			"&chd=t:"+ total.join( "," ) + "|" +
						  seed.join( "," ) + "|" +
						  zeros.join( "," ) +
		  	// Colors
			"&chco=" + colors.join( "," ) +

			// Hi/low data points
			"&chds="	+ "0," + Array.max( total ) * 1.10 +

			// Image size
			"&chs=" 	+ width + "x" + height +

			// Background fills - bg = background, s = solid
			"&chf=" 	+ "bg,s,ffffff" +

			// Line fills - b = between two lines, 
			"&chm=" 	+ "B," + colors[0] + ",0,1,0" + "|" +
			    		  "B," + colors[1] + ",1,2,0";

		return url;
	};

	/*
	 * Returns google pie chart image url
	 */
	function pie_chart_url( viral, seed, size ) {

		var values = [ viral, seed ];
		var colors = [ "EE3322", "0077EE" ];
		
		// Higher value needs to be first for reducing fraction
		if( seed > viral ) {
			values = values.reverse();
			colors = colors.reverse();
		}

		values = reduce_fraction( values );

		// Default size if not specified
		var width = size.width || 300;
		var height = size.height || 100;

		var url = "http://chart.apis.google.com/chart?cht=p" + 
			"&chd=t:"+ values.join( "," ) +
			"&chco=" + colors.join( "," ) +
			// "&chl=" 	+ labels.join( "|" ) +
			"&chs=" 	+ width + "x" + height;

		return url;
	};

	/*
	 * Reduce max/min fraction to something digestable 
	 * for google pie chart
	 * ex: 3000/1000 returns 70/30
	 * ex: 2854/542 returns 80/20
	 */
	function reduce_fraction( values ) {
		var max = values[0];
		var min = values[1];
		
		max = 10 - ( 10 / ( 10 - Math.round( max / min ) ) );
		min = 10 - max;
		
		return [ 10*max, 10*min ];
	};

	/*
	 * Get buzz stats from amazon ec2 server, and pass callback function
	 */
	function stats( buzz_id ) {
		var callback = fn.name + ".update";
		
		// What does cb stand for?
		var identifier = Math.round(new Date().getTime() / (1000 * 60 * 15));
		var url = Cloud.report + '/cloud/hourly_panel?' +
			"&buzzid=" + buzz_id + 
			"&cb=" + identifier +
			"&wrapper=" + callback + "(%25%25)";

		// Cross-domain ajax request
		BF_XSS.swift_injection( url );
	};

};

/*
 * Init object after page is ready 
 * arg is varname to global instantiated object, 
 * so that object can be easily mocked
 */
BuzzLoader.register( function() {
		new BF_buzz_stats( "buzz_stats" )
	} , 1 );
