/**
 * Framework contains the basic functionality needed for EA.com
 * It should be used for helper methods and for instantiation of global objects
 * across the site, such as Flash embedding, main navigation, etc.
 * 
 * @author Kevin Sweeney (Fi), Karl Stanton (Fi)
 * @version 1.0
 */

// Constructor _________________________________________________________________

function Framework() {
	
	this.min_flash_version		= '9.0.115';
	this.expressInstall_swf		= '/portal/media/swf/expressInstall.swf';
	this.videoSWFs				= [];
	
	//init the framework
	this.init();
}

// General _____________________________________________________________________

/**
 * The init function is called in the constructor.
 */
Framework.prototype.init = function () {
	
	// IE6 background image cache fix
	try {
		document.execCommand("BackgroundImageCache", false, true);
	} 
	catch (err) {
		// fail silently
	}
	
	// Search Spotlights
	$("#spotlight").attr("autocomplete", "off").spotlight({
		minlength: 3,
		timeout: 4000,
		searchpath: search_path,
		resultspath: results_path
	});
	
	$("#spotlight-footer").attr("autocomplete", "off").spotlight({
		minlength: 3,
		timeout: 4000,
		searchpath: search_path,
		resultspath: results_path,
		style: 'footer'
	});
		
	// Load any components reliant on third-party data sources
	//this.loadExternalModules();
	
	// Preload rollovers for cart & more info buttons
	this.preloadRollovers();
	
	//$(window).ready(function(){
	// Lightbox appropriate links
	$('a[rel*=facebox]').facebox({
		loadingImage: '/portal/css/assets/facebox/loading.gif',
		closeImage: '/portal/css/assets/facebox/closelabel.gif'
	});
	
	// Hook up external links to open in smaller browser window
	$('a[target*=blank]').click(function () {
		EA.framework.openInNewWindow($(this).attr('href'), $(this).attr('title'));
		return false;
	});
	/*
	$(document).bind('beforeReveal.facebox', function () {
		$('.hideFlash').children().hide();
	});
	
	$(document).bind('close.facebox', function () {
		$('.hideFlash').children().show();
	});
	*/
	// Breaking News
	$('#breakingNews a.close').click(function () {
		$('#breakingNews').slideUp(100, function () {
			$('#breakingNews').hide();
			this.setCookie('breakingNews', 'hide', 1);
		});
	});
	
	// Fake hover for menu elements in IE
	if ($.browser.msie) {
		Framework.prototype.fakeHover('#menu li', 'drop');
	}
	
	$("#header_search .submitsd").mouseover(function () {
		$(this).removeClass("submitsd").addClass("submitsd_on");
	}).mouseout(function () {
		$(this).removeClass("submitsd_on").addClass("submitsd");
	});
	$("#footer_search .submitsd").mouseover(function () {
		$(this).removeClass("submitsd").addClass("submitsd_on");
	}).mouseout(function () {
		$(this).removeClass("submitsd_on").addClass("submitsd");
	});
	$("#spotlight, #spotlight-footer").val('Search EA.com'.localize()).labelinput();

	$(document).unload(function () {
		// Unbind event listeners
		$('*').unbind();
	});
	
	// Make the counter clickable
	$("#counter dd").click(function () {
		window.location = game_browser_path;
	});
	
	// Make new window links open in new tab or maximized browser
	$('a.new-window').click(function(){
		window.open(this.href);
		return false;
	});
};

/**
 * Returns the value of a name/value pair in the query string
 * @param {Object} variable
 * @return The value of the specified variable
 */
Framework.prototype.getQueryVariable = function (variable) {
	
	var query = window.location.search.substring(1);
	var vars = query.split("&");
	
	for (var i = 0; i < vars.length; i++) {
		var pair = vars[i].split('=');
		if (pair[0] === variable) {
			return pair[1];
		}
	}
	
};


/**
 * Gets the value of a cookie, if it exists
 * @param {Object} cookieName
 */
