var _entryData = []; // array of entries
var _selectedIndex = -1;
var _selectedEntryId = null;
var _isLoggedIn = false;
var _requestQueue = [];
var _lastRequestDate = new Date();
var _pollPeriod = 180 * 1000; // 3 minutes
var _lastKeyPressDate = new Date();
var _lastRequestedIndex = 0; // 0 for initial load and poll, otherwise index of first item in next page
var _view = "public"; // or "home" if logged in
var _isPoppedOut = (location.search.indexOf('popout') > -1);
var _contentPane;
var _lastUrlOpened = '/default_right';

function initialize() {
	window.focus();
	if (_isPoppedOut) $('popout_button').src = '/images/popin.gif';
	_entryData = _feedData.entries;
	if (_isLoggedIn) _view = "home";
	else _view = "public";
	document.onkeydown = onKeyDown;
	window.onresize = onResize;
	
	if (_entryData != null) {
		extractLinks();
		renderHtml();
	}
	
	setTimeout(timerTick, 1000);  
	onResize();
}

function onResize() {
	var parentDimensions = $('reader_box_inner').getOffsetParent().getDimensions();
    $('reader_box_inner').setStyle({height: (parentDimensions.height - 90) + 'px'});
    $('reader_box_inner').setStyle({width: (parentDimensions.width - 5) + 'px'});
}

function onKeyDown(e){
	var event = e || window.event;
	var target = event.target || event.srcElement;
	
	//_lastKeyPressDate = new Date();

	var key = event.keyCode;
	
	//$('status').update("key: " + key);
	
	if (target && target.id.indexOf("comment_input") == 0) {
		if (key == 13) { // enter (return)
			if (target.value.length > 0) 
				postComment(_selectedIndex, target.value);
			else 
				toggleCommentForm(event);
		} else if (key == 27 ) { // esc
			toggleCommentForm(event);
		}
		else 
			return; // ignore hotkeys when trying to comment
	}
	
	if (target && target.id.indexOf("share_title") == 0 || target.id.indexOf("share_link") == 0) {
		if (key == 13) {
			if (target.value.length > 0) 
				postShare();
			else 
				toggleShareForm(event);
		} else if (key == 27) { //esc
			toggleShareForm(event);
		}
		else 
			return; // ignore hotkeys when trying to comment
	}
	
	if ([37, 38, 75, 80].indexOf(key) > -1) {
		movePrevious(); // left arrow, up arrow, "p"
	}
	else if ([39, 40, 74, 78, 32].indexOf(key) > -1) {
		moveNext(); // right arrow, down arrow, "n", space
	} else if (key == 83) { // "s" share
		toggleShareForm(event);
	} else if (key == 67 && _selectedEntryId != null) { // "c" comment
		toggleCommentForm(event);	
	} else if (key == 76 && _selectedIndex > 0) { // "l" like
		postLike(_selectedIndex);		
	} else if (key == 84) { // "t" top
		moveTo(0);
	} else if (key == 66) { // "b" bottom
		moveTo(_entryData.length -1);
	} else if (key = 77) { // "m" more comments
		showMoreComments(e, _selectedIndex);
	}
		
	//console.log(key);
}

function currentEntry() {
	return _entryData[_selectedIndex];
}

function setView( view) {
	if (_view == view) return;
	//$('reader_box_inner').update("Loading...");
	_view = view;
	_selectedIndex = -1;
	_selectedEntryId = null;
	_entryData = [];
	$('reader_box_inner').update('');
	_requestQueue.push(0);
	processQueue();
}

function timerTick() {
	processQueue();
	
	var now = new Date();
	var nextRequestTime = _lastRequestDate.getTime() + _pollPeriod;
	var secondsUntilNextRequest = Math.round((nextRequestTime - now.getTime()) / 1000);
	
	if (now.getTime() > nextRequestTime) {
		_requestQueue.push(0);
	}
	
	$('clock').update(Math.max(0, secondsUntilNextRequest));
	
	// todo: increase poll period if nothing was clicked
	
	setTimeout(timerTick, 1000);
}

function processQueue() {
	var startIndex = _requestQueue.pop();
	
	if (startIndex != null) {
		_lastRequestDate = new Date();
		_lastRequestedIndex = startIndex;
		getData(startIndex);
	}
}

