﻿var feeds = {
	feedItems			: new Object(),
	filteredItems		: new Array(),
	tagTree				: {
							hasTag : function(in_tag) {
								for (var curBucket in this)
									if (typeof(this[curBucket]) == 'object' && this[curBucket]['tags'][in_tag])
										return true;
								return false;
							},
							tagIsPublic : function(in_tag) {
								for (var curBucket in this)
									if (typeof(this[curBucket]) == 'object' && this[curBucket]['tags'][in_tag])
										return !this[curBucket]['internal'];
								return false;
							},
							getDisplayName : function(in_tag) {
								for (var curBucket in this)
									if (typeof(this[curBucket]) == 'object' && this[curBucket]['tags'][in_tag])
										return this[curBucket]['tags'][in_tag].tagName;
								return false;
							},
							getArticles : function(in_tag) {
								for (var curBucket in this)
									if (typeof(this[curBucket]) == 'object' && this[curBucket]['tags'][in_tag])
										return this[curBucket]['tags'][in_tag].articles;
								return false;
							},
							getParent : function(in_tag) {
								for (var curBucket in this)
									if (typeof(this[curBucket]) == 'object' && this[curBucket]['tags'][in_tag])
										return curBucket;
								return false;
							}
						  },
	
	filteredItemsPos	: 0,
	filteredItemsLimit	: 6,
	lastWrittenCount	: 0,
	feedLoaded			: false,
	brand				: 'Motorsports',
	updatesRun			: 0,
	matchColumnHeight	: false,
	debug				: false,
	
	
	/*********************************
	 * PUBLIC METHODS                *
	 *********************************/

	// read() converts XML in myFeed into feedItems with help from parseXML()
	read : function(feedURL) {
        var feed = new Ajax(feedURL, {
			method: 'get',
			onComplete: function(text, xml) { // text is an unneeded variable though it must be in this function param list
				this.parseXML(xml);
			}.bind(this)
		}).request();
    },


	// update() handles the outputting of information to the page
	// divToWriteTo is the div the feed content (with optional outputExtraInfo) will be put into
	// feedIDs is an array of feed array indices, filterIDs is likewise but of tags
	update : function(divToWriteTo, feedTags, filterTags, outputExtraInfo) {
		// Set default for outputting extra info
		outputExtraInfo = outputExtraInfo || false;
		
		// Only proceed if parseXML() has fully read in the data
		if (!this.feedLoaded) {
			setTimeout("feeds.update('"+divToWriteTo+"', ['"+feedTags.toString()+"'], ['"+filterTags.toString()+"'], "+outputExtraInfo+");", 1000);
			return;
		}
		// Clean out previous data
		this.clearFilteredItems();

		// Build out the <item>s in the data that have one or more of the tags listed in tagsToShow
		this.build(feedTags, filterTags);
		
		// Output items
		//alert(divToWriteTo);
		this.outputLinks(divToWriteTo+"_container", outputExtraInfo);
		
		this.updatesRun++;
	},

	// Write filteredItemsLimit number of items to page, direction defaults to 'forward' though can be 'backwards' to traverse backwards 
	outputLinks : function(divToWriteTo, outputExtraInfo, direction) {
		// Set default value for direction
		direction = direction || 'forward';
		
		// Set default for outputting extra info
		outputExtraInfo = outputExtraInfo || false;
		
		var textConglomerate = '<ul>';
		var itemsWritten = 0;
		divToWriteTo = $(divToWriteTo);
		
		// Setup how far to skip ahead in the results on page load (which we check by seeing if this.update() has ever completed a full run)
		if (!this.updatesRun) {
			// Nab the value
			skipValue = getParameter('skip');
			
			// If we find one (check to be safe), set it
			if (skipValue && parseInt(skipValue) < this.filteredItems.length) {
				this.setFilterPosition(parseInt(skipValue))
			}
		}
		
		switch (direction) {
			case 'forward':
				for (var i = this.filteredItemsPos;
					 i < this.filteredItemsPos + this.filteredItemsLimit;
					 i++) {
					
					// Don't blow by array boundary
					if (i >= this.filteredItems.length)
						break;

					if (typeof(this.filteredItems[i].text) == "string") {
						textConglomerate += this.filteredItems[i].text;
						itemsWritten++;
					}
				}

				// Update sentinel value
				this.filteredItemsPos += itemsWritten;
			break;
			
			case 'backward':
				this.filteredItemsPos = this.filteredItemsPos - this.lastWrittenCount
				
				for (var i = this.filteredItemsPos;
					 i > this.filteredItemsPos - this.filteredItemsLimit;
					 i--) {
					
					// Don't blow by array boundary
					if (i < 0)
						break;

					if (typeof(this.filteredItems[i].text) == "string") {
						textConglomerate += this.filteredItems[i].text;
						itemsWritten++;
					}
				}
			break;
		}
		
		textConglomerate += '</ul>';
		
		// Write out filtered items
		divToWriteTo.setHTML(textConglomerate);
		
		// Update sentinel value
		this.lastWrittenCount = itemsWritten;
		
		// This is very much tied to the specific HTML of the News archive page.  TODO: create a more general solution
		if (outputExtraInfo) {
			var viewingRangeMin = this.filteredItemsPos - itemsWritten + 1;
			viewingRangeMin = (viewingRangeMin >= 0) ? viewingRangeMin : 0;
		
			// Update info on viewed items
			if (this.filteredItems.length > 0) {
				divToWriteTo.getParent().getElement('h6').setHTML("Now viewing "+viewingRangeMin+"&ndash;"+this.filteredItemsPos+" of "+this.filteredItems.length);
				divToWriteTo.getParent().getElement('p').setHTML("Click on the headlines below to view the full story. Or click along the side to narrow your search.");
			}
			else {
				divToWriteTo.getParent().getElement('h6').setHTML("There where "+this.filteredItems.length+" items found.");
				divToWriteTo.getParent().getElement('p').setHTML("Please select a few more options on the left to broaden your search.");
			}
		
			// Choose how much of the pagination controls to show
			// Previous nav link
			if (viewingRangeMin > 1) {
				$('previousNav').setStyle('visibility', 'visible');
			}
			else {
				$('previousNav').setStyle('visibility', 'hidden');
			}
		
			// Nav divider
			if (this.filteredItemsPos < this.filteredItems.length && viewingRangeMin > 1) {
				$('dividerNav').setStyle('visibility', 'visible');
			}
			else {
				$('dividerNav').setStyle('visibility', 'hidden');
			}
		
			// Next nav link
			if (this.filteredItemsPos < this.filteredItems.length) {
				$('nextNav').setStyle('visibility', 'visible');
			}
			else {
				$('nextNav').setStyle('visibility', 'hidden');
			}
		}
		
		
		// Match column heights
		if (this.matchColumnHeight) {
			var maxHeight = 0;

			// Get the set of columns on this page with the class of the div we're writing to
			var columnClass = divToWriteTo.getProperty('class');
			var columns = $$('.'+columnClass);
			
			// Find the tallest of the divs
			columns.each(function(elt) {
				var curHeight = elt.getSize().size.y;
				if (curHeight > maxHeight) maxHeight = curHeight;
			});

			// Propagate max height to all columns
			columns.each(function(elt) {
				elt.getElement('ul').setStyle('height', maxHeight+'px');
			});
		}
		
		//Tracking for HBX is working, so we do not need this.
        $$('.news_link').each(function(f){
		    $(f).onclick = function(){
		    var linkName = $(f).getAttribute('title');
			    _hbSet('lid', linkName);
			    _hbSet('lpos', 'News Nav');
			    _hbSend();
		    }
	    });
	    
	    
	},
	
	// Writes a single article to a page and prevents it from being rewritten.
	// Takes optional parameters for a tag and an index into the array of articles with the tag, defaults are 'featured' and 0.
	showFeatured : function(tag, index) {
		tag = tag || 'featured';
		index = index || 0;
		
		// Only proceed if parseXML() has fully read in the data
		if (!this.feedLoaded) {
			setTimeout("feeds.showFeatured('"+tag+"', "+index+");", 1000);
			return;
		}
		
		// Get a copy of (i.e. not a reference to) this.tagTree.getArticles(tag)
		// This is important to do so that the shift() in the following for() does not modify the array in this.tagTree.
		var articlesWithTag = this.tagTree.getArticles(tag).copy();
		
		for (var i = 0; i <= index; i++) {
			var articleIndex = articlesWithTag.shift();
		}
		
		var item = this.feedItems[articleIndex];
		item.onScreen = true;
		
		// set img
		var img = '<a href="'+item.link+'" class="news_link" title="Featured News Image" name="&lid=Featured News Image&lpos=News Nav"><img src="' + (item.enclosure ? item.enclosure : '/shared/images/motorsports/featurednewsdefault.jpg')+ '" width="290" /></a>';
		$('featureImg').setHTML(img);
		
		// set title
		($$('#featureStory h4'))[0].setText(item.title);
		
		// set info
		($$('#featureStory .articleInfo'))[0].setHTML(item.pubDate + '<br/>' + item.source);
		
		// descStorage is a temporary element used to strip out the HTML from the feed's contents.
		// We first assign its innerHTML to be the HTML-laden contents of the feed but later we'll pull the text only out via descStorage.getText().
		var descStorage = new Element('div', {});
		descStorage.setHTML(item.description);
		
		// set text
		($$('#featureStory .articleText'))[0].setHTML(descStorage.getText().substring(0, 150)+'&hellip;');
		
		// set text
		($$('#featureStory .readMoreLink'))[0].setProperty('href', item.link);
	},
	
	// Return a reference to the object for the asked for <item> or return false if it can't be found
	getArticleByGUID : function(guid) {
		for (var item in this.feedItems) {
            if (this.feedItems[item]['guid'] == guid)
		        return this.feedItems[item];
  
		}
		
		return false;
	},
	
	// Set the number of filtered items displayed at a time
	setFilterLimit : function(val) {
		this.filteredItemsLimit = val;
	},

	// Set the number of filtered items displayed at a time
	setFilterPosition : function(val) {
		this.filteredItemsPos = val;
	},
	
	setMatchColumns : function(val) {
		this.matchColumnHeight = val;
	},

	// Resets feedItems and filteredItems
	reset : function() {
		this.feedItems = new Object();
		this.tagTree = new Object();
		this.clearFilteredItems();
	},

	// Resets just filteredItem
	clearFilteredItems : function() {
		this.filteredItems = new Array();
		this.filteredItemsPos = 0;
	},
	
	
	/*********************************
	 * PRIVATE METHODS               *
	 *********************************/
	
	
	// parseXML() does the actual conversion from RSS <item>s into an in-memory array
	parseXML : function(feedXML) {		
		var channel = feedXML.getElementsByTagName('channel')[0];		
		var items = channel.getElementsByTagName('item');
		var itemCount = items.length;
		
		// Loop through all <item>s and build up feedItems
		for (var i = 0; itemCount > i; i++) {
			var curItem = items[i];
			
			this.feedItems[i] = new Object();
			this.feedItems[i]['description'] = new Object();
			this.feedItems[i]['categories'] = new Array();
			this.feedItems[i]['links'] = new Array();
			this.feedItems[i]['onScreen'] = false;
			
			var nodeCount = curItem.childNodes.length;
			for (var n = 0; nodeCount > n; n++) {
				var curNode = curItem.childNodes[n];
				
				// if current node is an element and it has a child...
				if ((curNode.nodeType == 1 && curNode.firstChild) || (curNode.nodeName == 'enclosure')) {
					// <ENCLOSURE> HANDLER
					if (curNode.nodeName == 'enclosure') {
						this.feedItems[i]['enclosure'] = curNode.getAttribute('url');
					}
					
					// <CATEGORY> HANDLER
					else if (curNode.nodeName == 'category') {
						// We need to ensure we don't handle <category> nodes that have the 'domain' attribute because internal PR
						// news uses these nodes for other purposes that are irrelevant to the general data stored in
						// this.feedItems
						if (curNode.attributes.length == 0) {
							this.feedItems[i]['categories'] = curNode.firstChild.nodeValue.split(' ');
						}else{
						
						    this.feedItems[i]['links'].push({
					            name: curNode.firstChild.nodeValue,
					            url: curNode.getAttribute('domain')

				            });
						}  
					}
					
					// <LINK> HANDLER
					// Fix pathing to be relative to current domain
					else if (curNode.nodeName == 'link') {
						this.feedItems[i]['link'] = '/en' + this.splitter(curNode.firstChild.nodeValue, '/en')[1];
					}
					
					// <DC:SUBJECT> HANDLER
					// This is where this.tagTree is populated with the contents of the feeds
					else if (curNode.nodeName == 'dc:subject') {
						var tagBucket = curNode.attributes[1].nodeValue;
						var displayTag = curNode.attributes[0].nodeValue;
						var machineTag = curNode.firstChild.nodeValue;
						
						// Create new tag bucket if we haven't seen this one yet
						if (!this.tagTree[tagBucket]) {
							this.tagTree[tagBucket] = new Object();
							
							this.tagTree[tagBucket].internal = (tagBucket == 'System Tag' || tagBucket == 'Dodge Vehicles' || tagBucket == 'Jeep Vehicles');
							this.tagTree[tagBucket].tags = new Array();
						}
						
						// Create new tag if we haven't seen this one yet
						if (!this.tagTree[tagBucket].tags[machineTag]) {
							this.tagTree[tagBucket].tags[machineTag] = new Object();
							
							this.tagTree[tagBucket].tags[machineTag].tagName = displayTag;
							this.tagTree[tagBucket].tags[machineTag].articles = new Array();
							
							if (machineTag == 'internal' ||
								machineTag == 'external' ||
								machineTag == 'craftsman' ||
								machineTag == 'sprint_cup') {
								this.tagTree[tagBucket].tags[machineTag].feedLike = true;
								
								if (machineTag == 'internal')
									this.tagTree[tagBucket].tags[machineTag].tagName = displayTag+' '+this.brand;
								else if (machineTag == 'external')
									this.tagTree[tagBucket].tags[machineTag].tagName = this.brand+' '+displayTag;
								else if (machineTag == 'craftsman')
									this.tagTree[tagBucket].tags[machineTag].tagName = this.brand+' '+displayTag;
								else if (machineTag == 'sprint_cup')
									this.tagTree[tagBucket].tags[machineTag].tagName = this.brand+' '+displayTag;
							}
						}
						
						// insert item index into the list of articles where this tags was found
						this.tagTree[tagBucket].tags[machineTag].articles.push(i);
					}
					
					// <PUBDATE> HANDLER
					// Make date formatting consistent
					else if (curNode.nodeName == 'pubDate') {
						var pubDateStr = curNode.firstChild.nodeValue;

						// Create a date object with the date from the feed
						var pubDateObj = new Date(pubDateStr);

						// Set new date, using appropriate formatting (m/d/yyyy) if possible
						var formattedDate = '';
						if (pubDateObj.getMonth() || pubDateObj.getMonth() == 0) {
							formattedDate += pubDateObj.getMonth() + 1 + '/';
						}

						if (pubDateObj.getDate()) {
							formattedDate += pubDateObj.getDate() + '/';
						}

						if (pubDateObj.getFullYear()) {
							formattedDate += this.customGetYear(pubDateObj);
						}

						if (!formattedDate) {
							formattedDate = pubDateStr;
						}

						// change node value
						this.feedItems[i]['pubDate'] = formattedDate;
					}
					
					// Default XML node handler
					else {
						this.feedItems[i][curNode.nodeName] = curNode.firstChild.nodeValue;
					}
				}
			}
		}
		
		// Feed is now loaded and fully parsed, build() is now allowed to fire
		this.feedLoaded = true;
	},

	// Looks for tag-matches between the current filters and all the items in feedID, writes data about matches back to document inside of elt
	build : function(feedTags, filterTags) {
		var articleList = new Array();
		
		// Build list of articles from the listed sources
		for (var tag in feedTags) {
			if (typeof(feedTags[tag]) == 'string') {
				// moo's array.merge() concats two arrays and filters out duplicates
				articleList.merge(this.tagTree.getArticles(feedTags[tag]));
			}
		}
		
		// Sort the list of articles now that we have the full collection of articles that may be displayed
		articleList.sort(function(a, b){ return a - b; });
		
		// Loop over articleList and compare to filterTags.
		// The only articles that will remain in articleList are the ones that match at least one tag in filterTags
		if (filterTags.length && filterTags[0] != '') {
			
			// Use moo's array.filter() to screen out articles that don't include at least one of the filterTags
			articleList = articleList.filter(function(item, index) {
				for (var tag in filterTags) {
					if (typeof(filterTags[tag]) == 'string') {
						
						// if the article's tags match the current tag being examined, include it in the filter() results
						if (feeds.feedItems[articleList[index]]['categories'].contains(filterTags[tag])) {
							return true;
						}
					}
				}
				
				// We passed through every tag in filterTags and didn't match any.
				// This article has none of filterTags, return false to filter(), thus removing the article from articleList.
				return false;
			});
		}
		
		// We've got the full list of articles, now construct and push them into this.filteredItems
		for (var article in articleList) {
			var articleID = articleList[article];
			
			// Make sure the current foreach item isn't a function and that the article in question isn't already on screen.
			// Have to check if the articleID is an int OR if it's 0 which is an int but evaluates to false unless we specifically check for 0.
			if ((parseInt(articleID) || parseInt(articleID) == 0) && !this.feedItems[articleID].onScreen) {
				this.filteredItems.push({
					article: articleID,
					text: this.build_helper(this.feedItems[articleID], articleID)
				});
			}
		}
	},
	
	

	build_helper : function(item, ID) {
		var itemLayout = '<li><a class="news_link copy" title="'+item['title']+'" href="' + item['link'] + ((item['link'].indexOf('bounce.html') != -1) ? ' &title='+escape(item['title']) : '') + '" name="&lpos=News Nav"' + ((item['link'].indexOf('bounce.html') != -1) ? ' target="_blank"' : '') + '>';
		itemLayout += item['title'];
		itemLayout += (item['link'].indexOf('bounce.html') != -1) ? ' <img src="/shared/images/motorsports/home/openwindow.gif" />' : '';
		itemLayout += (this.debug ? (' <strong>' + ID + '</strong>') : '</a>');
		//itemLayout += item['pubDate'] + '<br />';
		
		// Write out tags if there are any
		if (item.categories.length > 0) {
			var tagsWritten = 0;
			
			// Loop through all tags
			for (var tag_id in item.categories) {
				if (!isNaN(parseInt(tag_id))) {
					var tag = item.categories[tag_id];
					
					if (this.tagTree.tagIsPublic(tag)) {
						//itemLayout += (!tagsWritten) ? 'Subjects:' : ' -';
						//itemLayout += ' <a class="news_link" title="'+tag+'" name="&lpos=News Nav" href="/en/motorsports/news/archive/?subject=' + tag + '">' + this.tagTree.getDisplayName(tag) + '</a>';
						tagsWritten++;
					}
				}
			}
			//itemLayout += (tagsWritten) ? '<br />' : '';
			itemLayout += (tagsWritten) ? '' : '';
		}
		
		itemLayout += '<br /><span class="source_class">' + 'Source: ' + item['source'] + '</span>';
		itemLayout += '<span class="date_class">' + item['pubDate'] + '</span></li>';
		
		return itemLayout;
	},
	
	splitter : function(item, splitOn) {
		return item.split(splitOn);
	},
	
	// customGetYear() always returns the correct year when passed a 2 digit year number
	// function from http://quirksmode.org/js/introdate.html
	customGetYear : function(theDate) {
		var y = theDate.getYear() % 100;
		y += (y < 38) ? 2000 : 1900;
		return y;
	}
}
//alert("feeds ");