Framework.prototype.getCookie = function (cookieName) {
	
	var allcookies = document.cookie;
	var pos = allcookies.indexOf(cookieName + '=');
	if (pos !== -1) {
		
		var start	= pos + cookieName.length + 1; // add 1 to include the "=" sign
		var end		= allcookies.indexOf(';', start);
		
		if (end === -1) {
			end = allcookies.length;
		}
		
		var value = allcookies.substring(start, end);
		value = decodeURIComponent(value);
		
	}
	
	return value;
	
};

/**
 * Updates the specified cookie, creating it if it does not yet exist
 * @param {Object} cookieName
 * @param {Object} cookieValue
 * @param {Object} expires - Number of days to keep
 */
Framework.prototype.setCookie = function (cookieName, cookieValue, expires) {

	var exp = expires || 360; // default to one year
	var expiresDate = new Date();
	expiresDate.setTime(expiresDate.getTime() + (1000 * 60 * 60 * 24 * exp));

	document.cookie = cookieName + '=' + encodeURIComponent(cookieValue) + '; expires=' + expiresDate.toGMTString() + '; path=/';

};

/**
 * Updates the specified cookie, creating it if it does not yet exist
 * @param {Object} cookieName
 * @param {Object} cookieValue
 * @param {Object} expires - Number of days to keep
 */
Framework.prototype.setSessionOnlyCookie = function (cookieName, cookieValue) {
	document.cookie = cookieName + '=' + encodeURIComponent(cookieValue) + '; expires=; path=/';

};

/**
 * Opens a link in a new browser window, centered on the user's screen
 * @param {Object} url - The link to open
 * @param {Object} windowName - The name of the window
 */
Framework.prototype.openInNewWindow = function (url, windowName) {
	
	var winName = windowName || '';
	
	var w = 640;
	var h = 480;
	var winl = (window.screen.width * 0.5) - (w * 0.5);
	var wint = (window.screen.height * 0.5) - (h * 0.5) - 50; // Visually center the window by subtracting 50px or so
	
	var settings = 'width='+w+',height='+h+',toolbar=yes,location=yes,directories=yes,status=yes,menubar=yes,scrollbars=yes,copyhistory=yes,resizable=yes,top='+wint+',left='+winl;
	var win = window.open(url, winName, settings);
	
	//win.window.focus();
	
}

// Browser Testing _____________________________________________________________

/**
 * 
 */
Framework.prototype.ie6 = function () {
	return ($.browser.msie && $.browser.version < 7);
};

/**
 * 
 */
Framework.prototype.opera8 = function () {
	return ($.browser.opera && $.browser.version < 9);
};

/**
 * Test the user's browser so that certain features are not displayed for 
 * browsers that do not support them
 */
Framework.prototype.oldBrowser = function () {
	return (this.ie6() || this.opera8());
};

// Lazy Loading ________________________________________________________________

/**
 * Once the page has loaded, checks the config object for the presence of an 
 * array, "externalModules". If found, the module is loaded via AJAX
 * @param {Boolean} replaceContent - Whether to replace content container (passed through to loadModule())
 */
Framework.prototype.loadExternalModules = function (replaceContent) {
	
	var scope = this;
	var replace = replaceContent || false;
	
	$(document).ready(function () {
		if (typeof(config) !== 'undefined' && typeof(config.externalModules) !== 'undefined') {
			var i = 0;
			var size = config.externalModules.length;
			for (i = 0; i < size; i++) {
				if(config.externalModules[i].dataSource !== null && config.externalModules[i].dataSource !== '') {
					scope.loadModule(config.externalModules[i].elementID, config.externalModules[i].dataSource, config.externalModules[i].callback, replace);
				}
			}
		}
	});
	
};

/**
 * Loads a given external module at runtime
 * @param {String} elementID
 * @param {String} dataSource
 * @param {Function} callback
 */