function getData(startIndex) {
	//console.log('Requesting ' + _view + ' feed (index ' + startIndex + ')');
	$('status').update('Requesting ' + _view + ' feed (index ' + startIndex + ')');
	
	var url;
	
	url = '/api/feed/' + _view + '?start=' + startIndex;
	
	new Ajax.Request(url, {
	  method: 'get',
	  onSuccess: onGetDataComplete
	});	
}

function onGetDataComplete(transport) {
	var feedData = eval('(' + transport.responseText + ')');
	$('status').update("Got " + feedData.entries.length + " entries.");
	//console.log("Got " + feedData.entries.length + " entries.");
	extractLinks(); // promote twitter links
	mergeData(feedData.entries);
	$('entry_' + _selectedEntryId).addClassName("entry_selected");
	scrollTo();
}

// also replaces stale HTML
function mergeData(freshData) {
	var data = [];
	var countNew = 0
	var countUpdated = 0;
	var commentText = null;
	
	//console.log(' ---- top ---- ');
	
	// rebuild top of list
	if (_lastRequestedIndex == 0) { // startIndex 0
		for (var i = 0; i < freshData.length; i++) {
			freshEntry = freshData[i];
			data.push(freshEntry);
			
			// remove old HTML, preserving (and showing) unsubmitted comment text
			if ($('entry_border_' + freshEntry.id) == null) {
				commentText = null;
				countNew++;
			} else {
				countUpdated++;
				if ($('comment_input_' + freshEntry.id)) {
					commentText = $('comment_input_' + freshEntry.id).value;
				}
				$('entry_border_' + freshEntry.id).remove();
			}

			// add at index i			
			if (i == 0) {
				$('reader_box_inner').insert({
					top: getEntryHtml(freshEntry, i, _isLoggedIn, commentText)
				});
			} else {
				// insert after the previous entry
				$('entry_border_' + data[i-1].id).insert({
					after: getEntryHtml(freshEntry, i, _isLoggedIn, commentText)
				})
			}
			
			new Effect.Highlight('entry_' + freshEntry.id);
			if (freshEntry.id == _selectedEntryId) _selectedIndex = i; // retain selected index
		}
	}
	
	//console.log(' ---- middle ---- ');
	
	// skip (remove) duplicate entries from middle of list (only keep those that aren't fresh)
	for (var i = 0; i < _entryData.length; i++) {
		staleEntry = _entryData[i];
		var found = false;
		for (var j = 0; j < freshData.length; j++) {
			freshEntry = freshData[j];
			if (freshEntry.id == staleEntry.id) {
				//console.log('skip:  ' + staleEntry.id + ' ' + staleEntry.title)
				found = true;
				break;
			}
		}
		
		// put into list at new position, update html with new index
		if (!found) {
			//console.log('update:' + staleEntry.id + ' ' + staleEntry.title);
			data.push(staleEntry);
			
			if ($('comment_input_' + freshEntry.id))
				commentText = $('comment_input_' + staleEntry.id).value;
			
			// remove old HTML, preserving unsubmitted comment text
			$('entry_border_' + staleEntry.id).replace(
				getEntryHtml(staleEntry, data.length - 1, _isLoggedIn, commentText));
				
			new Effect.Highlight('entry_' + staleEntry.id);
			
			if (staleEntry.id == _selectedEntryId) _selectedIndex = data.length - 1; // retain selected index	
		}
	}
	
	//console.log(' ---- bottom ---- ');
	
	// rebuild bottom of list
	if (_lastRequestedIndex > 0) { // startIndex > 0
		for (var i = 0; i < freshData.length; i++) {
			freshEntry = freshData[i];
			data.push(freshEntry);

			// remove old HTML (small chance it existed on previous page)
			// preserve (and show) unsubmitted comment text
			if ($('entry_border_' + freshEntry.id) == null) {
				commentText = null;
				countNew++;
			} else {
				countUpdated++;
				if ($('comment_input_' + freshEntry.id)) 
					commentText = $('comment_input_' + freshEntry.id).value;
				$('entry_border_' + freshEntry.id).remove();
			}

			$('reader_box_inner').insert({
				bottom: getEntryHtml(freshEntry, data.length - 1, _isLoggedIn, commentText)});
				
			//new Effect.Highlight('entry_' + freshEntry.id);	
			if (freshEntry.id == _selectedEntryId) _selectedIndex = data.length - 1; // retain selected index		
		}
	}
	
	_entryData = data;
	$('status').update(countNew + ' new, ' + countUpdated + ' refreshed. Viewing ' + (_selectedIndex + 1) + ' of ' + _entryData.length + '. ');
}

