var CslClass = function() {
	DEBUG = false;
	this.url_vars = Utils.getUrlVars();

	// Main Methods

	this.init = function() {
		View = new ViewClass();
		View.initView();
		
		// Make sure there's a gamecode in the query string before anything else
		if (!this.url_vars["gamecode"]) {
			if (typeof console !== undefined && DEBUG) { console.warn("*** FATAL ERROR: No gamecode in URL"); }
			View.renderError("No game code in URL");
			window.location = appConfig['redirect_url'];
			return;
		}
		
		Model = new ModelClass();
		Model.Feeds = new Model.FeedsClass();
		var app_config = Model.App.config;
		var app_state = Model.App.state;

		// Check that specified teams in gamecode have associated team config entries
		if (!teamConfigs[Model.Game.config.vtm] || !teamConfigs[Model.Game.config.htm]) {
			View.renderError("One or more teams in the game code was not recognized");
			window.location = appConfig['redirect_url'];
			return;
		}

		// Use NBA brand if specified brand is invalid (i.e. doesn't have associated teamConfig entry)
		if (!teamConfigs[app_config.brand]) {
			app_config.brand = "NBA";
		}
		
		// Setup Simulation feed timestamps
		if (app_config.sim) {
			app_state.feed_timestamp = app_config.starting_feed_timestamp;
			app_config.timestamp_diff = (Utils.getCurrentTimestamp() - app_config.starting_feed_timestamp);
		}

		this.bindEventHandlers();

		$j.getScript("script/brand_config/"+ app_config.brand +".js", function() {
			View.renderBrandConfig();
		});

		Model.Teams = new Model.TeamsClass();
	    View.renderTeamConfig();
		
		// Fire off initial ajax requests for core feeds
		Model.getDataForScreen("core", true);
		Model.getDataForFeed("pregame");
    Model.getDataForFeed("broadcaster", false);
	};

	
	
	this.bindEventHandlers = function() {
		
		// ========
		// = MAIN =
		// ========
		
		// Main Nav Buttons
		this.bindMainNavButtonHandlers();
		
		// AUTO Button
		$j("#auto_tab").click(function() {
			if (Model.App.state.auto_timer_id) {
				CSL.disableMainAuto();
			}
			else {
				CSL.rotateThroughScreens();
				$j(this).addClass('auto_selected');
			}
		});
		

		// INTERACT Module // Screen
		$j("#interact_tab").find(".interact_link").click(function() {
			//if interact_screen already shown - don't change iframe src
			if ( document.getElementById('interact_screen').style.display != "block" ) {
				if (brandConfig['cil_alt_cast_code']) {
					CSL.onScreenLoad("interact");
				}
			}
			
			CSL.disableMainAuto();
		});

		// Gigya Popout
		$j("#connect").click(function() {
			if (brandConfig['gigya_iframe_src']) {
				var gigya_src = encodeURIComponent(brandConfig['gigya_iframe_src']);
				window.open("gigya.html#"+gigya_src, "_blank","toolbar=no,directories=no,scrollbars=no,resizable=no,status=no,location=no,copyhistory=no,height=380,width=370");
			}
		});
		
		// CIL Popout
		$j('#interact_screen').find('.courtside_chat_module').find('.popout').click(function(){
			 window.open("cil.html#"+brandConfig['cil_alt_cast_code'], "_blank","toolbar=no,directories=no,scrollbars=no,resizable=no,status=no,location=no,copyhistory=no,height=385,width=500");																				 
		});

		// Arena Dropdown
		$j('#arena_stats').hover(
			function(){ View.toggleArenaStatsDropdown(); }, 
			function(){ View.toggleArenaStatsDropdown(); }
		);
		
		// Game Notes Dropdown
		$j('#game_notes').hover(
			function(){ View.toggleGameNotesDropdown(); }, 
			function(){ View.toggleGameNotesDropdown(); }
		);

		
		// =========
		// = STATS =
		// =========
		
		// Stat Set Dropdowns
		//
		$j('#stats_screen').find('.pick_set_select').click(function(){
			$j(this).children('.pick_set_dropdown').slideToggle('fast');														   
		});
		$j('#vtm_stat_sets').children('li').data('team', 'vtm');
		$j('#htm_stat_sets').children('li').data('team', 'htm');
		
		var $stats_list_elements = $j('#stats_screen').find('li');
		$stats_list_elements.click(function(){
			var l_sSelectedStat = $j(this).attr("rel");
			var l_sHomeOrAway = $j(this).data('team');
			
			if (l_sHomeOrAway == 'vtm'){
				Model.App.state.vtm_statset = l_sSelectedStat;
				Model.App.state.vtm_stats_auto = false;
			}
			else {
				Model.App.state.htm_statset = l_sSelectedStat;
				Model.App.state.htm_stats_auto = false;
			}
			
			$j('#'+l_sHomeOrAway+'_auto').removeClass('auto_hover'); //auto is set to false above, so remove selected state from button
			
			$j('#'+l_sHomeOrAway+'_stats').find('.pick_set_select').children('span').html(l_sSelectedStat);
			View.showStatTable(l_sSelectedStat, l_sHomeOrAway); 
		});
		
		if ($j.browser.msie && $j.browser.version=="6.0") {
			$stats_list_elements.hover(
				function(){ $j(this).css('background-color', '#000'); },
				function(){ $j(this).css('background-color', '#333'); }
			);
		}
			
		// Stat Set Auto Buttons
		//
		$j('#stats_screen').find('.auto_button')
			.click(function(){
				$j(this).toggleClass('auto_hover');
				
				var l_sHomeOrAway = $j(this).attr('id').substr(0,3); //l_sHomeOrAway will be either 'vtm' or 'htm'
				var l_sCurrentStatTable;
				
				switch (l_sHomeOrAway) {
					case 'vtm':
						if (Model.App.state.vtm_stats_auto == true)
							Model.App.state.vtm_stats_auto = false;
						else {
							Model.App.state.vtm_stats_auto = true;
							l_sCurrentStatTable = $j(this).siblings('.pick_set_select').find('span').html();
							l_sCurrentStatTable = $j.trim(l_sCurrentStatTable.toLowerCase()); // Sanitizing since IE adds a space to the end of the parsed value
							View.cycleStatTables(l_sCurrentStatTable, l_sHomeOrAway);
						}
						break;
					
					case 'htm':
						if (Model.App.state.htm_stats_auto == true)
							Model.App.state.htm_stats_auto = false;
						else {
							Model.App.state.htm_stats_auto = true;
							l_sCurrentStatTable = $j(this).siblings('.pick_set_select').find('span').html();
							l_sCurrentStatTable = $j.trim(l_sCurrentStatTable.toLowerCase()); // Sanitizing since IE adds a space to the end of the parsed value
							View.cycleStatTables(l_sCurrentStatTable, l_sHomeOrAway);
						}
						break;
				}
			});
		
		$j("#vtm_stats").find("span.see_bench").click(function() {
			View.openBoxscoreForTeam('vtm');
			CSL.onScreenLoad("boxscore");
		});
		$j("#htm_stats").find("span.see_bench").click(function() {
			View.openBoxscoreForTeam('htm');
			CSL.onScreenLoad("boxscore");
		});
		
		
		
		// =============
		// = SHOTCHART =
		// =============

		// Timeline
		//		
		var $shotchart_quarter_tabs = $j('#shotchart_timeline_tabs').find('div.timeline_quarter_tab');
		
		for (var i = 0; i < $shotchart_quarter_tabs.length; i++) {
			$shotchart_quarter_tabs.eq(i).data('prd', i+1);
		}
		
		$shotchart_quarter_tabs.click(function(){
			var $this = $j(this);
			var period = $this.data('prd');

			if (period == Model.App.state.sc_prd_shown || period > Model.Game.data.period) 
				return; // Don't do anything if displayed period or a future qtr is clicked
			else if (period == Model.Game.data.period)
				Model.Feeds.shotchart.first_request = true;
			
			if ((!$this.hasClass('selected_tab')) && !Model.App.state.sc_timeline_opening) {
				Model.App.state.sc_timeline_opening = true;
				View.openQuarterTimeline($this);
				View.updateMarkersAgainstFilters(period);
			}
			
			Model.App.state.sc_prd_shown = period;
		});
		
		// NOTE: This event handler gets cloned to all new shot markers
		$j("#shot_marker_template").hover(
			function(){
				var $this = $j(this);
				var $tooltip = $this.children('.shot_tooltip');
				$this.addClass('more_zindex');
				$tooltip.fadeIn(100); 
				$this.children('.tooltip_headshot').fadeIn(100);
			
				//if tooltip width hasn't been calculated/set previously, do so, then mark it as 'set'
				if (!$tooltip.hasClass('width_set')){
					var middle_width = $tooltip.children('.tooltip_middle').width();
					$tooltip.width(middle_width + 75).addClass('width_set'); //75px accounts for the left and right portions of the tooltip
				}
			},
			function(){ 
				$j(this).children('.shot_tooltip').fadeOut(250, function(){ $j(this).parent().removeClass('more_zindex'); }); 
				$j(this).children('.tooltip_headshot').fadeOut(250);
			}
		);
		
		// Show Shots
		var $shot_count_filter_spans = $j('#sc_shot_count_filter').children("span");
		$shot_count_filter_spans.eq(0).data("val", 3);
		$shot_count_filter_spans.eq(1).data("val", 5);
		$shot_count_filter_spans.eq(2).data("val", 10);
		$shot_count_filter_spans.eq(3).data("val", 1000); // ALL

		$shot_count_filter_spans.click(function(){
			$j(this).addClass("shot_count_selected").siblings().removeClass("shot_count_selected");
			Model.App.state.sc_shots_to_show = $j(this).data("val");
			View.updateMarkersAgainstFilters();
		});

		// Filters
		$j('#sc_team_filter, #sc_player_filter, #sc_shot_filter').click(function(){
			$j(this).children('div.dropdown').slideToggle(100);														   
		});

		$j("#sc_team_filter_dropdown").children().click(function(){ 
			var $this = $j(this);
			var selected_filter = $this.html();
			$this.parent().parent().siblings('span').html(selected_filter);

			var selected_team = $this.data("team");
			Model.App.state.shotchart_filters.team = selected_team;
			var team_to_hide = (selected_team == "htm") ? "vtm" : "htm";

			Model.App.state.shotchart_filters.player = false;
			$j("#sc_player_filter").children('span').html('PLAYER FILTER');


			var $player_filter_ul = $j("#sc_player_filter_dropdown");

			if (!selected_team) {
				$player_filter_ul.children("li").show(); // Show all players in Player Filter dropdown
			}
			else {
				$player_filter_ul.find("li.player_filter_"+team_to_hide).hide();
				$player_filter_ul.find("li.player_filter_"+selected_team).show();
			}

			View.updateMarkersAgainstFilters();
		});

		$j("#sc_player_filter_dropdown").children().click(function(){ 
			var $this = $j(this);
			var selected_filter = $this.html();
			$this.parent().parent().siblings('span').html(selected_filter);
			Model.App.state.shotchart_filters.player = $this.data("code");
			View.updateMarkersAgainstFilters();
		});

		$j("#sc_shot_filter_dropdown").children().click(function(){ 
			var $this = $j(this);
			var selected_filter = $this.html();
			$this.parent().parent().siblings('span').html(selected_filter);
			Model.App.state.shotchart_filters.shot = $this.data("group");
			View.updateMarkersAgainstFilters();
		});

		
		
		// ================
		// = PLAY-BY-PLAY =
		// ================

		var $pbp_quarter_tabs = $j('#playbyplay_timeline_tabs').find('div.pbp_quarter_tab');
		
		for (var i = 0; i < $pbp_quarter_tabs.length; i++) {
			$pbp_quarter_tabs.eq(i).data('prd', i+1);
		}
		
		$pbp_quarter_tabs.click(function(){
			var period = $j(this).data('prd');
			var current_period = Model.Game.data.period;
			
			if (period == Model.App.state.pbp_prd_shown || period > current_period) 
				return; // Don't do anything if displayed period or future period is clicked
			
			// Reset "quarter clicked" boolean to false if clicking back to current period
			Model.App.state.pbp_prev_qtr_clicked = !(period == current_period);
				
			CSL.onPbpQuarterLoad(period);
		});

		// PBP Filter Dropdowns
		$j('#pbp_team_filter, #pbp_player_filter').click(function(){
			$j(this).children('div.dropdown').slideToggle(100);														   
		});

			
		// PBP Team Filter
		$j("#pbp_team_filter_dropdown").children().click(function(){ 
			var $this = $j(this);
			var selected_filter = $this.html();
			$this.parent().parent().siblings('span').html(selected_filter);

			var selected_team = $this.data("team");
			var team_to_hide = (selected_team == "htm") ? "vtm" : "htm";

			var $pbp_table = $j("#pbp_table_q"+Model.App.state.pbp_prd_shown);
			var $player_filter_ul = $j("#pbp_player_filter_dropdown");
			
			Model.App.state.pbp_filters.team = selected_team;
			CSL.resetPlaybyplayFilters("player")
			
			// If "All" selected
			if (!selected_team) {
				$pbp_table.find("tr").show();
				$player_filter_ul.children("li").show(); // Show all players in Player Filter dropdown
			}
			else {
				$pbp_table.find("tr.pbp_team_"+team_to_hide).hide();
				$pbp_table.find("tr.pbp_team_"+selected_team).show();
				
				// Hide other team's players from Player Filter
				$player_filter_ul.find("li.player_filter_"+team_to_hide).hide();
				$player_filter_ul.find("li.player_filter_"+selected_team).show();
			}

			$pbp_table.find("tr.no_player_plays").hide();
			View.updatePbpScrollpane();
		});

		// PBP Player Filter
		$j("#pbp_player_filter_dropdown").children().click(function(){ 
			var $this = $j(this);
			var selected_filter = $this.html();
			$this.parent().parent().siblings('span').html(selected_filter);
			var selected_player_code = $this.data("code");
			
			$pbp_table = $j("#pbp_table_q"+Model.App.state.pbp_prd_shown);
			
			Model.App.state.pbp_filters.player = selected_player_code;
			var team_filter = Model.App.state.pbp_filters.team;

			// If "All Players" selected and Team filter is set to All, show all
			if (!selected_player_code && !team_filter) {
				$pbp_table.find("tr").show();
				$pbp_table.find("tr.no_player_plays").hide();
			}
			// If "All Players" selected and Team filter is active
			else if (!selected_player_code && team_filter) {
				$pbp_table.find("tr").hide();
				$pbp_table.find("tr.pbp_team_"+team_filter).show();
			}
			// Specific player is selected
			else {
				$pbp_table.find('tr').hide();

				// Only try to show player-specific plays if they exist in the current PBP
				if ($pbp_table.find("tr.pbp_player_"+selected_player_code).length)
					$pbp_table.find("tr.pbp_player_"+selected_player_code).show();
				else
					$pbp_table.find("tr.no_player_plays").show();
			}

			$pbp_table.find('tr.pbp_load_more_row').show(); // "Load More Row" is only in the DOM if the quarter had 10 plays to show when loaded
			View.updatePbpScrollpane();
		});



		if ($j.browser.msie && $j.browser.version=="6.0") {
			$j('#sc_team_filter_dropdown, #sc_player_filter_dropdown, #sc_shot_filter_dropdown, #pbp_team_filter_dropdown, #pbp_player_filter_dropdown').children().hover(
				function(){ $j(this).css('background-color', '#000'); },
				function(){ $j(this).css('background-color', '#333'); }
			);
		}



		
		// ============
		// = BOXSCORE =
		// ============
		
		// Expand buttons
		//
		var $vtm_close_button = $j('#vtm_boxscore').find('div.expand');
		var $htm_close_button = $j('#htm_boxscore').find('div.expand');
		
		$vtm_close_button.data("team", "vtm");
		$htm_close_button.data("team", "htm");
		
		$j('#boxscore_screen').find('div.expand').click(function(){
			View.toggleBoxscoreView($j(this).data("team"));
		});
		
		
		
		// =====================
		// = League Scoreboard =
		// =====================

		$j('#scoreboard_arrow_right').click(function(){
			var lsb_display = Model.LeagueScoreboard.display;
			if (!$j(this).hasClass('arrow_inactive')){
				lsb_display.position -= 68;
				
				$j('#scoreboard_games').animate({marginLeft: lsb_display.position}, 200 );
				if (lsb_display.position < 0)
					$j('#scoreboard_arrow_left').removeClass('arrow_inactive');
				if (lsb_display.position + lsb_display.extra_width <= 0)
					$j('#scoreboard_arrow_right').addClass('arrow_inactive');
			}
		});
		
		$j('#scoreboard_arrow_left').click(function(){
			var lsb_display = Model.LeagueScoreboard.display;
			if (!$j(this).hasClass('arrow_inactive')){
				lsb_display.position += 68;
				
				$j('#scoreboard_games').animate({marginLeft: lsb_display.position}, 200 );
				if (lsb_display.position == 0)
					$j('#scoreboard_arrow_left').addClass('arrow_inactive');
				$j('#scoreboard_arrow_right').removeClass('arrow_inactive');
			}
		});
	};
	

	this.bindMainNavButtonHandlers = function() {
		$j('#tabs_navigation').children('.tab')
			.hover(
				function(){ $j(this).addClass('nav_hover'); }, 
				function(){ $j(this).removeClass('nav_hover'); } 
			)
			.click(function() {
				var new_screen = $j(this).attr("id").slice(0, -4);
				
				// Do nothing if tab is already being shown
				if (new_screen == Model.App.state.screen) return;
				
				//clicking boxscore tab should follow this logic, but not all boxscore screen loads should... i.e. clicking "See Bench"
				if (new_screen == 'boxscore') {
					if (Model.Game.config.vtm == Model.App.config.brand)
						View.openBoxscoreForTeam('vtm');
					else if (Model.Game.config.htm == Model.App.config.brand)
						View.openBoxscoreForTeam('htm');
					else
						View.openBoxscoreForTeam('both');
				}
				
				View.showLoadingScreen();
				
				$j('#tabs_navigation').children('.tab').unbind('click');
				
				// If stats tables are auto-cycling on stats screen when tab is clicked, turn off auto
				Model.App.state.vtm_stats_auto = false;
				Model.App.state.htm_stats_auto = false;
				$j('#vtm_auto, #htm_auto').removeClass('auto_hover');
				CSL.disableMainAuto();

				CSL.onScreenLoad(new_screen);
			});
	};
	
	
	// Handles loading of new screens
	this.onScreenLoad = function(new_screen) {
		var app_state = Model.App.state;	
		var current_period = Model.Game.data.period;
		var prev_screen = Model.App.state.screen;
		app_state.screen = new_screen;
				
		$j("#tabs_navigation").children().removeClass('nav_selected');
		if (Model.Screens[new_screen].has_tab) {
			$j("#"+ new_screen +"_tab").addClass('nav_selected');
		}

		// Fire off screen-specific AJAX requests
		Model.getDataForScreen();

		// Omniture call
		nbaOmRecordPageView(new_screen+"_screen");

		// Close any open dropdowns when showing a new screen
		View.retractDropdowns();

		
		if (new_screen == "stats") {
			if (Model.Game.state == "postgame"){
				// Default Stats screen to Leaders Stat Set if game is over
				$j('#stats_screen').find('.pick_set_select').children("span").html("Leaders");
				app_state.vtm_statset = 'leaders';
				app_state.htm_statset = 'leaders';
				View.showStatTable('leaders', 'vtm');
				View.showStatTable('leaders', 'htm');
			}
			
			// Avoid choppy animation when switching screens
			app_state.stat_animations_on = false;
			View.updateScreen();
			app_state.stat_animations_on = true;
		}
		else if (new_screen =="boxscore") {
			// Avoid choppy animation when switching screens
			app_state.stat_animations_on = false;
			View.updateScreen();
			app_state.stat_animations_on = true;
		}
		else if (new_screen == "shotchart") {
			Model.Feeds.shotchart.first_request = true;
			$j('#court_overlay').find("div.shot_tooltip").hide();
			Model.Shots.tooltip_queue = [];
			
			// Getting shotchart feeds for previous quarters to populate their respective data objects
			for (var i = 1; i < current_period; i++) {
				if (Model.Shots.events["prd"+i].length < 1) {
					Model.getDataForFeed("shotchart", false, i);
					$j('#shotchart_timeline_tabs').find('div.timeline_quarter_tab').eq(i-1).addClass("clickable_tab");
				}
			};
			
			View.populateShotchartScreen(current_period);
			this.triggerShotchartQuarterClick(current_period);
		}
		else if (new_screen == "playbyplay"){
			app_state.pbp_prd_shown = current_period;
			Model.Feeds.playbyplay.first_request = true;

			// Getting PBP feeds for previous quarters to populate their respective data objects
			for (var i = 1; i < current_period; i++) {
				if (Model.Plays.events["prd"+i].length < 1) {
					Model.getDataForFeed("playbyplay", false, i);
					$j('#playbyplay_timeline_tabs').find('div.pbp_quarter_tab').eq(i-1).addClass("clickable_tab");
				}
			};

			var $current_quarter_tab = $j("#pbp_q"+current_period).children("div.pbp_quarter_tab"); 
			if (!$current_quarter_tab.hasClass('selected_tab')) {
				$j('#playbyplay_timeline_tabs').find('div.pbp_quarter_tab').removeClass('selected_tab');
				$current_quarter_tab.addClass("selected_tab");
			}
			
			CSL.resetPlaybyplayFilters();
			View.populatePlaybyplayScreen(); // Will default to current period if none passed in
		}
		else if (new_screen == "halftime") {
			View.populateHalftimeScreen();	
		}
		else if (new_screen == "postgame") {
			View.populatePostgameScreen();
			$j('#coverage_table').find('tr').css("visibility", "hidden");
		}

		if (new_screen == "interact") {
			if (brandConfig['cil_alt_cast_code'] && !$j("#coveritlive_iframe").attr("src")) {
				$j("#coveritlive_iframe").attr("src", "http://www.coveritlive.com/index2.php/option=com_altcaster/task=viewaltcast/altcast_code="+ brandConfig['cil_alt_cast_code'] +"/height=385/width=900");
			}
		}
		else {
			// Kill CoverItLive iframe when navigating away from Interact screen 
			$j("#coveritlive_iframe").attr("src", "");
		}

		View.showCurrentScreen(prev_screen);
		setTimeout('CSL.bindMainNavButtonHandlers()', 300); // Main Nav Tabs are deactivated for 300 milliseconds to mitigate unexpected behavior from frenetic clicking
	};
	
	
	this.triggerShotchartQuarterClick = function(period) {
		period = period || Model.Game.data.period;
		
		// Opens correct timeline tab when user navigates to shotchart
		if ($j('#shotchart_screen').is(':visible')){
			var $quarter_tab = $j('#timeline_q'+ period).children('div.timeline_quarter_tab');
			if (!$quarter_tab.hasClass('selected_tab')) {
				$quarter_tab.trigger('click');
			}
		}
		else
			setTimeout('CSL.triggerShotchartQuarterClick('+period+')', 100); // Try again
	};
	
	
	this.initShotchartSliders = function() {
		var slider_val;

		// Initialize slider
		for (var i = 1; i <= 8; i++) {
			$slider_bar = $j("#timeline_q"+i).find("div.slider_bar");
			slider_val = (i < Model.Game.data.period) ? 100 : 0; // Show slider at end of timeline for previous periods
			
			// Show slider at end of timeline for "latest" period if game is at halftime or is over
			if ((i == 2 && Model.Game.state == "halftime") || (i == Model.Game.data.period && Model.Game.state == "postgame"))
				slider_val = 100;
			
			$slider_bar.slider({
				animate: true,
				value: slider_val
	 		});

			$slider_bar.slider('disable'); // Disables dragging

			$slider_bar.children('.ui-slider-handle').html('<img src="image/scrubber_handle.gif" /><div class="scrubber_bubble"></div>').hover( 
			 	function(){
					var $this = $j(this);
					var total_deciseconds = 7200; // Assume it's a regulation period with 12 minutes
					// Looks at #timeline_q<#> to check if it's an overtime tab and display the time based on 5:00 periods
					if ($this.parent().parent().parent().attr("id").slice(-1) > 4) total_deciseconds = 3000;
					var deciseconds_per_percent = total_deciseconds / 100;
					var pct = 100 - $this.parent().slider('value');
					var deciseconds =  pct * deciseconds_per_percent; 
					var display_time = Utils.getDisplayTimeForDeciseconds(deciseconds);
					$this.children(".scrubber_bubble").html(display_time).show();
				}, 
				function(){ 
					$j(this).children(".scrubber_bubble").hide();	
				}
			);
		}
	};
	

	this.onLoadMorePlaysClick = function(period) {
		View.showLoadingScreen();
		View.populateMorePlays(period);
	};


	this.onPbpQuarterLoad = function(period) {
		$j('#playbyplay_timeline_tabs').find('div.pbp_quarter_tab').removeClass('selected_tab');
		$j("#pbp_q"+period).children("div.pbp_quarter_tab").addClass('selected_tab');
	
		CSL.resetPlaybyplayFilters();
		View.showPlaysForQuarter(period);
	};


	this.resetPlaybyplayFilters = function(type) {
		type = type || "both";

		if (type == "both" || type == "team") {
			Model.App.state.pbp_filters.team = false;
			$j('#pbp_team_filter').children('span').html('TEAM FILTER');
		}

		if (type == "both" || type == "player") {
			Model.App.state.pbp_filters.player = false;
			$j("#pbp_player_filter").children('span').html('PLAYER FILTER');
		}

		// Show all players in any case
		$j("#pbp_player_filter").children("li").show();
	};


	// Sets internal game state variable which determines which screen to show
	this.setGameState = function() {
		var game = Model.Game;
		var game_status = game.data.status;
		
		// Game hasn't started
		if (game_status == "1") {
			game.state = "pregame";
		}
		// Game is live
		else if (game_status == "2") {
			if (game.data.status_text.indexOf("Halftime") !== -1) {
				game.state = "halftime";
			}
			else {
				game.state = "live";
			}
		}
		// Game is over
		else if  (game_status == "3" || game_status == "4" || game_status == "5") {
			game.state = "postgame";
		}
	};


	// Determines if screen change is necessary based on game state
	this.checkForScreenChange = function(prev_state) {
		var new_screen;
		var current_screen = Model.App.state.screen;
		var game_state = Model.Game.state;

		try {
			if (brandConfig["screen"]) {
				Model.App.config.start_screen = CSL.url_vars["screen"] || brandConfig["screen"] || "stats";
			}
		} catch (err) {}

		if (prev_state != game_state) {
			if (game_state == "live") {
				if (current_screen == "init" || current_screen == "pregame" || current_screen == "halftime") {
					$j("#tabs_navigation").children().show();
					$j("#pregame_start_time").html("LIVE");
					new_screen = Model.App.config.start_screen;
					$j("#"+ new_screen + "_tab").addClass('nav_selected');
				}
				else if (current_screen == "interact") {
					$j("#tabs_navigation").children().fadeIn("slow");
					$j("#pregame_start_time").html("LIVE");
					new_screen = current_screen; // Don't automatically switch screen if user is on the Interact screen
				}
				else {
					new_screen = current_screen;  // Keep user on Stats/Shotchart/PBP/Boxscore screen if game goes live (Should only apply when going from Halftime -> 3rd Qtr)
				}
			}
			else if (game_state == "pregame") {
				new_screen = game_state;
			}
			else { // Halftime, Postgame states
				$j("#tabs_navigation").children().show();
				new_screen = game_state;
			}

			if (new_screen != current_screen) {
				CSL.onScreenLoad(new_screen);
				if (current_screen == "init") $j("#init_screen").remove();
			}
		}
	};


	// Main AUTO Button
	//
	this.rotateThroughScreens = function() {
		// Store the timer id so we can turn it off later
		Model.App.state.auto_timer_id = setInterval(this.showNextScreen, Model.App.config.main_auto_rotate_freq);
	};

	this.showNextScreen = function() {
		var next_tab_id;
		var $nav_tab_selected = $j("#tabs_navigation").children(".nav_selected");
		
		if ($nav_tab_selected.next(".tab").length) {
			next_tab_id = $nav_tab_selected.next().attr("id");
			CSL.onScreenLoad(next_tab_id.slice(0, -4));
		}
		else {
			CSL.onScreenLoad("stats");
		}
	};
	
	this.disableMainAuto = function() {
		clearInterval(Model.App.state.auto_timer_id);
		Model.App.state.auto_timer_id = 0;
		$j('#auto_tab').removeClass('auto_selected');
	};




	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// ==========================
	// = Feed Request Callbacks =
	// ==========================

	this.initSimplescoreboardCallback = function(xml) {
		var feed_has_data = false;

		if (xml && !$j(xml).children("error").length) {
			feed_has_data = true;
			Model.processSimpleScoreboardFeed(xml, true);
			var game_data = Model.Game.data;
			
			// NOTE: Game period is only set if Boxscore feed has already been processed
			if (!game_data.period || game_data.period < 3) {
				View.populatePregameScreen("simplescoreboard");
			}
			else {
				$j("#pregame_screen").remove();
			}

			View.populateBroadcasters();
			View.populateGameNotes();

			// Let the SimpleScoreboard feed set the screen just this once
			if (game_data.status == "1" && Model.App.state.screen != "pregame") {
				CSL.onScreenLoad("pregame");
				$j("#init_screen").remove();
			}
			
			View.createLeagueScoreboardGames();
			View.setLeagueScoreboardWidths();
			View.updateLeagueScoreboard();
		}
		
		// Running initSimpleScoreboardCallback again if feed didn't return data this time 
		setTimeout(function() { Model.getDataForFeed("simplescoreboard", !feed_has_data); }, Model.Feeds.simplescoreboard.freq );
	};


	this.initBoxscoreCallback = function(xml) {
		var feed_has_data = false;
		
		if (xml && !$j(xml).children("error").length) {
			feed_has_data = true;
			var max_num_players;
			var prev_state = Model.Game.state;
			
			Model.processBoxscoreFeed(xml, true);
			var latest_period = Model.Game.data.period;
			CSL.setGameState();
			CSL.checkForScreenChange(prev_state);

			View.updateJumbotron();

			// Populating Static data across app

			// PREGAME
			if (latest_period < 3) {
				View.populatePregameScreen("boxscore");
			}
			
			// MAIN
			View.populateArenaStatsDropdown();
			View.populateBroadcasters();
			
			// BOXSCORE
			max_num_players = Math.max(Model.Players.vtm_count, Model.Players.htm_count);
			View.createBoxscoreRows(max_num_players);
			View.populateStaticBoxscoreData();
			
			// SHOTCHART & PLAYBYPLAY
			//
			// Include latest period when requesting feeds if game is at halftime or over
			var latest_period = (Model.Game.state == "halftime" || Model.Game.state == "postgame") ? latest_period + 1 : latest_period;

			// Getting shotchart & playbyplay feeds for previous quarters to populate their respective data objects
			for (var i = 1; i < latest_period; i++) {
				Model.getDataForFeed("shotchart", false, i);
				$j('#shotchart_timeline_tabs').find('div.timeline_quarter_tab').eq(i-1).addClass("clickable_tab");
				
				Model.getDataForFeed("playbyplay", false, i);
				$j('#playbyplay_timeline_tabs').find('div.pbp_quarter_tab').eq(i-1).addClass("clickable_tab");
			};

			// Add clickable tab class to current quarter
			$j('#shotchart_timeline_tabs').find('div.timeline_quarter_tab').eq(latest_period-1).addClass("clickable_tab");
			$j('#playbyplay_timeline_tabs').find('div.pbp_quarter_tab').eq(latest_period-1).addClass("clickable_tab");

			if (latest_period > 4) {
				View.showOvertimeTabs("shotchart");
				View.showOvertimeTabs("playbyplay");
			}

			CSL.initShotchartSliders();
			View.populateTeamFilter("sc_team_filter_dropdown");
			View.populatePlayerFilter("sc_player_filter_dropdown");
			View.populateShotFilter();

			View.populateTeamFilter("pbp_team_filter_dropdown");
			View.populatePlayerFilter("pbp_player_filter_dropdown");

			Model.App.state.stat_animations_on = false; // Avoid choppy animation when all stats are first populated
			View.updateScreen();
			Model.App.state.stat_animations_on = true;
		}

		if (Model.App.state.postgame_retries < 10) {
			// Running initBoxscoreCallback again if feed didn't return data this time 
			setTimeout(function() { Model.getDataForFeed("boxscore", !feed_has_data); }, Model.Feeds.boxscore.freq );
		}

	};


  this.broadcasterCallback = function(xml) {
    Model.processBroadcaster(xml);
  }


	this.boxscoreCallback = function(xml) {
		var current_period = Model.Game.data.period;
		
		if (xml && !$j(xml).children("error").length) {
			var prev_state = Model.Game.state;
			Model.processBoxscoreFeed(xml);
			CSL.setGameState();

			CSL.checkForScreenChange(prev_state);
			
			View.updateJumbotron();
			View.updateScreen();
		}

		if (current_period > 4) {
			View.showOvertimeTabs("playbyplay");
			View.showOvertimeTabs("shotchart");
		}

		// Add clickable tab class to current quarter
		// TODO: Consider doing this only when the period changes
		$j('#shotchart_timeline_tabs').find('div.timeline_quarter_tab').eq(current_period-1).addClass("clickable_tab");
		$j('#playbyplay_timeline_tabs').find('div.pbp_quarter_tab').eq(current_period-1).addClass("clickable_tab");

		if (Model.Game.state == "postgame") Model.App.state.postgame_retries++;
		
		if (Model.App.state.postgame_retries < 10) { // Allows for 10 more boxscore requests in case of game state overrides at the end of the game
			setTimeout(function() { Model.getDataForFeed("boxscore"); }, Model.Feeds.boxscore.freq );
		}
	};


	this.playbyplayCallback = function(xml) { 
		var app_state = Model.App.state;

		if (xml && !$j(xml).children("error").length) {
			var current_period = Model.Game.data.period;
			
			if (app_state.screen == "playbyplay")
				Model.processPlaybyplayFeed(xml);

			if (Model.Feeds.playbyplay.first_request) {
				app_state.pbp_prd_shown = current_period;
				View.populatePlaybyplayScreen();
				Model.Plays.queue = []; // Reset queue after initial plays are shown
			}
			else {
				if (app_state.screen == "playbyplay" && app_state.pbp_prd_shown == current_period) { 
					View.updatePlaybyplayScreen();
				}
				// Auto-load the next quarter once it starts if the previous quarter is shown (and wasn't clicked back to from the new quarter)
				else if (app_state.pbp_prd_shown == (current_period-1) && !app_state.pbp_prev_qtr_clicked) {
					$j("#pbp_q"+current_period).addClass("clickable_tab");
					CSL.onPbpQuarterLoad(current_period);
					
					app_state.pbp_prev_qtr_clicked = false;
				}
			}
		}

		if (app_state.screen == "playbyplay" && Model.Game.state != "postgame") {
			setTimeout(function() { Model.Feeds.playbyplay.first_request = false; Model.getDataForFeed("playbyplay"); }, Model.Feeds.playbyplay.freq);
		}
	};
	
	
	this.shotchartCallback = function(xml) {
		if (xml && !$j(xml).children("error").length) {
			if (Model.App.state.screen == "shotchart")
				Model.processShotchartFeed(xml);

			if (Model.Feeds.shotchart.first_request) {
				Model.Shots.tooltip_queue = [];
				View.populateShotchartScreen();
			}
			else {
				View.updateShotchartScreen();
			}
		}
		
		if (Model.App.state.screen == "shotchart" && Model.Game.state != "postgame") {
			setTimeout(function() { Model.Feeds.shotchart.first_request = false; Model.getDataForFeed("shotchart"); }, Model.Feeds.shotchart.freq);
		}
	};
	
	
	// For previous quarters
	this.prevShotchartCallback = function(xml, period) {
		if (xml && !$j(xml).children("error").length) {
			Model.processShotchartFeed(xml, period);
			View.showPrevTimelineMarkers(period);
		}
	};
	
	
	// For previous quarters
	this.prevPlaybyplayCallback = function(xml, period) {
		if (xml && !$j(xml).children("error").length) {
			Model.processPlaybyplayFeed(xml, period);
		}
	};
	
	
	this.simplescoreboardCallback = function(xml) {
		if (xml && !$j(xml).children("error").length) {
			Model.processSimpleScoreboardFeed(xml);
			View.updateLeagueScoreboard();
		}

		setTimeout(function() { Model.getDataForFeed("simplescoreboard"); }, Model.Feeds.simplescoreboard.freq);
	};


	this.nbatickerCallback = function(xml) {
		if (xml && !$j(xml).children("error").length) {
			Model.processNbaTickerFeed(xml);
			View.updateNbaTicker();
		}
		
		if (Model.Game.state != "postgame") {
			setTimeout(function() { Model.getDataForFeed("nbaticker"); }, Model.Feeds.nbaticker.freq);
		}
	};


	this.pregameCallback = function(xml) {
		if (xml && !$j(xml).children("error").length) {
			Model.processPregameFeed(xml);

			// Still populates Arena & Officials for Pregame screen if game period isn't set yet (usually due to a race condition)
			if (!(Model.Game.data.period > 2)) {
				View.populatePregameScreen("pregame");
			}

			View.populateArenaStatsDropdown();
		}
	};




	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// ==================
	// = Helper Methods =
	// ==================

	this.getUrlForFeed = function(feed_name, period) {
		if (!feed_name) { return false; } // TODO: Reconsider whether this should throw an error instead
		var prd = (period) ? period : Model.Game.data.period;
		prd = (prd) ? prd : "all";
		
		var base_path = "";
		var feed_prefix = "";
		var feed_url = "";

		if (Model.App.config.sim) {
			// Using custom relative path so that mod_rewrite rules can target specific dataset
			base_path = "/simdata/"+ Model.Game.config.game_code;

			var feed_timestamp = Utils.getCurrentTimestamp() - Model.App.config.timestamp_diff;
			// Flooring timestamp to a multiple of 5 since simulation data files are prefixed with timestamps in intervals of 5
			feed_timestamp = feed_timestamp - (feed_timestamp % 5);
			feed_prefix = feed_timestamp + "_";
		}
		else if (Model.App.config.live) {
			base_path = "/livedata";
		}
	
		
		switch (feed_name.toString()) {
		case "broadcaster":
				feed_url = base_path +"/games/game_component/dynamic/"+ Model.Game.config.game_code +"/"+ feed_prefix +"broadcasters.xml"; break;
			case "boxscore":
				feed_url = base_path +"/games/game_component/dynamic/"+ Model.Game.config.game_code +"/"+ feed_prefix +"boxscore.xml"; break;
			case "playbyplay":
				feed_url = base_path +"/games/game_component/dynamic/"+ Model.Game.config.game_code +"/"+ feed_prefix +"pbp_"+ prd +".xml"; break;
			case "shotchart":
				feed_url = base_path +"/games/game_component/dynamic/"+ Model.Game.config.game_code +"/"+ feed_prefix +"shotchart_"+ prd +".xml"; break;
			case "simplescoreboard":
				feed_url = base_path +"/games/game_component/dynamic/"+ feed_prefix +"simple_scoreboard.xml"; break;
			case "nbaticker":
				feed_url = base_path +"/HPSGroup/"+ feed_prefix +"rss.xml"; break;
			case "pregame":
				feed_url = base_path +"/tvc/pregame.xml"; break;
		}
		
		return feed_url;
	};
	
};