Framework.prototype.loadModule = function (elementID, dataSource, callback, replace) {
	$.ajax({
		dataType: 'html',
		url: dataSource,
		success: function (data) {
			
			// Attach the new HTML
			if (replace) {
				$('#' + elementID).empty();
				$('#' + elementID).append(data);
			}
			else {
				$('#' + elementID).append(data);
			}
			// Hook up lightbox functionality to anything that might need it
			$('#' + elementID).find('a[rel*=facebox]').facebox({
				loadingImage: '/portal/css/assets/facebox/loading.gif',
				closeImage: '/portal/css/assets/facebox/closelabel.gif'
			});
			
			// Execute callback function
			if (typeof(callback) !== 'undefined') {
				callback();
			}
			
		}
	});
};

// Global callback methods for lazy-loaded components

/**
 * This is the callback for the Rupture / Community module. We have placed
 * it inside of Framework as the code is a little elongated for the front end,
 * and it will be called upon several times.
 */
Framework.prototype.ruptureCommunityCallback = function () {
	
	// Give accordion functionality to Rupture component in sidebar
	$('#sidebar .c_community').accordion({
		header: 'h3',
		fillSpace: false,
		alwaysOpen: true,
		autoHeight: false
	});
	
	// Fix for IE6 position bug
	$('#sidebar .c_community li').addClass('clearInner');
	$('#sidebar .c_community li > div > a').css({
		'display': 'block',
		'float': 'left'
	});
	
	// Delete spans created by jQuery
	$("#sidebar .c_community .ui-accordion-left, #sidebar .c_community .ui-accordion-right").remove();
	
	// Fix problem with showing top border of the bottomCap when it's closed
	$('#sidebar .c_community h3:not(:last)').click(function () {
		$(".c_community .bottomCap").css("padding-top", "15px");
	});
	
	$('#sidebar .c_community h3:last').click(function () {
		$("#sidebar .c_community .bottomCap").css("padding-top", "16px");
	});
	
};

/**
 * Cycles through creatures loaded into the Spore community module
 */
Framework.pauseSporeCycle = false; 
Framework.sporeIndex = 0;
Framework.sporeCreaturesToCycle = undefined;
Framework.prototype.cycleSporeImages = function () {
	
	//Used by the lightbox to pause the spore cycle
	if(Framework.pauseSporeCycle) {
		return;
	}
	
	var gt		= -1;
	var lt		= -1;
	var total	= $('#c_sporePromo div.creatureList div').length;
	
	// Runs only on the first time this function is called
	if (typeof(Framework.sporeCreaturesToCycle) === 'undefined') {
		
		// Get the amount to show at one time
		Framework.sporeCreaturesToCycle = $('#c_sporePromo div.creatureList div:visible').length;
		
		// Insert a horizontal rule on the game details page only
		if (Framework.sporeCreaturesToCycle > 3) {
			$('#communityDiv').after('<hr />');
		}
		
		// Wire rollover functionality to add to cart button
		/* NOCART BUTTON IN USE
		$('#c_sporePromo a.btn_addcart')
		.mouseover(function () {
			$(this).children('img').attr('src', '/portal/images/buttons/btn_add_cart_hover.gif');
		})
		.mouseout(function () {
			$(this).children('img').attr('src', '/portal/images/buttons/btn_add_cart.gif');
		})
		.mousedown(function () {
			$(this).children('img').attr('src', '/portal/images/buttons/btn_add_cart_press.gif');
		})
		.mouseup(function () {
			$(this).children('img').attr('src', '/portal/images/buttons/btn_add_cart.gif');
		});
		*/
		
	}
	
	if (Framework.sporeIndex >= (total - Framework.sporeCreaturesToCycle)) {
		
		Framework.sporeIndex = -(Framework.sporeCreaturesToCycle);
		
		gt = (total - Framework.sporeCreaturesToCycle) - 1;
		lt = total;
		
		$('#c_sporePromo div.creatureList div:gt(' + gt + '):lt(' + lt + ')').fadeOut(125, function () {
			var nextItem = Framework.sporeIndex + Framework.sporeCreaturesToCycle;
			$('#spore_creature_' + nextItem).fadeIn(125);
			Framework.sporeIndex++;
		});
		
	}
	else {
		
		gt = Framework.sporeIndex - 1;
		lt = Framework.sporeIndex + Framework.sporeCreaturesToCycle;
		
		$('#c_sporePromo div.creatureList div:visible').fadeOut(125, function () {
			var nextItem = Framework.sporeIndex + Framework.sporeCreaturesToCycle;
			$('#spore_creature_' + nextItem).fadeIn(125);
			Framework.sporeIndex++;
		});
		
	}
	
};