function renderHtml() {
	for (var i = 0; i < _entryData.length; i++) {
		var entry = _entryData[i]
		$('reader_box_inner').insert({
				bottom: getEntryHtml(entry, i, _isLoggedIn, null)
			});
			
		new Effect.Highlight('entry_' + entry.id);
	}
	
	// restore selected item, set scroll position
}

function navigateToEntryLink(){
	var destUrl = currentEntry().link;
	
	// avoid nested frames
	if (destUrl.toLowerCase() == 'http://www.stumbleread.com/' ||
		destUrl.toLowerCase() == 'http://www.stumbleread.com' ||
		destUrl.toLowerCase() == 'http://stumbleread.com' ||
		destUrl.toLowerCase() == 'http://stumbleread.com/') {
		destUrl = 'http://stumbleread.com/default_right?noframe';
	}
	
	if (_isPoppedOut) {
		if (_contentPane && !_contentPane.closed && _contentPane.location)
			_contentPane.location = destUrl;
		else 
			_contentPane = window.open(destUrl);
	} else {
		parent.frames['content_pane'].location = destUrl;
	}
	
	_lastUrlOpened = destUrl;
}

function moveNext() {
	moveTo(_selectedIndex + 1);
}

function movePrevious() {
	moveTo(_selectedIndex - 1);
}

function showMoreComments(e, index) {
	var event = e || window.event;

	moveTo(index);
	
	moreCommentsLink = $('more_comments_link_' + _selectedEntryId);
	
	if (moreCommentsLink) moreCommentsLink.remove();
	
	hiddenCommentsDiv = $('hidden_comments_' + _selectedEntryId);
	
	if (hiddenCommentsDiv) hiddenCommentsDiv.show();

	Event.stop(event);
}

function toggleCommentForm(event) {
	if (_selectedEntryId != null) {
		$('comment_form_' + _selectedEntryId).toggle();
		$('comment_input_' + _selectedEntryId).focus();
	}
	 
	Event.stop(event);
}

function syncShareFormLink() {
	if (_selectedIndex == -1) {
		// permission denied
		//$('post_link').value = parent.frames['content_pane'].location.href;
	}
	else {
		$('share_link').value = currentEntry().link;
	}
}

function toggleShareForm(event) {
	$('share_form').toggle();
	$('share_title').focus();
	Event.stop(event);
}

function moveTo(index) {
//	var event = e || window.event;
//	
//	if (e) {
//		var target = event.target || event.srcElement;
//		if (target && target.id.indexOf("more_comments_link") == 0) {
//			return;
//		}
//	}
	
	var currentDiv = null;
	
	if (_selectedIndex >= 0) {
		currentDiv = $('entry_' + currentEntry().id);
		var currentControlsDiv = $('controls_' + currentEntry().id);
		var currentCommentForm = $('comment_form_' + currentEntry().id);
	}
		
	if (index != _selectedIndex && index >= 0 && index < _entryData.length) {
		_selectedIndex = index;
		_selectedEntryId = currentEntry().id;

		var nextDiv = $('entry_' + _selectedEntryId);
		var nextControlsDiv = $('controls_' + _selectedEntryId);

		if (currentDiv != null) {
			currentDiv.removeClassName("entry_selected")
			currentDiv.addClassName("entry_read");
			
			if (currentControlsDiv != null) { // may not be there if logged out
				currentControlsDiv.hide();
				currentCommentForm.hide();
			}
		}

		nextDiv.removeClassName("entry_read");
		nextDiv.addClassName("entry_selected");
		if (nextControlsDiv != null) nextControlsDiv.show(); // not there if logged out
		navigateToEntryLink();
	}

	if (index == 0) {
		_requestQueue.push(0); 		
		processQueue();
	} else if (index == _entryData.length - 1) { // last page, fetch next page
		_requestQueue.push(_entryData.length); 		
		processQueue();
	}
	
	syncShareFormLink();
	scrollTo();
	$('status').update('Viewing ' + (_selectedIndex + 1) + ' of ' + _entryData.length + '. ');
}

