var radar = {

	// Initialise the Radar application
	init: function() {	
		this.CONFIG = {
			LATEST_STORIES_URL		: "story/json",
			MAX_STORIES				:	30,
			THUMBNAIL_HOST			: "http://newsimg.bbc.co.uk/",
			STORY_ITEM_TEMPLATE 	: 	'<li>' +
										'</li>',
			STORY_CONTENTS_TEMPLATE	: 	'	<div class="title">' +
                                        '		<p class="section">{section}</p>' +
                                        '		<h2><a href="{url}" target="new">{headline}</a></h2>' +
                                        '	</div>' +
                                        '	<img src="{thumbnailURL}" alt="{headline}" />' +
                                        '	<p class="publication-date"><span class="published"><strong>Published</strong> {publicationDate}</span></p>' +
                                        '	<p class="summary">{summary}</p>',										
			ABOUT_PANEL_TEMPLATE	:	'<h2 class="about">BBC News Radar</h2>' +
										'<p class="tagline">Monitoring low-flying news since 2008.</p>' +
										'<h3 class="about">About</h3>' +
										'<p class="about">The BBC News Radar displays a list of' +
										'   recently published stories from any section of the BBC News web site.' +
										'   It displays both stories that have just been published for the first' +
										'   time and stories that have been recently updated.</p>' +
										'<h3 class="about">Beta</h3>' +
										'<p class="about">This is an experimental version of this application which we\'ve' +
										'   put together in order to get your feedback to help us decide if' +
										'   we should create a more advanced version. As such, we can\'t' +
										'   guarantee that it will always behave itself. Please use it,' +
										'   and tell us what you think about it, but don\'t be too disappointed' +
										'   if it doesn\'t do the right thing all the time.</p>' + 
										'<h3 class="about">Feedback</h3>' +
										'<p class="about">We\'d like to hear your feedback. If you have any feedback' +
										'   that you\'d like to share with us, please click on the \'Feedback\' button.'+
										'</p>'
		}
		
		this.displayedStories = []; // array to store the stories displayed on the page
		this.lastUpdated = null;
		this.storyListElement = glow.dom.get("ol");
		this.aboutPanel = new glow.widgets.Panel(glow.dom.create(this.CONFIG.ABOUT_PANEL_TEMPLATE), { 'anim': 'fade' });

		glow.events.addListener(
			"#about",
			"click",
			function () { 
				this.aboutPanel.show();
			},
			this
		);
	},

	// Request the latest stories from the server. If this is the
	// first request (lastUpdated is null), then just ask for the 
	// 'latest stories', otherwise ask for the latest stories since
	// the last time we asked.
	requestLatestStories: function() {
		var that = this;
		
		var requestURL = this.CONFIG.LATEST_STORIES_URL;
		var firstTime = false;
		
		if(this.lastUpdated!=null) {
			requestURL = requestURL + '?since=' + this.lastUpdated;
		} else {
			firstTime = true;
		}
		
		var getRef = glow.net.get(requestURL, {
			onLoad: function(response) {
				var responseDocument = response.json();
				that.lastUpdated = responseDocument.lastUpdated;
				that.updateDisplayedStories(responseDocument.stories.reverse(), firstTime);
				that.removeOldStories();
			},
			onError: function(response) {} // should probably do something here.. but what?
		});
	},
	
	// Update the displayed list of stories.
	// This function will take a list of stories.
	//
	// Any stories in this list that are not
	// already displayed will be added to the
	// DOM.
	//
	// Any stories in this list that are already
	// displayed will be marked with an 'updated'
	// css class.
	updateDisplayedStories: function(stories, firstTime) {
	
		var displayStoryAnimations = [];
		var storiesBeingAdded = [];
	
		for( var i=stories.length-1; i>=0; i-- ) {
			var story = stories[i];
			
			// check to see if the story is already on the page
			var existingStory = null;
			var k = 0;
			while( existingStory===null && k <this.displayedStories.length ) {
				if(this.displayedStories[k].id === story.id) {
					existingStory = this.displayedStories[k];
				}
				k++;
			}
			
			if(existingStory!=null) {
				this.updateStory(existingStory, story);
			} else {
				
				// reformat the story section before merging the story and the template
				story.section = story.section.replace(/>>/i, ">");
				
				// replace the thumbnailURL with a default thumbnail if the image is missing
				if(story.thumbnailURL===null || story.thumbnailURL==='') {
					story.thumbnailURL = '_img/no-thumb.jpg';
				} else {
					story.thumbnailURL = this.CONFIG.THUMBNAIL_HOST + story.thumbnailURL;	
				}
												
				var storyDisplayItem = glow.dom.create(this.CONFIG.STORY_ITEM_TEMPLATE);
				var storyDisplayContents = glow.dom.create(glow.lang.interpolate(this.CONFIG.STORY_CONTENTS_TEMPLATE, story));
				story.storyDisplayItem = storyDisplayItem;
				story.storyDisplayContents = storyDisplayContents;
				
				// If the story is an 'update' add a class to the item
				if(story.firstPublicationDate!=story.publicationDate) {
					//storyDisplayItem.addClass('isupdate');
					var storyFirstModifiedDate = dateFromISOString(story.firstPublicationDate);
					storyDisplayContents.get('a').after('<span class="update"> update</span>');
					storyDisplayContents.get('.published').after('<span class="firstPublished">, <strong>First Published</strong> ' + timeSinceString(storyFirstModifiedDate) + '</span>');
				}
				
				this.displayedStories.unshift(story);
				
				// if this is the first load, just add the li to the dom without any effects
				if(firstTime===true) {
					storyDisplayContents.appendTo(storyDisplayItem);
					var storyModifiedDate = dateFromISOString(story.publicationDate);
					storyDisplayItem.get(".published").html('<strong>Published</strong> ' + timeSinceString(storyModifiedDate));
					storyDisplayItem.prependTo(this.storyListElement);
				} else {
					// set the initial height and opacity of the new story item
					storyDisplayItem.css('height', '0px').css('opacity', '0').css('margin-top', '0px');				

					// insert the new story in the dom
					storyDisplayItem.prependTo(this.storyListElement);

					storiesBeingAdded.unshift(story);

					var heightAnim = glow.anim.css(storyDisplayItem, 0.3, {
						"height" : {to:71},
						"margin-top" : {to:8}
					});

					glow.events.addListener(heightAnim, "complete", function(){
						var s = storiesBeingAdded.pop();
						s.storyDisplayContents.appendTo(s.storyDisplayItem);
						var storyModifiedDate = dateFromISOString(s.publicationDate);
						s.storyDisplayItem.get(".published").html('<strong>Published</strong> ' + timeSinceString(storyModifiedDate));
					});

					var opacityAnim = glow.anim.css(storyDisplayItem, 0.3, {
						"opacity" : {to:1}
					});

					displayStoryAnimations.push(heightAnim);
					displayStoryAnimations.push(opacityAnim);

				}
			}
		}
		
		if(displayStoryAnimations.length > 0) {
			new glow.anim.Timeline(displayStoryAnimations).start();
		}
		
		// update the 'last updated time' for all stories
		var i;
		for(i=0; i < this.displayedStories.length; i++ ) {
			var s = this.displayedStories[i];
			var storyModifiedDate = dateFromISOString(s.publicationDate);
			s.storyDisplayItem.get(".published").html('<strong>Published</strong> ' + timeSinceString(storyModifiedDate));
		}
	},
	
	updateStory: function(existingStory, story) {
		existingStory.storyDisplayItem.addClass('updated');
	},
	
	removeOldStories: function() {
		var numberOfStoriesToRemove = this.displayedStories.length - this.CONFIG.MAX_STORIES;
		while(numberOfStoriesToRemove > 0) {
			var storyToRemove = this.displayedStories.pop();
			storyToRemove.storyDisplayItem.remove();
			numberOfStoriesToRemove--;
		}
	}

};