// Flash Embedding Utilities ___________________________________________________

/**
 * Utility method for embedding flash content. If the props object has a 
 * property of "video" that is true, it is added to an array of movies that 
 * listen for the open and close events dispatched by the lightbox component.
 * @param {Object} props
 * @return {Object} props
 */
Framework.prototype.embedSWF = function (props) {
	
	if (typeof($('#' + props.container)[0]) !== 'undefined') {
	
		var fVersion = props.minFlashVersion || this.min_flash_version;
		
		swfobject.embedSWF(props.swf, props.container, props.width, props.height, fVersion, this.expressInstall_swf, props.flashvars, props.params, props.attributes);
		
		if (props.video === true) {
			if (this.videoSWFs.length === 0) {
				/*this.enableVideoEventDispatching();*/
			}
			this.videoSWFs.push(props.container);
		}
		
		return props;
		
	}
	
};

/**
 * Provides reference to a Flash movie
 * @param {Object} movieName
 * @return The object for the associated Flash movie
 */
Framework.prototype.getSWF = function (movieName) {
	return swfobject.getObjectById(movieName);
};

/**
 * Delays execution of a specified function by adding it to a queue. This function 
 * is then executed by calling the playQueuedFunction method
 * @param {Object} f - The function to place in queue
 * @param {Object} p - The parameter(s) to pass to the function
 * @see   playQueuedFunction()
 */
Framework.prototype.setQueuedFunction = function (f, p) {
	
	this.queuedFunction = {
		func: f,
		param: p
	};
	
	// Can't pass a true function reference from Flash, so we need to hard-code it for the EP
	if (f.toString() == 'EA.framework.resumeEPVideo') {
		this.queuedFunction = {
			func: this.resumeEPVideo,
			param: p
		};
	}
	
};

/**
 * Plays the function that was last queued
 */
Framework.prototype.playQueuedFunction = function () {
	if (typeof(this.queuedFunction.func) !== 'undefined') {
		this.queuedFunction.func(this.queuedFunction.param);
	}
};

/**
 * Handles whether the EP resumes playback of video content or skips to next item
 * based on the user's age
 */
Framework.prototype.resumeEPVideo = function () {
	if (EA.framework.restrictedContentEnabled() == true) {
		EA.framework.getSWF('flash_ep').enableMatureContent();
	}
	else {
		EA.framework.getSWF('flash_ep').disableMatureContent();
	}
};

/**
 * Checks if mature content can be displayed to the current user by checking the 
 * value of a preset cookie
 * @return {Boolean}
 */
Framework.prototype.restrictedContentEnabled = function () {
	return this.getCookie('matureContent10') == 1;
};

/**
 * Either prompts the user to enter their age or displays an error if they are too young
 */
Framework.prototype.displayAgeGate = function () {
	
	if (this.getCookie('matureContent10') === 0) {
		
		// Too young - display error
		$.facebox({
			ajax: '/portal/static/pages/age_gate_error.php',
			loadingImage: '/portal/css/assets/facebox/loading.gif',
			closeImage: '/portal/css/assets/facebox/closelabel.gif'
		});
		
	}
	else {
		
		// Show age gate
		$.facebox({
			ajax: '/portal/static/pages/age_gate_form.php',
			loadingImage: '/portal/css/assets/facebox/loading.gif',
			closeImage: '/portal/css/assets/facebox/closelabel.gif'
		});
		
	}
};

