﻿
var wsElectionResults = function() {

	var flashVersionRequired = "9.0.15";
	var boxWidth = 610;
	var boxHeight = 535;
	var mapHeight = 280;
	var verticalGap = 20;
	
	var hFix = 15;

	var listWidth = 140 + hFix;
	var listHeight = 140;

	var flashPresent;
	var flashReady = false;
	
	var translations;
	var replacementStrings = {
			noResult: "",
			demWin: "",
			repWin: "",
			projDemWin: "",
			projRepWin: "",
			disp: "" 
		};
		
	
	function init() {
		
		if ( !jQuery.boxModel ) {
			listWidth += 25;
		}
		
		parseTranslations();
		addFlash();
		reformat();
	}

	/** Pull dynamic translation data out of the HTML page and bring it into the translations variable. */
	function parseTranslations() {
		
		translations = new Object();
		
		var transDiv = $( "#translationData" );
		var arr, key, val;
		
		transDiv.children().each( function( i ) {
			arr = $( this ).text().split( ":" );
			key = arr[0];
			val = arr.slice( 1 ).join( ":" );
			translations[ key ] = val;
		} );
		
	}

	function addFlash() {

		var flashvars = {
			//imagePath: battlegroundsConfig.imagePath,
			//useImages: battlegroundsConfig.useImages,
			stateNames: getStateNamesListForFlash(),
			xmlPath: resultsConfig.feedUrl,
			updateSecsText: translations[ "updateSecs" ],
			helpText: translations[ "help" ],
			electoralCollegeText: translations[ "electoralCollege" ],
			useImages: resultsConfig.useImages,
			imagePath: resultsConfig.imagePath,
			bigText: resultsConfig.bigText,
			electoralCollegeImagePath: resultsConfig.electoralCollegeImagePath,
			helpTextImagePath: resultsConfig.helpTextImagePath,
			rtl: resultsConfig.rtl
		};
		
		var params = {
			allowScriptAccess: "always"
		};
		
		var attributes = {
			id: "ws_results_map",
			name: "ws_results_map"
		};
		
		if ( swfobject.hasFlashPlayerVersion( flashVersionRequired ) ) {
		
			swfobject.embedSWF( resultsConfig.flashPath, "map", boxWidth, mapHeight, 
							flashVersionRequired, null, flashvars, params, attributes );
			flashPresent = true;
		} else {
			flashPresent = false;
		}
	}

	// Use the list of links on the page to create a JSON-ish string to send to flash.
	function getStateNamesListForFlash() {
		
		var hash = {};
		
		var links = $( "#stateLinks > div > a" );
		links.each( function( i ) {
			var jq = $( this );
			var stateName = jq.html();
			var stateId = jq.attr( "href" ).split("_")[1];
			hash["id_"+stateId] = stateName;
		} );
		
		var arr = new Array();
		for ( var key in hash ) {
			arr.push( key + ":" + hash[key] + "" );
		}
		
		return ( "{" + arr.join(",") + "}" );
	}

	/** Rearrange page depending on presence of absence of Flash app. Ugly, needs some refactoring. */
	function reformat() {

		var nationalResults = $( "#nationalResults" );
		var stateResultList = $( "#stateResultList" );
		var mapOptions = $( "#mapOptions" );
		
		// if flash is present: 
		if ( flashPresent ) {
//			listHeight -= 30;
			
			// display map
			var mapUI = $( "#mapUI" );
			mapUI.css( "display", "block" );
			mapUI.height( mapHeight );
			mapUI.width( boxWidth );
			
			// move national results into the results list
			stateResultList.prepend( nationalResults.remove() );
			
			// display geog/prop map switch
//			mapOptions.css( "display", "block" );
			
//			// set up map type switcher
//			var radioGroup = $( "input[@name='mapTypes']" );
//			radioGroup.eq(0).attr( "checked", "checked" );	// check first option
//			radioGroup.change( mapOptionChanged );
			
			$( ".nationalResultUnit" ).css( "clear", "none" );
			$( "#mapKey" ).css( "display", "block" );
		} else {
			
		}
		
		// hide all the result boxes so we can show the correct one as needed
		var resultBox = $( ".resultBox" );
		resultBox.css( "display", "none" );
		resultBox.css( "clear", "none" );
		resultBox.css( "margin-top", "0px" );
		
		if ( jQuery.boxModel ) {
			resultBox.width( 442 - hFix );
		} else {
			resultBox.width( 440 - hFix );
		}

		if ( !flashPresent ) {
			// except the national ones, which get to be visible all the time
			nationalResults.css( "display", "block" );
			
			// in non-flash version, make national results wider to balance visuals
			nationalResults.width( 610 );
			$( ".nationalGraph" ).width( 500 );
		}
		
		// set sizes of boxes so they contain scrollable info
		stateResultList.width( 442 - hFix );

		
		// put the links in a scrolling list on the right, and turn them into blocks so there's
		// one on each line.
		var linkList = $( "#stateLinks" );
		linkList.attr( "class", "outerBorder" );
		//linkList.css( "float", "right" );
		linkList.width( listWidth );
		linkList.css( "height", listHeight );
		linkList.css( "margin-bottom", "5px" );
	
		var rightColumn = $( "#rightColumn" );
		rightColumn.css( "float" , "right" );
		
		var linkListCaption = $( "#stateLinks > p" );
		linkListCaption.css( "margin", "0px" );
		linkListCaption.css( "padding", "0px" );
		linkListCaption.css( "margin-bottom", "4px" );
		
		var linkListInner = $( "#stateLinks > div" );
		linkListInner.css( "height", listHeight - 20 );
		linkListInner.css( "overflow-x", "hidden" );
		linkListInner.css( "overflow-y", "auto" );


		var links = $( "#stateLinks > div > a" );
		links.click( selectStateFromNavLink );
		links.css( "display", "block" );
		links.css( "margin-right", "4px" );
		links.width( 115 );
		
		if ( !flashPresent ) {
			// hide national link if we're on the non-flash version 
			// (the national data is at the top of the page anyway)
			$( "#stateLinks > div > #nationalLink" ).css( "display", "none" );
		}
		
		// loop through each link and assign it a state id based on its href target
		links.each( function( i ) {
			var jq = $( this );
			var stateId = jq.attr( "href" ).split("_")[1];
			jq.attr( "href", "" );
			jq.data( "id", stateId );
		} );
		
		// get references to paragraphs containing links to top of the page, and remove them.
		var topLinks = $( 'a[href="#"]' );
		topLinks.remove();
		
		// if flash is present, select the national results, otherwise select the first state
		selectState( flashPresent ? 0 : 1 );
	}

	/** Map type changed - proportionate or geographical. */
	function mapOptionChanged() {

		// this should be "geog" or "prop"
		var newType =  $( "input[@name='mapTypes']:checked" ).val();
		
		if ( !flashPresent || !flashReady ) { return; };
		var app = $( "#ws_results_map" )[ 0 ];
		app.switchMapType( newType );
	}
	
	/** Call selectState on Flash app, if present and ready. */
	function mapSelect( id ) {

		if ( !flashPresent || !flashReady ) { return; };
		var app = $( "#ws_results_map" )[ 0 ];
		app.selectState( id );
	}

	/** Switch the currently selected state to the specified one. If id is 0, we show national results. */
	function selectState( id, preventScroll ) {
		
		$( "#stateResultList > .resultBox" ).css( "display", "none" );
		$( "#stateResult_" + id ).css( "display", "block" );
		
		currentStateId = id;
		
		var links = $( "#stateLinks > div > a" );
		var selectedLink;
		links.each( function( i ) {
			var jq = $( this );
			if ( jq.data( "id" ) == currentStateId ) {
				jq.attr( "class", "selectedLink" );
				if ( !preventScroll ) {
					$( "#stateLinks>div" ).scrollTo( jq, 800 );
				}
			} else {
				jq.attr( "class", "" );
			}
		} );
		
		if ( id == 0 ) {
			$( "#nationalResults" ).css( "display", "block" );
		}
		
		updateStateFromFlash( id );
	}

	/** Called from Flash when it's ready to recieve externalinterface calls. */
	function flashIsReady() {
		flashReady = true;
	}

	/** Called from Flash when it's recieved new XML data. */
	function flashDataUpdated() {
		updateStateFromFlash( currentStateId );
	}

	/** Cross-browser parsing. Just putting the string in a JQuery object won't work in IE6. */
	function parseXML( xmlStr ) {
		if( window.ActiveXObject && window.GetObject ) {
			var dom = new ActiveXObject( "Microsoft.XMLDOM" );
			dom.loadXML( xmlStr );
			return dom;
		}
		if ( window.DOMParser ) {
			return new DOMParser().parseFromString( xmlStr, "text/xml" );
		}
		throw new Error( 'No XML parser available' );
	} 	
	
	/** Pull latest data for the currently selected state out of flash and update the screen with it. */
	function updateStateFromFlash( id ) {
		
		if ( !flashReady ) { return false; };
		
		var app = $( "#ws_results_map" )[ 0 ];
		var xmlStr = app.getResultForState( id );
		var jData = $( parseXML( xmlStr ) );
		var isNational = ( id == 0 );
		
		var stateNode = jData.find( "state" );
		// "Dem" or "Rep" or "" in this 2 party system!
		var resultValue = stateNode.attr( "res" );
		// This may or may not have the string "projected" in it
		var headlineValue = stateNode.attr( "headline" );
		updateStateResult( id, resultValue, headlineValue.indexOf( "projected" ) > -1 );
		
		var x, candidate, votes, ec, pct, cells, candidateDiv;
		
		jData.find( "candidate" ).each( function( i ) {
			x = $( this );
			candidate = x.attr( "n" );
			votes = x.attr( "votes" );
			ec = x.attr( "ec" );
			pct = x.attr( "pct" );
			//console.log( i + ": " + candidate + ", " + ec + ", " + votes + ", " + pct );
			
			if ( isNational ) { 		// update national result graph
			
				candidateDiv = $( ".nationalResultUnit > ." + candidate );
				candidateDiv.find( "p > .numVotes" ).text( ec );
				candidateDiv.find( ".graph > .bar" ).css( "width", ec/270*200 + "px" );
				
			} else {					// update state result table
				
				cells = $( "#stateResult_" + id + " > table > tbody > ." + candidate + " > td" );
				cells.eq( 2 ).text( pct );
				cells.eq( 3 ).text( ec );
				cells.eq( 1 ).find( ".graph > .bar" ).css( "width", pct + "%" );
			}
		} );

		if ( !isNational ) {
			sortStateResultTable( id );
		}
	}
	
	/**
	*	@param stateId 		Don't pass 0 here.
	*	@param resultValue	String, either "Dem" or "Rep" or blank.
	*	@param isProjected	Boolean, whether the win is projected or concrete
	*/
	function updateStateResult( stateId, resultValue, isProjected ) {

		//console.log( "updateStateResult(" + stateId + ", " + resultValue + ", " + isProjected + ")");
		
		var resultHeader = $( "#stateResult_" + stateId + " > .stateResultHeader" );
		var span = resultHeader.find( ".stateResultStatus" );
		//console.log( "span class = " + span.attr( "class" ) );
		
		var spanClass = "stateResultStatus";
		var newStatus = translations.noResult;

		switch ( resultValue ) {
			case "GOP":
				spanClass += " textRep";	
				newStatus = isProjected ? translations.projRepWin : translations.repWin;
				break;
			case "Dem":
				spanClass += " textDem";
				newStatus = isProjected ? translations.projDemWin : translations.demWin;
				break;
			default:
		}
		
		span.attr( "class", spanClass );
		//console.log("newStatus = " + newStatus);
		span.text( newStatus );
	}

	/** Sort the graphs in a state result table by values currently in the vote percentage column. */
	function sortStateResultTable( stateId ) {

		var table = $( "#stateResult_" + stateId ); 
		var tbody = table.find( "tbody" );
		var rows = table.find( "tbody > tr" ).get();
		var keyA, keyB;
		
		rows.sort( function( a, b ) {
			keyA = parseFloat( $( a ).children( 'td' ).eq( 2 ).text() );
			keyB = parseFloat( $( b ).children( 'td' ).eq( 2 ).text() );
			if ( keyA < keyB ) { return 1 };
			if ( keyA > keyB ) { return -1 };
			return 0;
		} );

		$.each( rows, function( index, row ) {
			tbody.append( row );
		} );
	}
	
	/*
	<state id="99999" res=" " PrecinctsDeclared="2665" TotalPrecincts="2665" ec="9" headline=" projected to win" disclaimer=" " 
			name="National" dec="100"> 
		<candidate n="Obama " party="Dem" votes="602590" ec="9" pct="52"/> 
		<candidate n="McCain " party="GOP" votes="555799" ec="0" pct="48"/> 
	</state>	
	
	<state id="1" res="GOP" PrecinctsDeclared="100" TotalPrecincts="100" ec="9" headline="McCain projected to win" disclaimer=" " 
			name="Alabama" dec="100">
		<candidate n="McCain " party="GOP" votes="50" ec="9" pct="50"/>
		<candidate n="Obama " party="Dem" votes="50" ec="0" pct="50"/>
	</state> 
	*/

	/** Handles clicks in the right hand state list nav. */
	function selectStateFromNavLink() {

		var jq = $( this );
		var stateName = jq.html();
		var stateId = jq.data( "id" );
		
		mapSelect( stateId );
		selectState( stateId, true );
		
		return false;
	}
	
	// put public members in this object
	return {
		init: init,
		flashIsReady: flashIsReady,
		selectState: selectState,
		flashDataUpdated: flashDataUpdated
	};
}()

// JQuery initialisation
$( document ).ready( wsElectionResults.init );