glow.ready(function() {
	radar.init();
	radar.requestLatestStories();
	window.setInterval("radar.requestLatestStories()", 15000);
});


// Utils -- where should these functions go?

// converts a date from a specific ISO 8601 format: '2008-07-12T06:07:12Z'
function dateFromISOString(dateString) {
	var date = new Date();
	date.setUTCFullYear(dateString.substring(0,4));
	date.setUTCMonth(dateString.substring(5,7) - 1);
	date.setUTCDate(dateString.substring(8,10));
	date.setUTCHours(dateString.substring(11,13));
	date.setUTCMinutes(dateString.substring(14,16));
	date.setUTCSeconds(dateString.substring(17,19));
	return date;
}

// converts a date to a specific ISO 8601 format: '2008-07-12T06:07:12Z'
function dateToISOString(date) {
	var dateString = date.getUTCFullYear() + '-' + 
		pad((date.getUTCMonth() + 1),2) + '-' + 
		pad(date.getUTCDate(),2) + 'T' + 
		pad(date.getUTCHours(),2) + ':' + 
		pad(date.getUTCMinutes(),2) + ':' +
		pad(date.getUTCSeconds(),2) + 'Z';
	return dateString;
}

// pads a number with leading zeros to return a string representing a 
// number of at least the specified numberOfDigits
function pad(value, numberOfDigits) {
	var paddedNumber = value.toString();
	while(paddedNumber.length < numberOfDigits) {
		paddedNumber = '0' + paddedNumber;
	}
	return(paddedNumber);
}