/**
 * Hides the thumbnail navigation if there was only 1 item loaded into the EP
 */
Framework.prototype.hideEPThumbs = function () {
	var ep = $('#flash_ep');
	if (ep.length == 0) {
		ep = $('#gamePod');
	}
	//var epHeight = ep.attr('height');
	//var newHeight = epHeight - 100;
	var newHeight = 369;
	if (ep.length > 0) {
		ep.attr('height', newHeight);
		ep.children('object').attr('height', newHeight);
		ep.parent().css('height', newHeight + 'px');
	}
}

// Manual Lightbox Instantiation _______________________________________________

/**
 * Automatically displays the add to cart popup. Called by Flash components
 * @param {Object} cartLink - Supplied in the XML given to Flash and passed automatically
 */
Framework.prototype.purchaseGame = function (cartLink) {
	$.facebox({
		ajax: cartLink
	});
};

// Image Utilities _____________________________________________________________

/**
 * Returns the path to a large image given any thumbnail's path
 * @param {String} inputImageSrc - The src attribute of a thumbnail
 */
Framework.prototype.getLargeImage = function (inputImageSrc) {
	
	// Find the last underscore ("_") occurence and strip out everything from
	// there to the start of the extension (the "." in ".jpg");
	var sizeSuffix = inputImageSrc.substring(inputImageSrc.lastIndexOf('_'), inputImageSrc.lastIndexOf('.'));
	var largeImage = inputImageSrc.split(sizeSuffix).join('');
	
	return largeImage;
	
};

/**
 * Preloads rollover and press states for "Add to Cart", "More Info", etc. buttons
 * To preload a new set of button states, append the normal state filename to the array.
 * 
 * Filenames MUST be formatted as follows (any extension may be used):
 * Normal State: filename.gif
 * Hover State: filename_hover.gif
 * Press State: filename_press.gif
 */
Framework.prototype.preloadRollovers = function () {
	
	var buttons = [
		{
			selector: 'a.btn_info',
			normalState: '/portal/images/buttons/btn_more_info.gif'
		}, 
		{
			selector: 'a.btn_addcart',
			normalState: '/portal/images/buttons/btn_add_cart.gif'
		},
		{
			selector: 'a.btn_buyalbum',
			normalState: '/portal/images/buttons/btn_buy_album.gif'
		},
		{
			selector: 'a.btn_playNow',
			normalState: '/portal/images/buttons/btn_play_now.gif'
		},
		{
			selector: 'a.btn_add_all_games',
			normalState: '/portal/images/buttons/btn_add_all_games.gif'
		},
		{
			selector: 'a.btn_iTunes',
			normalState: '/portal/images/buttons/btn_itunes.gif'
		}
	];
	
	var i = 0;
	var size = buttons.length;
	
	var fileName;
	var fileExt;
	var hoverImg;
	var pressImg;
	
	// Create hover and press states
	for (i = 0; i < size; i++) {
		
		fileName	= buttons[i].normalState.substring(0, buttons[i].normalState.lastIndexOf('.'));
		fileExt		= buttons[i].normalState.substring(buttons[i].normalState.lastIndexOf('.'), buttons[i].normalState.length);
		
		hoverImg	= new Image();
		pressImg	= new Image();
		
		hoverImg.src = fileName + '_hover' + fileExt;
		pressImg.src = fileName + '_press' + fileExt;
		
		buttons[i].hoverState = fileName + '_hover' + fileExt;
		buttons[i].pressState = fileName + '_press' + fileExt;
		
	}
	
	// Apply rollover and hover states
	$(buttons).each(function () {
		
		var btn = this;
		
		$(btn.selector)
		.mouseover(function () {
			$(this).children('img').attr('src', btn.hoverState);
		})
		.mouseout(function () {
			$(this).children('img').attr('src', btn.normalState);
		})
		.mousedown(function () {
			$(this).children('img').attr('src', btn.pressState);
		})
		.mouseup(function () {
			$(this).children('img').attr('src', btn.normalState);
		});
		
	});
	
};