function scrollTo(){
	var container = $('reader_box_inner');
	var dest = $('entry_' + _selectedEntryId);
	
	try {
		if (container && dest) {
			if (container.scrollTop > dest.offsetTop - 100) {
				container.scrollTop = dest.offsetTop - 100;
			}
			else 
				if (dest.offsetTop + dest.clientHeight > container.scrollTop + container.clientHeight) {
					container.scrollTop += (dest.offsetTop + dest.clientHeight) -
					(container.scrollTop + container.clientHeight);
				}
		}
	} catch (err) {
		// could not scroll 
	}
}

function postShare(index, commentText) {
	$('status').update('Sharing...');
	new Ajax.Request('/share?title=' + escape($('share_title').value) +
			'&link=' + $('share_link').value, 
			{ method: 'post', onSuccess: postShareComplete});
	$('share_form').toggle();
}

function postShareComplete(transport) {
	$('status').update('Shared!');
	var feedData = eval('(' + transport.responseText + ')');
	mergeData(feedData.entries);
	moveTo(0);
}

function postComment(index, commentText) {
	$('status').update('Posting comment...');
	new Ajax.Request('/comment?id=' + _entryData[index].id +
			'&comment_text=' +
			escape($('comment_input_' + _entryData[index].id).value), 
			{ method: 'post', onSuccess: postCommentComplete});
}

// expect response to contain entry id and text of comment
function postCommentComplete(transport) {
	$('status').update('Comment posted.');
	lines = transport.responseText.split('\n');
	entry_id = lines[0];
	comment_text = lines[1];
	$('comments_' + entry_id).insert(
		'<div class="comment">' + comment_text + ' -  via StumbleRead</div>');
	$('comment_form_' + entry_id).hide();
	$('comment_input_' + entry_id).value = '';	
}

function postLike(index) {
	$('status').update('Liking...');
	new Ajax.Request('/like?id=' + _entryData[index].id, 
			{ method: 'post', onSuccess: postLikeComplete});
}

// expect response to contain entry id
function postLikeComplete(transport) {
	$('status').update('Liked!');
	entry_id = transport.responseText;
	$('like_anchor_' + entry_id).replace("Liked");
}

function getCommentHtml(comment, index, isVisible){
	html = '<div class="comment" id="comment_{{ entry.id }}_' + index + '" ';
	html += '>';
	html += comment.body + ' - ' + comment.user.name;
	html += '</div>'	
	return html;
}

function getCommentsHtml(entry) {
	if (entry.comments == null) return '';

	var html = '<div id="comments_{{ entry.id }}">';
	
	// first two (0 to 1), then "Show x more comments", then last 3
	var i = 0;
	while (i < Math.min(2, entry.comments.length)) {
		html += getCommentHtml(entry.comments[i], i, true);
		i++;
	}

	hiddenCommentCount = 0;
	hiddenCommentHtml = '';
	while (i < entry.comments.length - 3) {
		hiddenCommentHtml += getCommentHtml(entry.comments[i], i, false);
		i++;
		hiddenCommentCount++;
	}
	
	if (hiddenCommentCount > 0) {
		html += '<div id="more_comments_link_{{ entry.id }}">';
		html += '<br/><a class="show_more_comments action" onclick="showMoreComments(event, {{ index }});" href="#">Show ' + hiddenCommentCount +
		' <b>m</b>ore comments</a>';
		html += '</div>';
		html += '<div id="hidden_comments_{{ entry.id }}" style="display:none">';
		html += hiddenCommentHtml;
		html += '</div>';
	}
	
	while (i < entry.comments.length) {
		html += getCommentHtml(entry.comments[i], i, true);
		i++;
	}

	html += '</div>';
	return html;
}

function getLikesHtml(entry) {
	if (entry.likes == null) return '';
	
	var html = '<div class="like">';
	
	for (var i = 0; i < Math.min(3, entry.likes.length); i++) {
		like = entry.likes[i];
		html += like.user.name;
		if (i < Math.min(3, entry.likes.length -1)) html += ', ';
	}
	
	if (entry.likes.length > 3) {
		html += 'and <a target="content_pane" href="http://friendfeed.com/e/{{ entry.id }}">3 others</a>';
	}

	html += '</div>';
	
	return html;
}