// Returns a 'time since string' to display a 'nice' string
// to communicate how long ago some date is.
function timeSinceString(date) {

	var returnString = "";

	var MILLISECONDS_IN_A_SECOND = 1000;
	var MILLISECONDS_IN_A_MINUTE = 60 * MILLISECONDS_IN_A_SECOND;
	var MILLISECONDS_IN_AN_HOUR = 60 * MILLISECONDS_IN_A_MINUTE;
	var MILLISECONDS_IN_A_DAY = 24 * MILLISECONDS_IN_AN_HOUR;
	var MILLISECONDS_IN_A_WEEK = 7 * MILLISECONDS_IN_A_DAY;
	var MILLISECONDS_IN_A_MONTH = 30 * MILLISECONDS_IN_A_DAY;
	var MILLISECONDS_IN_A_YEAR = 365 * MILLISECONDS_IN_A_DAY;

	// get the num of milliseconds since the time passed in
	var millisecondsSinceStartTime = new Date().getTime() - date.getTime();
	
	if ( millisecondsSinceStartTime <  MILLISECONDS_IN_A_MINUTE ) {
		var elapsedSeconds = Math.round( millisecondsSinceStartTime / MILLISECONDS_IN_A_SECOND );
		if ( elapsedSeconds > 1 ) {
			returnString = elapsedSeconds + " seconds ago";
		} else {
			returnString = elapsedSeconds + " second ago";
		}
	} else if ( millisecondsSinceStartTime <  MILLISECONDS_IN_AN_HOUR ) {		
		var elapsedMinutes = Math.round( millisecondsSinceStartTime / MILLISECONDS_IN_A_MINUTE );
		if ( elapsedMinutes > 1 ) {
			returnString = elapsedMinutes + " minutes ago";
		} else {
			returnString = elapsedMinutes + " minute ago";
		}
	} else if ( millisecondsSinceStartTime <  MILLISECONDS_IN_A_DAY ) {
		var elapsedHours = Math.round( millisecondsSinceStartTime / MILLISECONDS_IN_AN_HOUR );
		if ( elapsedHours > 1 ) {
			returnString = " &gt; " + elapsedHours + " hours ago";
		} else {
			returnString = " &gt; " + elapsedHours + " hour ago";
		}
	} else if ( millisecondsSinceStartTime <  MILLISECONDS_IN_A_WEEK ) {
		var elapsedDays = Math.round( millisecondsSinceStartTime / MILLISECONDS_IN_A_DAY );
		if ( elapsedDays > 1 ) {
			returnString = elapsedDays + " days ago";
		} else {
			returnString = "yesterday";
		}
	} else if ( millisecondsSinceStartTime <  MILLISECONDS_IN_A_MONTH ) {
		var elapsedWeeks = Math.round( millisecondsSinceStartTime / MILLISECONDS_IN_A_WEEK );
		if ( elapsedWeeks > 1 ) {
			returnString = elapsedWeeks + " weeks ago";
		} else {
			returnString = "last week";
		}
	} else if ( millisecondsSinceStartTime <  MILLISECONDS_IN_A_YEAR ) {
		var elapsedMonths = Math.round( millisecondsSinceStartTime / MILLISECONDS_IN_A_MONTH );
		if ( elapsedMonths > 1 ) {
			returnString = elapsedMonths + " months ago";
		} else {
			returnString = "last month";
		}
	} else {
		var elapsedYears = Math.round( millisecondsSinceStartTime / MILLISECONDS_IN_A_YEAR );
		if ( elapsedYears > 1 ) {
			returnString = elapsedYears + " years ago";
		} else {
			returnString = "last year";
		}
	}

	return returnString;
}