// Browser-Specific Work-Arounds _______________________________________________

/**
 * Simulates :hover event for all elements in IE by adding a 'hover' class when
 * the element is moused over by the user. This method should ONLY be called by 
 * IE7 and lower!
 * 
 * Optionally specify a class to join into the fakeHover class since IE6 can't handle chained class selectors in CSS
 * Whether or not a joinClass was provided, it always adds the plain fakeHover class for backwards compability with existing CSS
 * 
 */
Framework.prototype.fakeHover = function (selection, joinClass) {
	$(selection).hover(
		function () {
			if (joinClass && $(this).hasClass(joinClass)) {
				$(this).addClass(joinClass+'_fakeHover');	
			}
			$(this).addClass('fakeHover');
		}, 
		function () {
			if (joinClass && $(this).hasClass(joinClass)) {
				$(this).removeClass(joinClass+'_fakeHover');
			}
			$(this).removeClass('fakeHover');
		}
	);
};

// Global Utilities ____________________________________________________________

// http://www.howtocreate.co.uk/tutorials/javascript/browserwindow (Thanks, Munish!)
Framework.prototype.getScrollXY = function () {
	var scrOfX = 0, scrOfY = 0;
	if (typeof(window.pageYOffset) === 'number') {
		//Netscape compliant
		scrOfY = window.pageYOffset;
		scrOfX = window.pageXOffset;
	}
	else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) {
		//DOM compliant
		scrOfY = document.body.scrollTop;
		scrOfX = document.body.scrollLeft;
	}
	else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
		//IE6 standards compliant mode
		scrOfY = document.documentElement.scrollTop;
		scrOfX = document.documentElement.scrollLeft;
	}
	return [scrOfX, scrOfY];
};

/** It appears that jQuery 1.2.6 has a few cross browser problems when getting the
 * hieght of the window (document is top of html elements to bottom, window is
 * browser visibilitiy).
 * I found a small patch from
 * http://www.koders.com/javascript/fid69E7017C9DC7FDEFF58D3B1C36F15B1D22EBA424.aspx
 * and just used the height function fix
*/ 
jQuery.fn._height = jQuery.fn.height;
jQuery.fn.height = function () {
	if (this[0] == window) {
		// ie, opera...
		return self.innerHeight || jQuery.boxModel && document.documentElement.clientHeight || document.body.clientHeight;
	}
	if (this[0] == document) {
		// firefox (gecko)
		return Math.max(document.body.scrollHeight, document.body.offsetHeight);
	}
	return this._height(arguments[0]);
};

// Global AJAX Indicators ______________________________________________________
/**
 * Handles AJAX loading animations and information 
 * @param {Object} el - The containing element which is being updated
 */
Framework.prototype.paginationBeforeAjax = function(el){
	// Height
	var h = jQuery(el).height();
	if (h === 0) {
		h = 85; // 85 is minimum height of ajax loading div
	}
	var top = (h / 2) - 25; //25 = half height of loading image

	// Width	
	var w = jQuery(el).width();
	if(w === 0){
	
	}
	var left = (w / 2) - 86; //86 = half width of loading image


	// If we haven't created our loader, do so
	if (jQuery("#ajax-loader").length === 0) {
		jQuery(el).prepend("<div id=\"ajax-loader\" style=\"height:" + h + "px; width:" + w + "px;\"><img src=\"/portal/images/loading.gif\" style=\"top:" + top + "px; left:" + left + "px;\" alt=\""+ "Loading Content...".localize() + "\" /></div>");
	}else{
		// Else, update it's positioning.
		jQuery("#ajax-loader").css({
			height: h,
			width: w
		}).children("img").css({
			top: top,
			left: left
		});
	}
	// Hide the el and fade in the Loader
	jQuery(el).children(":not(#ajax-loader):not(.bottomClosed)").hide();
	jQuery("#ajax-loader img").fadeIn("fast");
}