function getFormHtml() {
	return '\
<div class="entry_controls_container">															\
	<span id="controls_{{ entry.id }}" style="display:none;">									\
		<a id="comment_anchor_{{ entry.id }}" href="#" 											\
			onclick="toggleCommentForm(event, $(\'comment_form_{{ entry.id }}\'));">Comment</a>	\
		<a id="like_anchor_{{ entry.id }}" href="#" onclick="postLike({{ index }})">Like</a>	\
	</span>																						\
</div>																							\
<div id="comment_form_{{ entry.id }}" class="comment_form" style="display:{{ commentFormDisplay }};">\
	<input type="text" id="comment_input_{{ entry.id }}" 				 						\
		style="margin-bottom: -3px;" maxlength="140" value="{{ pendingCommentText }}"></input>	\
	<input type="button" style="margin-left: 3px;" value="Post"									\
		onclick="postComment({{ index }}, $(\'comment_input_{{ entry.id }}\').value)"></input>	\
</div>';
}

function getEntryHtml(entry, index, isLoggedIn, pendingCommentText) {
	html = '\
<div id="entry_border_{{ entry.id }}" class="entry_border">										\
	<div id="entry_{{ entry.id }}" class="entry" onclick="moveTo({{ index }})">					\
		<img src="{{ entry.service.iconUrl }}"/>												\
		<a href="{{ entry.user.profileUrl }}" target="content_pane">{{ entry.user.name }}</a>	\
		posted an item on 																		\
		<a href="{{ entry.service.profileUrl }}" target="content_pane">{{ entry.service.name }}</a>:		\
		<a href="#">{{ entry.title }}</a>					\
		{{ likes_html }}																		\
		{{ comments_html }}																		\
		{{ form_html }}																			\
	</div>																						\
</div>';

	html = html.replace('{{ likes_html }}', getLikesHtml(entry));
	html = html.replace('{{ comments_html }}', getCommentsHtml(entry));
	
	if (isLoggedIn) formHtml = getFormHtml();
	else formHtml = '';
	
	html = html.replace('{{ form_html }}', formHtml)

	html = html.replace(/{{ index }}/g, index);
	html = html.replace(/{{ entry.id }}/g, entry.id);
	html = html.replace(/{{ entry.service.iconUrl }}/g, entry.service.iconUrl);
	html = html.replace(/{{ entry.user.name }}/g, entry.user.name);
	html = html.replace(/{{ entry.service.name }}/g, entry.service.name);
	html = html.replace(/{{ entry.title }}/g, entry.title);
	html = html.replace(/{{ entry.link }}/g, entry.link);
	html = html.replace(/{{ entry.user.profileUrl }}/g, entry.user.profileUrl);
	html = html.replace(/{{ entry.service.profileUrl }}/g, entry.service.profileUrl);

	if (pendingCommentText == null || pendingCommentText == '') {
		html = html.replace(/{{ commentFormDisplay }}/g, 'none');
		html = html.replace(/{{ pendingCommentText }}/g, '');
	} else {
		html = html.replace(/{{ commentFormDisplay }}/g, 'block');
		html = html.replace(/{{ pendingCommentText }}/g, pendingCommentText);
	}
	
	return html;
}

function extractLinks(){
	for (var i = 0; i < _entryData.length; i++) {
		var entry = _entryData[i];
		
		if (entry.service.name == 'Twitter' || entry.service.name == 'FriendFeed') {
			var start = entry.title.indexOf('http://');
			var end = null;
			
			if (start > -1) {
				end = entry.title.indexOf(' ', start + 1);
				if (end == -1) end = entry.title.length;
				var url = entry.title.substring(start, end);
				//console.log('found link: ' + url);
				entry.link = url;
			} 
		} else {
				//console.log('missing link? ' + entry.service.name + ' ' + entry.title);
		}
	}
}

function togglePopup() {
	if (_isPoppedOut) { // pop in
		if (_contentPane && !_contentPane.closed && _contentPane.location)
			_contentPane.location = '/';
		else 
			_contentPane = window.open('/');	
			self.close();		
	} else { // pop out
		popup = window.open("/reader?popout","external_reader", "menubar=no,width=300,height=700,toolbar=no");
		popup._contentPane = parent;
		popup.focus();
		
		var url = _lastUrlOpened;
		if (url.indexOf('default_right') > -1) url += '?noframe'
		parent.location =  url;
	}
	return false;
}

function refreshWindow() {
	if (_isPoppedOut) {
		self.location.reload();
	} else {
		parent.location.reload();
	}
}