Framework.prototype.paginationAjaxError = function(el){
	// To be used for callBacks from AJAX errors.
}

Framework.prototype.trackStudioView = function(path, studio, id){
	jQuery.ajax({
		type: "GET",
		url: path + "?studio=" + studio + "&id="+ id + "&type=view&key=&data="
	});
}

// Random Components ___________________________________________________________

Framework.prototype.getAccordionIndex = function (defaultIndex) {
	if (this.getCookie('accordionIndex')) {
		return parseInt(this.getCookie('accordionIndex'));
	}
	else {
		return defaultIndex;
	}
};

Framework.prototype.initBrowseGamesAccordion = function (defaultIndex) {
	$('#browseGames').removeClass('disabled');
	$('#browseGames').accordion({
		header: 'h3',
		active: EA.framework.getAccordionIndex(defaultIndex),
		alwaysOpen: false,
		autoHeight: false,
		collapsible: true,
		change: function(event, ui) {
			var index = -1;
			$('#browseGames .ui-accordion-header').each(function(i) {
				if ($(this).hasClass('selected')) {
					index = i;
				}
			});
			EA.framework.setCookie('accordionIndex', index);
		}
	});
	
	$("#browseGames .ui-accordion-left, #browseGames .ui-accordion-right").remove();
};


// Omniture Tracking ___________________________________________________________

Framework.prototype.omnitureTrackFullScreen = function (videoTitle) {
	
};

Framework.prototype.omnitureTrackAddToCart = function (videoTitle) {
	
};

Framework.prototype.omnitureTrackMoreInfo = function (videoTitle) {
	
};

Framework.prototype.linksExternal = function(){
    if (document.getElementsByTagName) {
        var anchors = document.getElementsByTagName("a");
        for (var i = 0; i < anchors.length; i++) {
            var anchor = anchors[i];
            if (anchor.getAttribute('href') && anchor.className == 'external new-window') {
                anchor.target = "_blank";
            }
        }
    }
};

// script initiates on page load. 
Framework.prototype.addEvent = function(obj, type, fn){
    if (obj.addEventListener) {
        obj.addEventListener(type, fn, false);
        this.EventCache.add(obj, type, fn);
    }
    else 
        if (obj.attachEvent) {
            obj["e" + type + fn] = fn;
            obj[type + fn] = function(){
                obj["e" + type + fn](window.event);
            }
            obj.attachEvent("on" + type, obj[type + fn]);
            this.EventCache.add(obj, type, fn);
        }
        else {
            obj["on" + type] = obj["e" + type + fn];
        }
};

Framework.prototype.EventCache = function(){
    var listEvents = [];
    return {
        listEvents: listEvents,
        add: function(node, sEventName, fHandler){
            listEvents.push(arguments);
        },
        flush: function(){
            var i, item;
            for (i = listEvents.length - 1; i >= 0; i = i - 1) {
                item = listEvents[i];
                if (item[0].removeEventListener) {
                    item[0].removeEventListener(item[1], item[2], item[3]);
                };
                if (item[1].substring(0, 2) != "on") {
                    item[1] = "on" + item[1];
                };
                if (item[0].detachEvent) {
                    item[0].detachEvent(item[1], item[2]);
                };
                item[0][item[1]] = null;
            };
                    }
    };
}();

// Self-Instantiation __________________________________________________________

var EA = {};
EA.framework = new Framework();
EA.framework.addEvent(window, 'unload', EA.framework.EventCache.flush);
EA.framework.addEvent(window, "load", EA.framework.linksExternal);

